Skip to content

Commit d6c4fcc

Browse files
committed
feature: allow file upload for getuploadparams* apis
Fixes #144 Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 4673829 commit d6c4fcc

File tree

1 file changed

+115
-1
lines changed

1 file changed

+115
-1
lines changed

cmd/api.go

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,15 @@
1818
package cmd
1919

2020
import (
21+
"bytes"
2122
"errors"
2223
"fmt"
24+
"io"
25+
"mime/multipart"
26+
"net/http"
27+
"os"
28+
"path/filepath"
29+
"reflect"
2330
"strings"
2431
)
2532

@@ -111,9 +118,116 @@ func init() {
111118

112119
if len(response) > 0 {
113120
printResult(r.Config.Core.Output, response, filterKeys, excludeKeys)
121+
if r.Config.HasShell {
122+
apiName := strings.ToLower(api.Name)
123+
if apiName == "getuploadparamsforiso" ||
124+
apiName == "getuploadparamsforvolume" ||
125+
apiName == "getuploadparamsfotemplate" {
126+
promptForFileUpload(r, apiName, response)
127+
}
128+
}
114129
}
115-
116130
return nil
117131
},
118132
}
119133
}
134+
135+
func promptForFileUpload(r *Request, api string, response map[string]interface{}) {
136+
fmt.Print("Enter path of the file(s) to upload (comma-separated): ")
137+
var filePaths string
138+
fmt.Scanln(&filePaths)
139+
filePathsList := strings.FieldsFunc(filePaths, func(r rune) bool { return r == ',' })
140+
141+
var missingFiles []string
142+
var validFiles []string
143+
for _, filePath := range filePathsList {
144+
filePath = strings.TrimSpace(filePath)
145+
if filePath == "" {
146+
continue
147+
}
148+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
149+
missingFiles = append(missingFiles, filePath)
150+
} else {
151+
validFiles = append(validFiles, filePath)
152+
}
153+
}
154+
if len(missingFiles) > 0 {
155+
fmt.Println("File(s) do not exist or are not accessible:", strings.Join(missingFiles, ", "))
156+
return
157+
}
158+
if len(validFiles) == 0 {
159+
fmt.Println("No valid files to upload.")
160+
return
161+
}
162+
paramsRaw, ok := response["getuploadparams"]
163+
if !ok || reflect.TypeOf(paramsRaw).Kind() != reflect.Map {
164+
fmt.Println("Invalid response format for getuploadparams.")
165+
return
166+
}
167+
params := paramsRaw.(map[string]interface{})
168+
requiredKeys := []string{"postURL", "metadata", "signature", "expires"}
169+
for _, key := range requiredKeys {
170+
if _, ok := params[key]; !ok {
171+
fmt.Printf("Missing required key '%s' in getuploadparams response.\n", key)
172+
return
173+
}
174+
}
175+
176+
postURL, _ := params["postURL"].(string)
177+
signature, _ := params["signature"].(string)
178+
expires, _ := params["expires"].(string)
179+
metadata, _ := params["metadata"].(string)
180+
181+
fmt.Println("Uploading files for", api, ":", validFiles)
182+
spinner := r.Config.StartSpinner("uploading files, please wait...")
183+
defer r.Config.StopSpinner(spinner)
184+
185+
for _, filePath := range validFiles {
186+
if err := uploadFile(postURL, filePath, signature, expires, metadata); err != nil {
187+
fmt.Println("Error uploading", filePath, ":", err)
188+
}
189+
}
190+
}
191+
192+
// uploadFile uploads a single file to the given postURL with the required headers.
193+
func uploadFile(postURL, filePath, signature, expires, metadata string) error {
194+
file, err := os.Open(filePath)
195+
if err != nil {
196+
return err
197+
}
198+
defer file.Close()
199+
200+
var body bytes.Buffer
201+
writer := multipart.NewWriter(&body)
202+
part, err := writer.CreateFormFile("file", filepath.Base(filePath))
203+
if err != nil {
204+
return err
205+
}
206+
if _, err := io.Copy(part, file); err != nil {
207+
return err
208+
}
209+
writer.Close()
210+
211+
req, err := http.NewRequest("POST", postURL, &body)
212+
if err != nil {
213+
return err
214+
}
215+
req.Header.Set("Content-Type", writer.FormDataContentType())
216+
req.Header.Set("x-signature", signature)
217+
req.Header.Set("x-expires", expires)
218+
req.Header.Set("x-metadata", metadata)
219+
220+
client := &http.Client{}
221+
resp, err := client.Do(req)
222+
if err != nil {
223+
return err
224+
}
225+
defer resp.Body.Close()
226+
227+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
228+
respBody, _ := io.ReadAll(resp.Body)
229+
return fmt.Errorf("upload failed: %s", string(respBody))
230+
}
231+
fmt.Println("Upload successful for:", filePath)
232+
return nil
233+
}

0 commit comments

Comments
 (0)