Marvin Preuss
1d4ae27878
All checks were successful
continuous-integration/drone/push Build is passing
148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package restclient
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/textproto"
|
|
)
|
|
|
|
// MultipartBuffer holds the Body & ContentType of the multipart body
|
|
type MultipartBuffer struct {
|
|
Buffer *bytes.Buffer
|
|
ContentType string
|
|
}
|
|
|
|
// PayloadWithFiles returns the given payload as multipart body with all files in it
|
|
//goland:noinspection GoUnusedExportedFunction
|
|
func PayloadWithFiles(v interface{}, files ...File) (buffer *MultipartBuffer, err error) {
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
writer.FormDataContentType()
|
|
defer func() {
|
|
_ = writer.Close()
|
|
}()
|
|
|
|
var payload []byte
|
|
payload, err = json.Marshal(v)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
part, err := writer.CreatePart(partHeader(`form-data; name="payload_json"`, "application/json"))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if _, err = part.Write(payload); err != nil {
|
|
return
|
|
}
|
|
|
|
for i, file := range files {
|
|
var name string
|
|
if file.Flags.Has(FileFlagSpoiler) {
|
|
name = "SPOILER_" + file.Name
|
|
} else {
|
|
name = file.Name
|
|
}
|
|
part, err = writer.CreatePart(partHeader(fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, name), "application/octet-stream"))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if _, err = io.Copy(part, file.Reader); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
buffer = &MultipartBuffer{
|
|
Buffer: body,
|
|
ContentType: writer.FormDataContentType(),
|
|
}
|
|
return
|
|
}
|
|
|
|
func partHeader(contentDisposition string, contentType string) textproto.MIMEHeader {
|
|
return textproto.MIMEHeader{
|
|
"Content-Disposition": []string{contentDisposition},
|
|
"Content-Type": []string{contentType},
|
|
}
|
|
}
|
|
|
|
// NewFile returns a new File struct with the given name, io.Reader & FileFlags
|
|
func NewFile(name string, reader io.Reader, flags ...FileFlags) File {
|
|
return File{
|
|
Name: name,
|
|
Reader: reader,
|
|
Flags: FileFlagNone.Add(flags...),
|
|
}
|
|
}
|
|
|
|
// File holds all information about a given io.Reader
|
|
type File struct {
|
|
Name string
|
|
Reader io.Reader
|
|
Flags FileFlags
|
|
}
|
|
|
|
// FileFlags are used to mark Attachments as Spoiler
|
|
type FileFlags int
|
|
|
|
// all FileFlags
|
|
const (
|
|
FileFlagSpoiler FileFlags = 1 << iota
|
|
FileFlagNone FileFlags = 0
|
|
)
|
|
|
|
// Add allows you to add multiple FileFlags together, producing a new FileFlags
|
|
func (f FileFlags) Add(flags ...FileFlags) FileFlags {
|
|
total := FileFlags(0)
|
|
for _, flag := range flags {
|
|
total |= flag
|
|
}
|
|
f |= total
|
|
return f
|
|
}
|
|
|
|
// Remove allows you to subtract multiple FileFlags from the first, producing a new FileFlags
|
|
func (f FileFlags) Remove(flags ...FileFlags) FileFlags {
|
|
total := FileFlags(0)
|
|
for _, flag := range flags {
|
|
total |= flag
|
|
}
|
|
f &^= total
|
|
return f
|
|
}
|
|
|
|
// HasAll will ensure that the FileFlags includes all of the FileFlags(s) entered
|
|
func (f FileFlags) HasAll(flags ...FileFlags) bool {
|
|
for _, flag := range flags {
|
|
if !f.Has(flag) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Has will check whether the FileFlags contains another FileFlags
|
|
func (f FileFlags) Has(flag FileFlags) bool {
|
|
return (f & flag) == flag
|
|
}
|
|
|
|
// MissingAny will check whether the FileFlags is missing any one of the FileFlags
|
|
func (f FileFlags) MissingAny(flags ...FileFlags) bool {
|
|
for _, flag := range flags {
|
|
if !f.Has(flag) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Missing will do the inverse of FileFlags.Has
|
|
func (f FileFlags) Missing(flag FileFlags) bool {
|
|
return !f.Has(flag)
|
|
}
|