7 Commits

  1. 480
      cmd/log/asana.log
  2. 2
      go.mod
  3. 16
      module/attach/attachments.go
  4. 9
      module/error_response.go
  5. 56
      module/story/stories.go
  6. 68
      module/task/follower.go
  7. 100
      module/task/task.go
  8. 67
      module/users/user.go
  9. 46
      text/rich_text.go
  10. 1
      util/constant.go
  11. 14
      util/http.go

480
cmd/log/asana.log
File diff suppressed because it is too large
View File

2
go.mod

@ -1,4 +1,4 @@
module asana
module git.drinkme.beer/yinghe/asana
go 1.15

16
module/attach/attachments.go

@ -14,11 +14,7 @@ import (
"git.drinkme.beer/yinghe/log"
"asana/util"
)
const (
URI = "/api/1.0/tasks/%s/attachments"
"git.drinkme.beer/yinghe/asana/util"
)
type Request struct {
@ -48,8 +44,16 @@ func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
func (r Request) CreateInEncryption(download func(src, tmp string) error) (*Response, error) {
return r.create(download)
}
// Create - upload attachments
func (r Request) Create() (resp *Response, err error) {
return r.create(download)
}
func (r Request) create(f func(src, tmp string) error) (resp *Response, err error) {
var (
tempPath string
data struct {
@ -59,7 +63,7 @@ func (r Request) Create() (resp *Response, err error) {
tempPath = "./static/" + r.Name
// TODO
err = download(r.Path, tempPath)
err = f(r.Path, tempPath)
if nil != err {
return nil, err
}

9
module/error_response.go

@ -0,0 +1,9 @@
package module
type Error struct {
Code string `json:"error"`
Message string `json:"message"`
Help string `json:"help"`
}
type Errors []Error

56
module/story/stories.go

@ -8,7 +8,8 @@ import (
"git.drinkme.beer/yinghe/log"
"asana/util"
"git.drinkme.beer/yinghe/asana/module/users"
"git.drinkme.beer/yinghe/asana/util"
)
const (
@ -21,9 +22,9 @@ type Data struct {
type Request struct {
HtmlText string `json:"html_text,omitempty"`
Text string `json:"text"`
Text string `json:"text,omitempty"`
StickerName string `json:"sticker_name,omitempty"`
IsPinned bool `json:"is_pinned"`
IsPinned bool `json:"is_pinned,omitempty"`
taskID string
ticketID string
@ -55,14 +56,21 @@ func (r *Request) SetPAToken(token string) {
}
type Response struct {
ID string `json:"gid"`
ResourceType string `json:"resource_type"`
Type string `json:"type"`
Text string `json:"text"`
ID string `json:"gid"`
ResourceType string `json:"resource_type"`
ResourceSubtype string `json:"resource_subtype"`
Type string `json:"type"`
Text string `json:"text"`
// IsPinned Conditional
// Whether the story should be pinned on the resource.
IsPinned bool `json:"is_pinned"`
StickerName string `json:"sticker_name,omitempty"`
IsPinned bool `json:"is_pinned"`
StickerName string `json:"sticker_name,omitempty"`
CreatedAt string `json:"created_at"`
CreatedBy users.User `json:"created_by"`
}
func (r *Response) IsComplete() bool {
return "marked_complete" == r.ResourceSubtype
}
func (r Request) validate() error {
@ -111,7 +119,7 @@ func (r Request) Create() (resp *Response, err error) {
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusCreated != client.HTTPStatus {
log.Errorf("unexpected response")
client.Print()
err = errors.New("unexpected response")
return
}
@ -125,3 +133,31 @@ func (r Request) Create() (resp *Response, err error) {
log.Infof("[%s]new comment ID:%s", r.taskID, resp.ID)
return
}
func (r Request) Get() ([]Response, error) {
var (
resp struct {
Data []Response `json:"data"`
}
)
headers := make(map[string]string)
headers["Authorization"] = r.paToken
headers["Content-Type"] = util.ContentType
client := util.NewHttpClient(util.AsanaHost, fmt.Sprintf(URI, r.taskID), util.HttpGetMethod, nil)
client.Headers = headers
err := client.Request()
if nil != err || http.StatusOK != client.HTTPStatus {
client.Print()
log.Errorf("failed")
}
err = json.Unmarshal(client.Body, &resp)
if nil != err {
log.Errorf("invalid response")
return nil, fmt.Errorf("invalid response")
}
return resp.Data, nil
}

68
module/task/follower.go

@ -0,0 +1,68 @@
package task
import (
"encoding/json"
"fmt"
"net/http"
"git.drinkme.beer/yinghe/log"
"git.drinkme.beer/yinghe/asana/util"
)
const (
AddFollowersURI = "/api/1.0/tasks/%s/addFollowers"
)
type Follower struct {
Followers []string `json:"followers,omitempty"`
}
type FollowersRequest struct {
Data Follower `json:"data"`
}
func (f Follower) Add(token, taskID string) error {
var (
req FollowersRequest
)
if "" == token || "" == taskID {
log.Errorf("illegal request")
return fmt.Errorf("illegal request")
}
if nil == f.Followers {
log.Errorf("invalid request, followers")
return fmt.Errorf("none followers")
}
req.Data = f
buf, err := json.Marshal(&req)
if nil != err {
log.Errorf("invalid arguments: %s", err.Error())
return err
}
log.Infof("request ==> %s", string(buf))
headers := make(map[string]string)
headers["Authorization"] = token
headers["Content-Type"] = util.ContentType
client := util.NewHttpClient(util.AsanaHost,
fmt.Sprintf(AddFollowersURI, taskID),
util.HttpPostMethod, buf)
client.Headers = headers
err = client.Request()
if nil != err {
log.Errorf("failed to create new Asana task: %s", err.Error())
return err
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusOK != client.HTTPStatus {
log.Errorf("unexpected response")
err = fmt.Errorf("unexpected response")
return err
} else {
return nil
}
}

100
module/task/task.go

@ -3,11 +3,13 @@ package task
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"git.drinkme.beer/yinghe/log"
"asana/util"
"git.drinkme.beer/yinghe/asana/module"
"git.drinkme.beer/yinghe/asana/util"
)
type Data struct {
@ -15,18 +17,19 @@ type Data struct {
}
type Request struct {
ResourceSubtype string `json:"resource_subtype"`
Assignee string `json:"assignee"`
Name string `json:"name"`
ResourceSubtype string `json:"resource_subtype,omitempty"`
Assignee string `json:"assignee,omitempty"`
Name string `json:"name,omitempty"`
Completed bool `json:"completed"`
DueOn string `json:"due_on"`
Liked bool `json:"linked"`
DueOn string `json:"due_on,omitempty"`
Liked bool `json:"linked,omitempty"`
// Notes refer to the content of each Ticket
Notes string `json:"notes"`
StartOn string `json:"start_on"`
CustomFields map[string]string `json:"custom_fields"`
Projects []string `json:"projects"`
Workspace string `json:"workspace"`
Notes string `json:"notes,omitempty"`
HtmlNotes string `json:"html_notes,omitempty"`
StartOn string `json:"start_on,omitempty"`
CustomFields map[string]string `json:"custom_fields,omitempty"`
Projects []string `json:"projects,omitempty"`
Workspace string `json:"workspace,omitempty"`
TicketID string `json:"-"`
TicketType string `json:"-"`
@ -49,19 +52,65 @@ type Response struct {
}
const (
URI = "/api/1.0/tasks"
URICreateTask = "/api/1.0/tasks"
URIUpdateTask = "/api/1.0/tasks/%s"
ResourceSubtype = "default_task"
)
func (r Request) Update(taskID string) error {
var (
uri = fmt.Sprintf(URIUpdateTask, taskID)
err error
)
c, err := r.call(uri, util.HttpPutMethod)
if nil != err || nil == c {
return err
}
if http.StatusOK != c.HTTPStatus {
c.Print()
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return err
}
return nil
}
func (r Request) Create() (resp *Response, err error) {
var (
reqData Data
respData struct {
Response Response `json:"data"`
Response Response `json:"data"`
Errors module.Errors `json:"errors"`
}
)
client, err := r.call(URICreateTask, util.HttpPostMethod)
resp = new(Response)
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusCreated != client.HTTPStatus {
client.Print()
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return
}
err = json.Unmarshal(client.Body, &respData)
if nil != err {
client.Print()
log.Errorf("illegal task result: %s", err.Error())
return
}
resp = &respData.Response
log.Infof("[%s]new task ID:%s", r.TicketID, resp.ID)
return
}
func (r Request) call(uri, httpMethod string) (*util.Client, error) {
var (
err error
reqData Data
client = new(util.Client)
)
headers := make(map[string]string)
headers["Authorization"] = r.paToken
@ -76,32 +125,19 @@ func (r Request) Create() (resp *Response, err error) {
buf, err := json.Marshal(&reqData)
if nil != err {
log.Errorf("failed to generate task request: %s", err.Error())
return
return client, err
}
log.Infof("request: %s", string(buf))
client := util.NewHttpClient(util.AsanaHost, URI, util.HttpPostMethod, buf)
client = util.NewHttpClient(util.AsanaHost, uri, httpMethod, buf)
client.Headers = headers
err = client.Request()
if nil != err {
log.Errorf("failed to create new Asana task: %s", err.Error())
return
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusCreated != client.HTTPStatus {
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return
return client, err
}
err = json.Unmarshal(client.Body, &respData)
if nil != err {
log.Errorf("illegal task result: %s", err.Error())
return
}
resp = &respData.Response
log.Infof("[%s]new task ID:%s", r.TicketID, resp.ID)
return
return client, nil
}

67
module/users/user.go

@ -0,0 +1,67 @@
package users
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"git.drinkme.beer/yinghe/log"
"git.drinkme.beer/yinghe/asana/util"
)
const (
URI = "/api/1.0/users/%s"
)
type User struct {
ID string `json:"gid,omitempty"`
ResourceType string `json:"resource_type,omitempty"`
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Photo map[string]string `json:"photo,omitempty"`
Workspaces []struct {
ID string `json:"gid,omitempty"`
ResourceType string `json:"resource_type,omitempty"`
Name string `json:"name,omitempty"`
} `json:"workspaces,omitempty"`
}
type Response struct {
Data User `json:"data,omitempty"`
}
func (u User) Get(paToken string) (*User, error) {
var (
err error
resp Response
)
headers := make(map[string]string)
headers["Authorization"] = paToken
headers["Content-Type"] = util.ContentType
client := util.NewHttpClient(util.AsanaHost, fmt.Sprintf(URI, u.ID), util.HttpGetMethod, nil)
client.Headers = headers
err = client.Request()
if nil != err {
log.Errorf("failed to obtain user info: %s", err.Error())
return nil, err
}
log.Infof("response status: %d", client.HTTPStatus)
if http.StatusOK != client.HTTPStatus {
log.Errorf("unexpected response")
err = errors.New("unexpected response")
return nil, err
}
err = json.Unmarshal(client.Body, &resp)
if nil != err {
log.Errorf("illegal task result: %s", err.Error())
return nil, err
}
return &resp.Data, err
}

46
text/rich_text.go

@ -0,0 +1,46 @@
package text
import (
"fmt"
"html"
"regexp"
"strings"
)
const (
DataMention = `<a data-asana-gid="%s"/>`
)
// `<body>
// testing
// <a data-asana-gid="1199521781039350"/>
// <a data-asana-gid="1200773217477032"/>
// </body>`
func Mention(gid string) string {
return fmt.Sprintf(DataMention, gid)
}
func DeleteHtmlTags(src string) string {
var (
line int
v, des string
)
if "" == src || 0 == len(src) {
return ""
}
reg := regexp.MustCompile(`<.+?>`)
str := reg.ReplaceAllString(src, " ")
s := strings.Split(str, "\n")
for _, v = range s {
if 0 == len(strings.TrimSpace(v)) {
continue
}
des = des + fmt.Sprintf("\n%s", v)
line++
}
if 0 == line {
return ""
}
return html.UnescapeString(des)[1:]
}

1
util/constant.go

@ -6,6 +6,7 @@ const (
ContentType = "application/json"
HttpGetMethod = "GET"
HttpPutMethod = "PUT"
HttpPostMethod = "POST"
AsanaDateFormat = "2006-01-02"

14
util/http.go

@ -1,7 +1,6 @@
package util
import (
"bufio"
"bytes"
"context"
"errors"
@ -80,13 +79,21 @@ type Client struct {
HTTPStatus int
Body []byte // Indicates both Request Body & Response Body
TraceId interface{}
Buffer *bufio.Reader
//Buffer *bufio.Reader
}
func (c *Client) AddHeader(k, v string) {
c.Headers[k] = v
}
func (c *Client) Print() {
if nil != c.Body {
log.Infof(string(c.Body))
} else {
log.Infof("nil")
}
}
type Bytes []byte
func (self Bytes) BuildRequest() []byte {
@ -139,7 +146,6 @@ func (c *Client) Request() (err error) {
c.HTTPStatus = resp.StatusCode
c.Body, err = ioutil.ReadAll(resp.Body)
log.Infof("response: %s", string(c.Body))
return
}
@ -153,7 +159,7 @@ func Request(req *http.Request) ([]byte, error) {
log.Errorf("illegal request")
return nil, errors.New("illegal request")
}
log.Infof("%v", req)
//log.Infof("%v", req)
resp, err := client.Do(req)
if nil == resp {
log.Info("none response received")

Loading…
Cancel
Save