-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathattachment.go
206 lines (173 loc) · 4.8 KB
/
attachment.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package zendesk
import (
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"sync"
)
// Attachment is struct for attachment payload
// https://developer.zendesk.com/rest_api/docs/support/attachments.html
type Attachment struct {
ID int64 `json:"id,omitempty"`
FileName string `json:"file_name,omitempty"`
ContentURL string `json:"content_url,omitempty"`
ContentType string `json:"content_type,omitempty"`
Size int64 `json:"size,omitempty"`
Thumbnails []Photo `json:"thumbnails,omitempty"`
Inline bool `json:"inline,omitempty"`
}
// Photo is thumbnail which is included in attachment
type Photo struct {
ID int64 `json:"id"`
FileName string `json:"file_name"`
ContentURL string `json:"content_url"`
ContentType string `json:"content_type"`
Size int64 `json:"size"`
}
// Upload is the API response received from zendesk whenc creating attachments
type Upload struct {
Attachment Attachment `json:"attachment"`
Attachments []Attachment `json:"attachments"`
Token string `json:"token"`
}
type result struct {
body []byte
err error
resp *http.Response
}
// UploadWriter is used to write a zendesk attachment
type UploadWriter interface {
io.Writer
Close() (Upload, error)
}
type writer struct {
*Client
once sync.Once
w io.WriteCloser
filename string
token string
c chan result
ctx context.Context
}
func (wr *writer) open() error {
r, w := io.Pipe()
wr.c = make(chan result)
wr.w = w
path := "/uploads.json"
req, err := http.NewRequest(http.MethodPost, wr.baseURL.String()+path, r)
if err != nil {
return err
}
req = wr.prepareRequest(wr.ctx, req)
req.Header.Set("Content-Type", "application/binary")
q := req.URL.Query()
if wr.token != "" {
q.Add("token", wr.token)
}
q.Add("filename", wr.filename)
req.URL.RawQuery = q.Encode()
go func() {
resp, err := wr.httpClient.Do(req)
if err != nil {
wr.c <- result{
err: err,
}
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
wr.c <- result{
err: err,
}
return
}
wr.c <- result{
body: body,
resp: resp,
}
}()
return nil
}
func (wr *writer) Write(p []byte) (n int, err error) {
wr.once.Do(func() {
err = wr.open()
})
if err != nil {
return 0, err
}
return wr.w.Write(p)
}
func (wr *writer) Close() (Upload, error) {
defer close(wr.c)
err := wr.w.Close()
if err != nil {
return Upload{}, err
}
result := <-wr.c
if result.err != nil {
return Upload{}, result.err
}
resp, body := result.resp, result.body
if resp.StatusCode != http.StatusCreated {
return Upload{}, Error{
resp: resp,
body: body,
}
}
var data struct {
Upload Upload `json:"upload"`
}
err = json.Unmarshal(body, &data)
if err != nil {
return Upload{}, err
}
return data.Upload, nil
}
// AttachmentAPI an interface containing all of the attachment related zendesk methods
type AttachmentAPI interface {
UploadAttachment(ctx context.Context, filename string, token string) UploadWriter
DeleteUpload(ctx context.Context, token string) error
GetAttachment(ctx context.Context, id int64) (Attachment, error)
}
// UploadAttachment returns a writer that can be used to create a zendesk attachment
// ref: https://developer.zendesk.com/rest_api/docs/support/attachments#upload-files
func (z *Client) UploadAttachment(ctx context.Context, filename string, token string) UploadWriter {
return &writer{
Client: z,
filename: filename,
token: token,
ctx: ctx,
}
}
// DeleteUpload deletes a previously uploaded file
// ref: https://developer.zendesk.com/rest_api/docs/support/attachments#delete-upload
func (z *Client) DeleteUpload(ctx context.Context, token string) error {
return z.delete(ctx, fmt.Sprintf("/uploads/%s.json", token))
}
// GetAttachment returns the current state of an uploaded attachment
// ref: https://developer.zendesk.com/rest_api/docs/support/attachments#show-attachment
func (z *Client) GetAttachment(ctx context.Context, id int64) (Attachment, error) {
var result struct {
Attachment Attachment `json:"attachment"`
}
body, err := z.get(ctx, fmt.Sprintf("/attachments/%d.json", id))
if err != nil {
return Attachment{}, err
}
err = json.Unmarshal(body, &result)
if err != nil {
return Attachment{}, err
}
return result.Attachment, nil
}
// RedactCommentAttachment deletes an attachment with attachmentID on comment with commentID for ticket with ticketID
// https://developer.zendesk.com/api-reference/ticketing/tickets/ticket-attachments/#redact-comment-attachment
func (z *Client) RedactCommentAttachment(ctx context.Context, ticketID, commentID, attachmentID int64) error {
path := fmt.Sprintf("/api/v2/tickets/%d/comments/%d/attachments/%d/redact", ticketID, commentID, attachmentID)
_, err := z.put(ctx, path, nil)
return err
}