@@ -33,6 +33,8 @@ import (
33
33
"golang.org/x/oauth2"
34
34
)
35
35
36
+ const TemplateFileExtension = ".tino"
37
+
36
38
type StorageApiClient struct {
37
39
client * http.Client
38
40
host string
@@ -95,6 +97,22 @@ func (c *StorageApiClient) performMultipartRequest(endpoint, method, token, file
95
97
return res , nil
96
98
}
97
99
100
+ func (c * StorageApiClient ) performBinaryGetRequest (endpoint , token string ) (* http.Response , error ) {
101
+ req , err := http .NewRequest ("GET" , endpoint , nil )
102
+ if err != nil {
103
+ return nil , err
104
+ }
105
+ req .Header .Add ("Authorization" , "Bearer " + token )
106
+ if c .organization != "" {
107
+ req .Header .Add ("X-Organization" , c .organization )
108
+ }
109
+ res , err := c .client .Do (req )
110
+ if err != nil {
111
+ return nil , err
112
+ }
113
+ return res , nil
114
+ }
115
+
98
116
func (c * StorageApiClient ) ImportCustomTemplate (templateFile string ) (* ImportCustomTemplateResponse , error ) {
99
117
100
118
if templateFile == "" {
@@ -141,3 +159,97 @@ func (c *StorageApiClient) ImportCustomTemplate(templateFile string) (*ImportCus
141
159
142
160
return nil , err
143
161
}
162
+
163
+ func (c * StorageApiClient ) ExportCustomTemplate (templateId string ) (* string , error ) {
164
+
165
+ if templateId == "" {
166
+ return nil , fmt .Errorf ("invalid template id: no id provided" )
167
+ }
168
+
169
+ userRequestToken , err := c .src .Token ()
170
+ if err != nil {
171
+ if strings .Contains (err .Error (), "401" ) {
172
+ return nil , errors .New ("wrong credentials" )
173
+ }
174
+ return nil , fmt .Errorf ("cannot retrieve a valid token: %w" , err )
175
+ }
176
+
177
+ endpoint := c .host + "/storage/template/archive/v1/" + templateId
178
+ res , err := c .performBinaryGetRequest (endpoint , userRequestToken .AccessToken )
179
+ if err != nil {
180
+ return nil , err
181
+ }
182
+ defer res .Body .Close ()
183
+
184
+
185
+ if res .StatusCode == 200 {
186
+ outfile , fileExportPath , err := createNewLocalFile (templateId , res )
187
+ if err != nil {
188
+ return nil , err
189
+ }
190
+ defer outfile .Close ()
191
+ io .Copy (outfile , res .Body )
192
+ return & fileExportPath , nil
193
+ } else if res .StatusCode == 400 {
194
+ bodyb , _ := io .ReadAll (res .Body )
195
+ return nil , fmt .Errorf ("bad request: %s" , string (bodyb ))
196
+ } else if res .StatusCode == 401 {
197
+ return nil , errors .New ("unauthorized request" )
198
+ } else if res .StatusCode == 403 {
199
+ return nil , errors .New ("forbidden request" )
200
+ } else if res .StatusCode == 500 {
201
+ return nil , errors .New ("internal server error" )
202
+ }
203
+
204
+ return nil , err
205
+ }
206
+
207
+ func createNewLocalFile (templateId string , res * http.Response ) (* os.File , string , error ) {
208
+ fileExportPath , err := composeNewLocalFileName (templateId , res )
209
+ if err != nil {
210
+ return nil , "" , err
211
+ }
212
+ outfile , err := os .Create (fileExportPath )
213
+ if err != nil {
214
+ return nil , "" , err
215
+ }
216
+ return outfile , fileExportPath , nil
217
+ }
218
+
219
+ func composeNewLocalFileName (templateId string , res * http.Response ) (string , error ) {
220
+ fileExportPath := extractFileNameFromHeader (res )
221
+ originalFileExportName := fileExportPath
222
+ if fileExportPath == "" {
223
+ fileExportPath = templateId + TemplateFileExtension
224
+ }
225
+
226
+ i := 1
227
+ for ; i < 51 ; i ++ {
228
+ _ , err := os .Stat (fileExportPath )
229
+ if err != nil {
230
+ if os .IsNotExist (err ) {
231
+ break
232
+ } else {
233
+ newbase := strings .TrimSuffix (originalFileExportName , TemplateFileExtension )
234
+ newbase = newbase + "_" + string (i ) + TemplateFileExtension
235
+ fileExportPath = newbase
236
+ }
237
+ }
238
+ }
239
+ if i >= 50 {
240
+ return "" , errors .New ("cannot create a new file name. Max number of copy reached." )
241
+ }
242
+
243
+ return fileExportPath , nil
244
+ }
245
+
246
+ func extractFileNameFromHeader (res * http.Response ) string {
247
+ content := res .Header .Get ("Content-Disposition" )
248
+ if strings .HasPrefix (content , "attachment;" ) {
249
+ content = strings .TrimPrefix (content , "attachment;" )
250
+ content = strings .TrimSpace (content )
251
+ content = strings .TrimPrefix (content , "filename=" )
252
+ return strings .Trim (content , "\" " )
253
+ }
254
+ return ""
255
+ }
0 commit comments