3
3
import typing
4
4
import uuid
5
5
6
+ from marshmallow import Schema
7
+ from marshmallow import fields as schema_fields
8
+
6
9
from commercetools import schemas , types
7
10
from commercetools .testing .abstract import BaseModel , ServiceBackend
8
- from commercetools .testing .utils import custom_fields_from_draft , get_product_variants
11
+ from commercetools .testing .utils import (
12
+ create_commercetools_response ,
13
+ custom_fields_from_draft ,
14
+ get_product_variants ,
15
+ parse_request_params ,
16
+ )
9
17
10
18
11
19
class ProductsModel (BaseModel ):
@@ -149,17 +157,35 @@ def _create_price_from_draft(
149
157
)
150
158
151
159
152
- def _get_target_obj (obj : dict , action : types .ProductUpdateAction , default_staged = False ):
153
- staged = getattr (action , "staged" , default_staged )
160
+ def _get_target_obj (obj : dict , staged : bool ):
154
161
if not staged and obj ["masterData" ]["current" ]:
155
162
return obj ["masterData" ]["current" ]
156
163
return obj ["masterData" ]["staged" ]
157
164
158
165
166
+ def _get_variant (
167
+ data_object : dict , * , id : str = "" , sku : str = ""
168
+ ) -> typing .Optional [dict ]:
169
+ if not data_object :
170
+ return None
171
+
172
+ variants = [data_object ["masterVariant" ]]
173
+ if data_object ["variants" ]:
174
+ variants += data_object ["variants" ]
175
+
176
+ for variant in variants :
177
+ if id and id == variant ["id" ]:
178
+ return variant
179
+ if sku and sku == variant ["sku" ]:
180
+ return variant
181
+
182
+ return None
183
+
184
+
159
185
def _update_productdata_attr (dst : str , src : str ):
160
186
def updater (self , obj : dict , action : types .ProductUpdateAction ):
161
187
value = getattr (action , src )
162
- target_obj = _get_target_obj (obj , action )
188
+ target_obj = _get_target_obj (obj , getattr ( action , "staged" , False ) )
163
189
164
190
if target_obj [dst ] != value :
165
191
new = copy .deepcopy (obj )
@@ -175,16 +201,9 @@ def updater(self, obj: dict, action: types.ProductSetAttributeAction):
175
201
staged = getattr (action , "staged" , False )
176
202
new = copy .deepcopy (obj )
177
203
178
- target_obj = _get_target_obj (new , action )
179
-
180
- variants = [target_obj ["masterVariant" ]]
181
- if target_obj ["variants" ]:
182
- variants += target_obj ["variants" ]
183
-
184
- for variant in variants :
185
- if action .variant_id != variant ["id" ]:
186
- continue
187
-
204
+ target_obj = _get_target_obj (new , staged )
205
+ variant = _get_variant (target_obj , id = action .variant_id )
206
+ if variant :
188
207
for attr in variant ["attributes" ]:
189
208
if attr ["name" ] == action .name :
190
209
attr ["value" ] = action .value
@@ -195,7 +214,6 @@ def updater(self, obj: dict, action: types.ProductSetAttributeAction):
195
214
variant ["attributes" ].append (
196
215
attr_schema .dump (types .Attribute (name = action .name , value = action .value ))
197
216
)
198
- break
199
217
200
218
return new
201
219
@@ -217,7 +235,7 @@ def updater(self, obj: dict, action: types.ProductAddVariantAction):
217
235
schema = schemas .ProductVariantSchema ()
218
236
219
237
new = copy .deepcopy (obj )
220
- target_obj = _get_target_obj (new , action )
238
+ target_obj = _get_target_obj (new , staged = getattr ( action , "staged" , True ) )
221
239
if not target_obj ["variants" ]:
222
240
target_obj ["variants" ] = []
223
241
target_obj ["variants" ].append (schema .dump (variant ))
@@ -243,7 +261,7 @@ def updater(self, obj: dict, action: types.ProductPublishAction):
243
261
def _set_product_prices ():
244
262
def updater (self , obj : dict , action : types .ProductSetPricesAction ):
245
263
new = copy .deepcopy (obj )
246
- target_obj = _get_target_obj (new , action , default_staged = True )
264
+ target_obj = _get_target_obj (new , getattr ( action , "staged" , True ) )
247
265
prices = []
248
266
for price_draft in action .prices :
249
267
price = types .Price (
@@ -275,6 +293,12 @@ def updater(self, obj: dict, action: types.ProductSetPricesAction):
275
293
return updater
276
294
277
295
296
+ class UploadImageQuerySchema (Schema ):
297
+ staged = schema_fields .Bool ()
298
+ filename = schema_fields .Field ()
299
+ sku = schema_fields .Field ()
300
+
301
+
278
302
class ProductsBackend (ServiceBackend ):
279
303
service_path = "products"
280
304
model_class = ProductsModel
@@ -292,6 +316,7 @@ def urls(self):
292
316
("^(?P<id>[^/]+)$" , "POST" , self .update_by_id ),
293
317
("^(?P<id>[^/]+)$" , "DELETE" , self .delete_by_id ),
294
318
("^key=(?P<key>[^/]+)$" , "DELETE" , self .delete_by_key ),
319
+ ("^(?P<id>[^/]+)\/images$" , "POST" , self .upload_image ),
295
320
]
296
321
297
322
# Fixme: use decorator for this
@@ -302,3 +327,26 @@ def urls(self):
302
327
"setPrices" : _set_product_prices (),
303
328
"publish" : _publish_product_action (),
304
329
}
330
+
331
+ def upload_image (self , request , id ):
332
+ obj = self .model .get_by_id (id )
333
+ if not obj :
334
+ return create_commercetools_response (request , status_code = 404 )
335
+
336
+ obj = copy .deepcopy (obj )
337
+
338
+ params = parse_request_params (UploadImageQuerySchema , request )
339
+ target = _get_target_obj (obj , staged = params ["staged" ])
340
+ filename = params ["filename" ]
341
+
342
+ variant = _get_variant (target , sku = params ["sku" ])
343
+ if not variant ["images" ]:
344
+ variant ["images" ] = []
345
+ image_schema = schemas .ImageSchema ()
346
+ variant ["images" ].append (
347
+ image_schema .dump (
348
+ types .Image (url = f"cdn.commercetools.local/detail-{ filename } " )
349
+ )
350
+ )
351
+ self .model .save (obj )
352
+ return create_commercetools_response (request , json = obj )
0 commit comments