-
Notifications
You must be signed in to change notification settings - Fork 22
/
file.go
140 lines (117 loc) · 2.86 KB
/
file.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
package graphql
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"strconv"
)
type File interface {
io.Reader
io.Closer
}
type Upload struct {
File File
FileName string
}
type UploadMap []struct {
upload Upload
positions []string
}
func (u *UploadMap) UploadMap() map[string][]string {
var result = make(map[string][]string)
for idx, attachment := range *u {
result[strconv.Itoa(idx)] = attachment.positions
}
return result
}
func (u *UploadMap) NotEmpty() bool {
return len(*u) > 0
}
func (u *UploadMap) Add(upload Upload, varName string) {
*u = append(*u, struct {
upload Upload
positions []string
}{
upload,
[]string{fmt.Sprintf("variables.%s", varName)},
})
}
// returns a map of file names to paths.
// Used only in testing extractFiles
func (u *UploadMap) uploads() map[string]string {
var result = make(map[string]string)
for _, attachment := range *u {
result[attachment.upload.FileName] = attachment.positions[0]
}
return result
}
// function extracts attached files and sets respective variables to null
func extractFiles(input *QueryInput) *UploadMap {
uploadMap := &UploadMap{}
for varName, value := range input.Variables {
uploadMap.extract(value, varName)
if _, ok := value.(Upload); ok { //If the value was an upload, set the respective QueryInput variable to null
input.Variables[varName] = nil
}
}
return uploadMap
}
func (u *UploadMap) extract(value interface{}, path string) {
switch val := value.(type) {
case Upload: // Upload found
u.Add(val, path)
case map[string]interface{}:
for k, v := range val {
u.extract(v, fmt.Sprintf("%s.%s", path, k))
if _, ok := v.(Upload); ok { //If the value was an upload, set the respective QueryInput variable to null
val[k] = nil
}
}
case []interface{}:
for i, v := range val {
u.extract(v, fmt.Sprintf("%s.%d", path, i))
if _, ok := v.(Upload); ok { //If the value was an upload, set the respective QueryInput variable to null
val[i] = nil
}
}
}
return
}
func prepareMultipart(payload []byte, uploadMap *UploadMap) (body []byte, contentType string, err error) {
var b = bytes.Buffer{}
var fw io.Writer
w := multipart.NewWriter(&b)
fw, err = w.CreateFormField("operations")
if err != nil {
return
}
_, err = fw.Write(payload)
if err != nil {
return
}
fw, err = w.CreateFormField("map")
if err != nil {
return
}
err = json.NewEncoder(fw).Encode(uploadMap.UploadMap())
if err != nil {
return
}
for index, uploadVariable := range *uploadMap {
fw, err := w.CreateFormFile(strconv.Itoa(index), uploadVariable.upload.FileName)
if err != nil {
return b.Bytes(), w.FormDataContentType(), err
}
_, err = io.Copy(fw, uploadVariable.upload.File)
if err != nil {
return b.Bytes(), w.FormDataContentType(), err
}
}
err = w.Close()
if err != nil {
return
}
return b.Bytes(), w.FormDataContentType(), nil
}