grim/youtrack-import
Clone
Summary
Browse
Changes
Graph
Use the built in mime stuff to figure out the content type for attachments
2020-01-14, Gary Kramlich
4763018b25c8
Use the built in mime stuff to figure out the content type for attachments
package
youtrack
import
(
"fmt"
"io"
"mime"
"mime/multipart"
"net/http"
"net/textproto"
"net/url"
"path/filepath"
"strings"
"time"
)
type
Attachment
struct
{
issue
int
author
string
created
time
.
Time
payload
*
strings
.
Builder
writer
*
multipart
.
Writer
files
[]
string
}
func
NewAttachment
(
issue
int
,
author
string
,
created
time
.
Time
)
*
Attachment
{
a
:=
&
Attachment
{
issue
:
issue
,
author
:
author
,
created
:
created
,
files
:
[]
string
{},
}
a
.
payload
=
&
strings
.
Builder
{}
a
.
writer
=
multipart
.
NewWriter
(
a
.
payload
)
return
a
}
func
(
a
*
Attachment
)
Payload
()
(
string
,
error
)
{
if
err
:=
a
.
writer
.
Close
();
err
!=
nil
{
return
""
,
err
}
return
a
.
payload
.
String
(),
nil
}
var
quoteEscaper
=
strings
.
NewReplacer
(
"\\"
,
"\\\\"
,
`"`
,
"\\\""
)
func
escapeQuotes
(
s
string
)
string
{
return
quoteEscaper
.
Replace
(
s
)
}
func
(
a
*
Attachment
)
AddFile
(
r
io
.
ReadCloser
,
filename
string
)
error
{
header
:=
textproto
.
MIMEHeader
{}
header
.
Set
(
"Content-Disposition"
,
fmt
.
Sprintf
(
"form-data; name=%q; filename=%q"
,
escapeQuotes
(
filename
),
escapeQuotes
(
filename
),
),
)
contentType
:=
""
ext
:=
filepath
.
Ext
(
filename
)
if
ext
!=
""
{
contentType
=
mime
.
TypeByExtension
(
ext
)
}
if
contentType
==
""
{
contentType
=
"application/octet-stream"
}
header
.
Set
(
"Content-Type"
,
contentType
)
w
,
err
:=
a
.
writer
.
CreatePart
(
header
)
if
err
!=
nil
{
return
err
}
_
,
err
=
io
.
Copy
(
w
,
r
)
if
err
!=
nil
{
return
err
}
defer
r
.
Close
()
a
.
files
=
append
(
a
.
files
,
filename
)
return
nil
}
func
(
a
*
Attachment
)
ContentType
()
string
{
return
a
.
writer
.
FormDataContentType
()
}
func
(
c
*
Client
)
importAttachment
(
p
*
Project
,
a
*
Attachment
)
error
{
values
:=
url
.
Values
{}
values
.
Add
(
"authorLogin"
,
a
.
author
)
values
.
Add
(
"created"
,
formatTimeString
(
a
.
created
))
payload
,
err
:=
a
.
Payload
()
if
err
!=
nil
{
return
err
}
reader
:=
strings
.
NewReader
(
payload
)
issueID
:=
fmt
.
Sprintf
(
"%s-%d"
,
p
.
ID
,
a
.
issue
)
resp
,
err
:=
c
.
requestContentType
(
http
.
MethodPost
,
c
.
uri
+
"/import/"
+
issueID
+
"/attachment?"
+
values
.
Encode
(),
a
.
ContentType
(),
reader
,
)
if
err
!=
nil
{
return
err
}
defer
resp
.
Body
.
Close
()
return
c
.
validateXmlImportReport
(
[]
int
{
http
.
StatusOK
,
http
.
StatusCreated
},
resp
,
)
}
func
(
c
*
Client
)
ImportAttachments
(
p
*
Project
)
error
{
for
_
,
issue
:=
range
p
.
Issues
{
for
_
,
attachment
:=
range
issue
.
Attachments
{
if
err
:=
c
.
importAttachment
(
p
,
attachment
);
err
!=
nil
{
return
err
}
}
}
return
nil
}