Skip to content

Commit 7850a67

Browse files
authored
Feature/test upload image (#90)
* Add upload_image handler for product testing service * Add upload_image return type * Copy incoming object and store result Co-authored-by: Tim Leguijt <t.leguijt@labdigital.nl>
1 parent 58a87ad commit 7850a67

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

CHANGES

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
8.1.2 (xxxx-xx-xx)
2+
------------------
3+
- Testing: Add upload_image handler for product testing service
4+
5+
16
8.1.1 (2020-05-20)
27
------------------
38
- Testing: Fix publish action on mock backend; already published products got overwritten

src/commercetools/services/products.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def upload_image(
218218
sku: str = None,
219219
filename: str = "img",
220220
staged: bool = True,
221-
):
221+
) -> types.Product:
222222
params = {"filename": filename, "staged": staged}
223223
if sku:
224224
params["sku"] = sku

src/commercetools/testing/products.py

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@
33
import typing
44
import uuid
55

6+
from marshmallow import Schema
7+
from marshmallow import fields as schema_fields
8+
69
from commercetools import schemas, types
710
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+
)
917

1018

1119
class ProductsModel(BaseModel):
@@ -149,17 +157,35 @@ def _create_price_from_draft(
149157
)
150158

151159

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):
154161
if not staged and obj["masterData"]["current"]:
155162
return obj["masterData"]["current"]
156163
return obj["masterData"]["staged"]
157164

158165

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+
159185
def _update_productdata_attr(dst: str, src: str):
160186
def updater(self, obj: dict, action: types.ProductUpdateAction):
161187
value = getattr(action, src)
162-
target_obj = _get_target_obj(obj, action)
188+
target_obj = _get_target_obj(obj, getattr(action, "staged", False))
163189

164190
if target_obj[dst] != value:
165191
new = copy.deepcopy(obj)
@@ -175,16 +201,9 @@ def updater(self, obj: dict, action: types.ProductSetAttributeAction):
175201
staged = getattr(action, "staged", False)
176202
new = copy.deepcopy(obj)
177203

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:
188207
for attr in variant["attributes"]:
189208
if attr["name"] == action.name:
190209
attr["value"] = action.value
@@ -195,7 +214,6 @@ def updater(self, obj: dict, action: types.ProductSetAttributeAction):
195214
variant["attributes"].append(
196215
attr_schema.dump(types.Attribute(name=action.name, value=action.value))
197216
)
198-
break
199217

200218
return new
201219

@@ -217,7 +235,7 @@ def updater(self, obj: dict, action: types.ProductAddVariantAction):
217235
schema = schemas.ProductVariantSchema()
218236

219237
new = copy.deepcopy(obj)
220-
target_obj = _get_target_obj(new, action)
238+
target_obj = _get_target_obj(new, staged=getattr(action, "staged", True))
221239
if not target_obj["variants"]:
222240
target_obj["variants"] = []
223241
target_obj["variants"].append(schema.dump(variant))
@@ -243,7 +261,7 @@ def updater(self, obj: dict, action: types.ProductPublishAction):
243261
def _set_product_prices():
244262
def updater(self, obj: dict, action: types.ProductSetPricesAction):
245263
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))
247265
prices = []
248266
for price_draft in action.prices:
249267
price = types.Price(
@@ -275,6 +293,12 @@ def updater(self, obj: dict, action: types.ProductSetPricesAction):
275293
return updater
276294

277295

296+
class UploadImageQuerySchema(Schema):
297+
staged = schema_fields.Bool()
298+
filename = schema_fields.Field()
299+
sku = schema_fields.Field()
300+
301+
278302
class ProductsBackend(ServiceBackend):
279303
service_path = "products"
280304
model_class = ProductsModel
@@ -292,6 +316,7 @@ def urls(self):
292316
("^(?P<id>[^/]+)$", "POST", self.update_by_id),
293317
("^(?P<id>[^/]+)$", "DELETE", self.delete_by_id),
294318
("^key=(?P<key>[^/]+)$", "DELETE", self.delete_by_key),
319+
("^(?P<id>[^/]+)\/images$", "POST", self.upload_image),
295320
]
296321

297322
# Fixme: use decorator for this
@@ -302,3 +327,26 @@ def urls(self):
302327
"setPrices": _set_product_prices(),
303328
"publish": _publish_product_action(),
304329
}
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

Comments
 (0)