1
1
package main
2
2
3
3
import (
4
+ "bytes"
4
5
"encoding/base64"
6
+ "encoding/json"
5
7
"errors"
6
8
"github.com/emersion/go-imap"
7
9
"github.com/emersion/go-imap/client"
@@ -12,13 +14,18 @@ import (
12
14
"io"
13
15
"io/ioutil"
14
16
"log"
17
+ "mime/multipart"
15
18
"net/http"
16
19
"os"
17
20
"os/signal"
18
21
"regexp"
19
22
"strings"
20
23
)
21
24
25
+ type AddIssueResponse struct {
26
+ Key string `json:"key"`
27
+ }
28
+
22
29
func main () {
23
30
cronInterval := os .Getenv ("CRON" )
24
31
c := cron .New ()
@@ -32,6 +39,27 @@ func main() {
32
39
33
40
}
34
41
42
+ func jsonEscape (i string ) string {
43
+ b , err := json .Marshal (i )
44
+ if err != nil {
45
+ log .Println (err )
46
+ }
47
+ s := string (b )
48
+ return s [1 :len (s )- 1 ]
49
+ }
50
+
51
+ func getAddIssueResponse (resp * http.Response ) AddIssueResponse {
52
+ bodyBytes , err := ioutil .ReadAll (resp .Body )
53
+ if err != nil {
54
+ log .Fatal (err )
55
+ }
56
+
57
+ response := AddIssueResponse {}
58
+ json .Unmarshal (bodyBytes , & response )
59
+
60
+ return response
61
+ }
62
+
35
63
func printErrorFromApi (resp * http.Response ) {
36
64
bodyBytes , err := ioutil .ReadAll (resp .Body )
37
65
if err != nil {
@@ -45,16 +73,14 @@ func printErrorFromApi(resp *http.Response) {
45
73
func getMailBody (p * mail.Part ) string {
46
74
sanitizePolicy := bluemonday .UGCPolicy ()
47
75
body , _ := ioutil .ReadAll (p .Body )
48
- plainTextBody := strings .Replace (string (body ), "\n " , "\\ n" , - 1 )
49
- plainTextBody = strings .Replace (plainTextBody , "\r " , "\\ r" , - 1 )
50
76
51
77
regex , err := regexp .Compile (`[^\w] && [\\]` )
52
78
if err != nil {
53
79
log .Fatal (err )
54
80
}
55
- plainTextBody = regex .ReplaceAllString (plainTextBody , " " )
81
+ plainTextBody : = regex .ReplaceAllString (string ( body ) , " " )
56
82
57
- return sanitizePolicy .Sanitize (plainTextBody )
83
+ return jsonEscape ( sanitizePolicy .Sanitize (plainTextBody ) )
58
84
}
59
85
60
86
func makePostRequest (endpoint string , body string ) * http.Response {
@@ -70,7 +96,46 @@ func makePostRequest(endpoint string, body string) *http.Response {
70
96
if err != nil {
71
97
log .Fatal (err )
72
98
}
73
- defer resp .Body .Close ()
99
+
100
+ return resp
101
+ }
102
+
103
+ func makePostRequestWithFile (endpoint string , filename string ) * http.Response {
104
+ jiraUrl := os .Getenv ("JIRA_URL" )
105
+ jiraUser := os .Getenv ("JIRA_USER" )
106
+ jiraPassword := os .Getenv ("JIRA_PASSWORD" )
107
+
108
+ clt := & http.Client {}
109
+
110
+ file , err := os .Open (filename )
111
+ if err != nil {
112
+ log .Fatal (err )
113
+ }
114
+ fileContents , err := ioutil .ReadAll (file )
115
+ if err != nil {
116
+ log .Fatal (err )
117
+ }
118
+
119
+ body := new (bytes.Buffer )
120
+ writer := multipart .NewWriter (body )
121
+ part , err := writer .CreateFormFile ("file" , filename )
122
+ if err != nil {
123
+ log .Fatal (err )
124
+ }
125
+ part .Write (fileContents )
126
+ err = writer .Close ()
127
+ if err != nil {
128
+ log .Fatal (err )
129
+ }
130
+
131
+ req , err := http .NewRequest ("POST" , jiraUrl + endpoint , body )
132
+ req .Header .Add ("X-Atlassian-Token" , "no-check" )
133
+ req .Header .Add ("Content-Type" , writer .FormDataContentType ())
134
+ req .Header .Add ("Authorization" , "Basic " + base64 .StdEncoding .EncodeToString ([]byte (jiraUser + ":" + jiraPassword )))
135
+ resp , err := clt .Do (req )
136
+ if err != nil {
137
+ log .Fatal (err )
138
+ }
74
139
75
140
return resp
76
141
}
@@ -171,6 +236,11 @@ func run() {
171
236
172
237
isMessageWithIssueNumber , _ := regexp .MatchString ("^.*\\ [.*-\\ d+]$" , subject )
173
238
239
+ issueNumber := ""
240
+ if isMessageWithIssueNumber {
241
+ issueNumber = subject [strings .LastIndex (subject , "[" )+ 1 : strings .LastIndex (subject , "]" )]
242
+ }
243
+
174
244
mr , err := mail .CreateReader (r )
175
245
if err != nil {
176
246
log .Fatal (err )
@@ -192,9 +262,14 @@ func run() {
192
262
log .Fatal (err )
193
263
}
194
264
195
- switch p .Header .(type ) {
265
+ switch h := p .Header .(type ) {
196
266
case * mail.InlineHeader :
197
267
sanitizedBody := getMailBody (p )
268
+ contentType , _ , _ := h .ContentType ()
269
+
270
+ if contentType != "text/plain" {
271
+ continue
272
+ }
198
273
199
274
if isMessageWithIssueNumber {
200
275
content , err := ioutil .ReadFile ("/go/src/app/structure_add_comment.json" )
@@ -206,8 +281,6 @@ func run() {
206
281
jsonString = strings .Replace (jsonString , "%SUMMARY%" , subject + " (" + sender .Name + " <" + sender .Address + ">)" , 1 )
207
282
jsonString = strings .Replace (jsonString , "%DESCRIPTION%" , strings .TrimSpace (sanitizedBody ), 1 )
208
283
209
- issueNumber := subject [strings .LastIndex (subject , "[" )+ 1 : strings .LastIndex (subject , "]" )]
210
-
211
284
resp := makeGetRequest ("/rest/api/" + jiraApiVersion + "/issue/" + issueNumber )
212
285
213
286
if resp .StatusCode != 200 {
@@ -216,11 +289,13 @@ func run() {
216
289
resp := makePostRequest ("/rest/api/" + jiraApiVersion + "/issue/" + issueNumber + "/comment" , jsonString )
217
290
218
291
if resp .StatusCode != 201 {
292
+ println ("Error while adding comment" )
219
293
printErrorFromApi (resp )
220
294
} else {
221
295
setMailAsSeenForService (c , currentUid )
222
- log .Println ("Success add comment" )
296
+ log .Println ("Success add comment for issue " + issueNumber )
223
297
}
298
+ defer resp .Body .Close ()
224
299
}
225
300
226
301
} else {
@@ -234,19 +309,42 @@ func run() {
234
309
jsonString = strings .Replace (jsonString , "%SUMMARY%" , subject , 1 )
235
310
jsonString = strings .Replace (jsonString , "%DESCRIPTION%" , strings .TrimSpace (sanitizedBody ), 1 )
236
311
237
- log .Println (jsonString )
238
-
239
312
resp := makePostRequest ("/rest/api/" + jiraApiVersion + "/issue" , jsonString )
240
313
241
314
if resp .StatusCode != 201 {
315
+ println ("Error while adding issue" )
242
316
printErrorFromApi (resp )
243
317
} else {
318
+ issueNumber = getAddIssueResponse (resp ).Key
244
319
setMailAsSeenForService (c , currentUid )
245
- log .Println ("Success add issue" )
320
+ log .Println ("Success add issue " + issueNumber )
246
321
}
247
322
}
323
+ case * mail.AttachmentHeader :
324
+ filename , _ := h .Filename ()
325
+ log .Println ("Found attachment \" " + filename + "\" for issue number " + issueNumber )
326
+ file , err := os .Create ("/tmp/" + filename )
327
+ if err != nil {
328
+ log .Fatal (err )
329
+ }
330
+ _ , err = io .Copy (file , p .Body )
331
+ if err != nil {
332
+ log .Fatal (err )
333
+ }
334
+
335
+ if issueNumber == "" {
336
+ log .Fatal ("Error, no issue number for attachment found" )
337
+ }
338
+
339
+ resp := makePostRequestWithFile ("/rest/api/" + jiraApiVersion + "/issue/" + issueNumber + "/attachments" , "/tmp/" + filename )
340
+ if resp .StatusCode != 200 {
341
+ println ("Error while adding attachment for issue " + issueNumber )
342
+ printErrorFromApi (resp )
343
+ } else {
344
+ log .Println ("Success add attachment for issue " + issueNumber )
345
+ }
346
+ defer resp .Body .Close ()
248
347
}
249
- break
250
348
}
251
349
}
252
350
0 commit comments