From 6e66c17d790022f0eff0e097f72611508c787a0f Mon Sep 17 00:00:00 2001 From: Patrick Peng Sun Date: Fri, 19 May 2017 21:29:27 +1000 Subject: [PATCH] create attachment at EspoCRM done ~ yeah --- crmAttachment.go | 107 ++++++++++++++++++++++++++++++------------ crmAttachment_test.go | 9 ++-- fileinfo.go | 10 ++++ upload.go | 15 +++--- 4 files changed, 99 insertions(+), 42 deletions(-) diff --git a/crmAttachment.go b/crmAttachment.go index cc95148..d6a21c4 100644 --- a/crmAttachment.go +++ b/crmAttachment.go @@ -1,47 +1,101 @@ package main import ( + "encoding/base64" "encoding/json" + "fmt" + "io/ioutil" "log" ) +type crmFileInfo struct { + Name string `json:"name"` + Type string `json:"type"` + Role string `json:"role"` + Size int64 `json:"size"` +} + type attachmentID struct { ID string `json:"attachmentId"` } -func crmAttachFile(path string) (fileID string) { - //http post - r, _ := crmPostAttach(path) +func crmUploadFile(path string) (fileID string, fileInfo crmFileInfo, err error) { + + fileInfo, err = getFileInfo4CRM(path) + headers, err := crmUploadFileHTTPHeader(fileInfo) + data, err := crmFileDataString(path, fileInfo) + url := crmUploadAttachmentURL() + resp, err := postRAW([]byte(data), url, headers) + fileID, err = crmFileIDFromJSON(resp) + log.Println(fileID) + log.Println(err) + return +} + +//crmFileIDFromHTTP read attachment id from http response +// as http response cannot be 'rewind', this function is +// specifically used for one purpose only. +// i.e. upload attachment to EspoCRM +func crmFileIDFromJSON(jsonStr string) (fileID string, err error) { attach := attachmentID{} - json.Unmarshal([]byte(r), &attach) - return attach.ID + err = json.Unmarshal([]byte(jsonStr), &attach) + return attach.ID, err } -func crmPostAttachmentURL() string { +//crmUploadFileHTTPHeader when uploading a file, we need its mime, auth header, etc. +func crmUploadFileHTTPHeader(fileInfo crmFileInfo) (headers map[string]string, err error) { + headers = map[string]string{} + headers["Authorization"] = crmAuthHeader() + headers["Accept"] = "application/json" + headers["Content-Type"] = fileInfo.Type + return headers, err +} + +func crmUploadAttachmentURL() string { return "https://c.hitxy.org.au/api/v1/Attachment/action/upload" } func crmAuthHeader() string { - return "Basic cGF0cmljazpiNjFmYWRlMTM5OWYwY2ZjNmZjZjcxNTU0OTljNTNkOQ==" - //return "Basic cGF0cmljazp3b3JraGFyZA==" + //return "Basic cGF0cmljazpiNjFmYWRlMTM5OWYwY2ZjNmZjZjcxNTU0OTljNTNkOQ==" + return "Basic cGF0cmljazp3b3JraGFyZA==" } -func crmFileDataString(path string) string { - //read file +//crmFileDataString, encode a base64 string of the given file +//so that the receiver EspoCRM can correctly understand and decode it. +//"data:image/png;base64,iVB....=" +// +//TODO: for big files, this might ave issue cause out of memory +func crmFileDataString(path string, fileInfo crmFileInfo) (encoded string, err error) { + content, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + b64content := base64.StdEncoding.EncodeToString(content) + encoded = fmt.Sprintf("data:%s;base64,%s", fileInfo.Type, b64content) + //encode it - return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXIAAAFyAQMAAADS6sNKAAAABlBMVEX///8AAABVwtN+AAABsklEQVR4nO2aS47EIAxEkXKAHClX7yPlAJHcwR8MgZnljCqqWrjzefQG29iQUiiKoiiK+h+J67Krcqg566s93n3I4/J2s1/1apP7shq9vU2PkMfk67TrO/UCN5s9M0ch/wq+uoI6hYjFO/k38Yaa0eHkX8GXYe6b0Wc9Qh6Sz3rssz/Msh4jD8X3I9t6raX2miKPxasr3F1UjfJTl+rN0HCFbfIf8kC8zn033NBTmyqx9oo8Ml97J98Faeu1ds7aVE31GHk43k1U3mHkfJRi5CF58V3MLrN7U+WJ4OEP5JF4i2grxYLPreq5MiOPxQdweWYvLZWrPxxT0JOH4rPKHraq16UbeTg+UrlEAWYOEPX2yn/IY/GezyVLbc/nl/8beVw+HucBRFULf0XI4/IZ1j73w8liWYg8Eh+ldoT1ERsgnWeQx+X7kZnA9xz03O8iD8X7tEeXXErpv9eyQeSBebsJIJtm94cpP5AH43cP8OinfKk2zeeP5GH56KfSFeZDCfKovNjOtcjYSv3oD+QxeP1prbL1U/m91llGkQfjXddQb9t54u/1G3kEnqIoiqKov9QXf1Q2La7tzOYAAAAASUVORK5CYII=" + return encoded, nil } -func crmPostAttach(path string) (resp string, err error) { +func crmUploadAttachmentMeta(fileID string, fileInfo crmFileInfo) (resp string, err error) { headers := map[string]string{} headers["Authorization"] = crmAuthHeader() headers["Accept"] = "application/json, text/javascript, */*; q=0.01" - data := []byte(crmFileDataString(path)) - URL := crmPostAttachmentURL() - resp, err = postRAW(data, URL, headers) + headers["Content-Type"] = "application/json" + + fileInfo.Role = "Attachment" + jb, _ := json.Marshal(fileInfo) + log.Println(string(jb)) + + URL := crmAttachmentMetaURL(fileID) + resp, err = putRAW(jb, URL, headers) return } +func crmAttachmentMetaURL(fileID string) string { + return "https://c.hitxy.org.au/api/v1/Attachment/" + fileID +} + type attachmentInfo struct { ID string `json:"id"` //"id": "591e55398345683ee", Name string `json:"name"` //"name": "static_qr_code_without_logo.png", @@ -62,21 +116,12 @@ type attachmentInfo struct { CreatedbyName string `json:"createdByName"` // "createdByName": "Admin" } -func crmPatchAttachmentInfo(id string) (j string) { - info := map[string]interface{}{} - //{"name":"static_qr_code_without_logo.png","type":"image/png","role":"Attachment","size":509} - info["name"] = "static_qr_code_without_logo.png" - info["type"] = "image/png" - info["role"] = "Attachment" - info["size"] = 509 - url := "https://c.hitxy.org.au/api/v1/Attachment/591e5f7b9463d7147" - - headers := map[string]string{} - headers["Authorization"] = crmAuthHeader() - headers["Content-Type"] = "application/json" - - jb, _ := json.Marshal(info) - log.Println(string(jb)) - j, _ = putRAW(jb, url, headers) +func crmCreateAttachment(path string) (result attachmentInfo, err error) { + fileID, fileInfo, err := crmUploadFile(path) + aInfo, err := crmUploadAttachmentMeta(fileID, fileInfo) + if err != nil { + return + } + json.Unmarshal([]byte(aInfo), &result) return } diff --git a/crmAttachment_test.go b/crmAttachment_test.go index c57285c..a90bcd5 100644 --- a/crmAttachment_test.go +++ b/crmAttachment_test.go @@ -5,13 +5,14 @@ import "log" import "encoding/json" func TestCRMAttachFile(t *testing.T) { - id := crmAttachFile("media_for_test/200x200.png") - log.Println(id) - + r, e := crmCreateAttachment("media_for_test/200x200.png") + log.Println(r) + log.Println(e) } func TestPatchAttachmentInfo(t *testing.T) { - crmPatchAttachmentInfo("591e5f7b9463d7147") + //crmPatchAttachmentInfo("591e5f7b9463d7147") + crmCreateAttachment("abc") } func TestDecodeJsonResponse(t *testing.T) { diff --git a/fileinfo.go b/fileinfo.go index c144c87..36a5d43 100644 --- a/fileinfo.go +++ b/fileinfo.go @@ -6,6 +6,8 @@ import ( "os" "strings" + "path/filepath" + filetype "gopkg.in/h2non/filetype.v1" ) @@ -93,3 +95,11 @@ func isJPG(path string) bool { check2 := strings.EqualFold("image/jpeg", mime) return check1 && check2 } + +//get file Info for uploading CRM attachment /files +func getFileInfo4CRM(path string) (info crmFileInfo, err error) { + info.Name = filepath.Base(path) + filepath.Ext(path) + info.Type, _, err = getFileMime(path) + info.Size, err = getFileSize(path) + return +} diff --git a/upload.go b/upload.go index e36d30c..0ca83a0 100644 --- a/upload.go +++ b/upload.go @@ -8,7 +8,6 @@ import ( "log" "mime/multipart" "net/http" - "net/http/httputil" "os" ) @@ -56,7 +55,9 @@ func postFileForm(filename string, targetURL string, formFieldName string) (strJ } func postJSON(jsonB []byte, targetURL string) (resp string, err error) { - return postRAW(jsonB, targetURL, nil) + headers := map[string]string{} + headers["Content-Type"] = "application/json" + return postRAW(jsonB, targetURL, headers) } func postRAW(data []byte, targetURL string, headers map[string]string) (resp string, err error) { @@ -86,11 +87,11 @@ func httpRaw(httpMethod, targetURL string, data []byte, headers map[string]strin } defer r.Body.Close() - dump, err := httputil.DumpResponse(r, true) - if err != nil { - log.Fatal(err) - } - fmt.Printf("dump : %q", dump) + // dump, err := httputil.DumpResponse(r, true) + // if err != nil { + // log.Fatal(err) + // } + // fmt.Printf("dump : %q", dump) b, _ := ioutil.ReadAll(r.Body) resp = string(b)