Skip to content

Commit f68c2cc

Browse files
author
Robert Segal
committed
Added create and update with icon mixin and updated product
1 parent 5a75c11 commit f68c2cc

File tree

9 files changed

+594
-35
lines changed

9 files changed

+594
-35
lines changed

mpt_api_client/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
APPLICATION_JSON = "application/json"

mpt_api_client/http/mixins.py

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Self
44
from urllib.parse import urljoin
55

6+
from mpt_api_client.constants import APPLICATION_JSON
67
from mpt_api_client.http.query_state import QueryState
78
from mpt_api_client.http.types import FileTypes, Response
89
from mpt_api_client.models import Collection, FileModel, ResourceData
@@ -84,7 +85,7 @@ def create(
8485
files[data_key] = (
8586
None,
8687
_json_to_file_payload(resource_data),
87-
"application/json",
88+
APPLICATION_JSON,
8889
)
8990
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
9091

@@ -105,6 +106,77 @@ def download(self, resource_id: str) -> FileModel:
105106
return FileModel(response)
106107

107108

109+
class CreateWithIconMixin[Model]:
110+
"""Create resource with icon mixin."""
111+
112+
def create(
113+
self,
114+
resource_data: ResourceData,
115+
icon: FileTypes,
116+
data_key: str,
117+
icon_key: str,
118+
) -> Model:
119+
"""Create resource with icon.
120+
121+
Args:
122+
resource_data: Resource data.
123+
data_key: Key for the resource data.
124+
icon: Icon image in jpg, png, GIF, etc.
125+
icon_key: Key for the icon.
126+
127+
Returns:
128+
Created resource.
129+
"""
130+
files: dict[str, FileTypes] = {}
131+
files[data_key] = (
132+
None,
133+
json.dumps(resource_data),
134+
APPLICATION_JSON,
135+
)
136+
files[icon_key] = icon
137+
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
138+
139+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
140+
141+
142+
class UpdateWithIconMixin[Model]:
143+
"""Update resource with icon mixin."""
144+
145+
def update(
146+
self,
147+
resource_id: str,
148+
resource_data: ResourceData,
149+
icon: FileTypes,
150+
data_key: str,
151+
icon_key: str,
152+
) -> Model:
153+
"""Update resource with icon.
154+
155+
Args:
156+
resource_id: Resource ID.
157+
resource_data: Resource data.
158+
data_key: Key for the resource data.
159+
icon: Icon image in jpg, png, GIF, etc.
160+
icon_key: Key for the icon.
161+
162+
Returns:
163+
Updated resource.
164+
"""
165+
files: dict[str, FileTypes] = {}
166+
files[data_key] = (
167+
None,
168+
json.dumps(resource_data),
169+
APPLICATION_JSON,
170+
)
171+
files[icon_key] = icon
172+
173+
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
174+
175+
response = self.http_client.request("put", url, files=files) # type: ignore[attr-defined]
176+
177+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
178+
179+
108180
class AsyncCreateMixin[Model]:
109181
"""Create resource mixin."""
110182

@@ -174,7 +246,7 @@ async def create(
174246
files[data_key] = (
175247
None,
176248
_json_to_file_payload(resource_data),
177-
"application/json",
249+
APPLICATION_JSON,
178250
)
179251

180252
response = await self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
@@ -196,6 +268,77 @@ async def download(self, resource_id: str) -> FileModel:
196268
return FileModel(response)
197269

198270

271+
class AsyncCreateWithIconMixin[Model]:
272+
"""Create resource with icon mixin."""
273+
274+
async def create(
275+
self,
276+
resource_data: ResourceData,
277+
icon: FileTypes,
278+
data_key: str,
279+
icon_key: str,
280+
) -> Model:
281+
"""Create resource with icon.
282+
283+
Args:
284+
resource_data: Resource data.
285+
data_key: Key for the resource data.
286+
icon: Icon image in jpg, png, GIF, etc.
287+
icon_key: Key for the icon.
288+
289+
Returns:
290+
Created resource.
291+
"""
292+
files: dict[str, FileTypes] = {}
293+
files[data_key] = (
294+
None,
295+
json.dumps(resource_data),
296+
APPLICATION_JSON,
297+
)
298+
files[icon_key] = icon
299+
response = await self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
300+
301+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
302+
303+
304+
class AsyncUpdateWithIconMixin[Model]:
305+
"""Update resource with icon mixin."""
306+
307+
async def update(
308+
self,
309+
resource_id: str,
310+
resource_data: ResourceData,
311+
icon: FileTypes,
312+
data_key: str,
313+
icon_key: str,
314+
) -> Model:
315+
"""Update resource with icon.
316+
317+
Args:
318+
resource_id: Resource ID.
319+
resource_data: Resource data.
320+
data_key: Key for the resource data.
321+
icon: Icon image in jpg, png, GIF, etc.
322+
icon_key: Key for the icon.
323+
324+
Returns:
325+
Updated resource.
326+
"""
327+
files: dict[str, FileTypes] = {}
328+
files[data_key] = (
329+
None,
330+
json.dumps(resource_data),
331+
APPLICATION_JSON,
332+
)
333+
files[icon_key] = icon
334+
335+
url = urljoin(f"{self.path}/", resource_id) # type: ignore[attr-defined]
336+
337+
response = await self.http_client.request("put", url, files=files) # type: ignore[attr-defined]
338+
339+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
340+
341+
199342
class GetMixin[Model]:
200343
"""Get resource mixin."""
201344

mpt_api_client/resources/catalog/products.py

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import json
1+
from typing import override
22

33
from mpt_api_client.http import AsyncService, Service
44
from mpt_api_client.http.mixins import (
55
AsyncCollectionMixin,
6-
AsyncModifiableResourceMixin,
6+
AsyncCreateWithIconMixin,
7+
AsyncDeleteMixin,
8+
AsyncGetMixin,
9+
AsyncUpdateWithIconMixin,
710
CollectionMixin,
8-
ModifiableResourceMixin,
11+
CreateWithIconMixin,
12+
DeleteMixin,
13+
GetMixin,
14+
UpdateWithIconMixin,
915
)
1016
from mpt_api_client.http.types import FileTypes
1117
from mpt_api_client.models import Model, ResourceData
@@ -56,38 +62,71 @@ class ProductsServiceConfig:
5662

5763

5864
class ProductsService(
65+
CreateWithIconMixin[Product],
66+
UpdateWithIconMixin[Product],
5967
PublishableMixin[Product],
60-
ModifiableResourceMixin[Product],
68+
GetMixin[Product],
69+
DeleteMixin,
6170
CollectionMixin[Product],
6271
Service[Product],
6372
ProductsServiceConfig,
6473
):
6574
"""Products service."""
6675

76+
@override
6777
def create(
6878
self,
6979
resource_data: ResourceData,
7080
icon: FileTypes,
81+
data_key: str = "product",
82+
icon_key: str = "icon",
7183
) -> Product:
7284
"""Create product with icon.
7385
7486
Args:
7587
resource_data: Product data.
7688
icon: Icon image in jpg, png, GIF, etc.
89+
data_key: Key for the product data.
90+
icon_key: Key for the icon.
7791
7892
Returns:
7993
Created resource.
8094
"""
81-
files: dict[str, FileTypes] = {}
82-
files["product"] = (
83-
None,
84-
json.dumps(resource_data),
85-
"application/json",
95+
return super().create(
96+
resource_data=resource_data,
97+
icon=icon,
98+
data_key=data_key,
99+
icon_key=icon_key,
86100
)
87-
files["icon"] = icon
88-
response = self.http_client.request("post", self.path, files=files)
89101

90-
return self._model_class.from_response(response)
102+
@override
103+
def update(
104+
self,
105+
resource_id: str,
106+
resource_data: ResourceData,
107+
icon: FileTypes,
108+
data_key: str = "product",
109+
icon_key: str = "icon",
110+
) -> Product:
111+
"""Update product with icon.
112+
113+
Args:
114+
resource_id: Product ID.
115+
resource_data: Product data.
116+
icon: Icon image in jpg, png, GIF, etc.
117+
data_key: Key for the product data.
118+
icon_key: Key for the icon.
119+
120+
Returns:
121+
Updated resource.
122+
"""
123+
return super().update(
124+
resource_id=resource_id,
125+
resource_data=resource_data,
126+
icon=icon,
127+
data_key=data_key,
128+
icon_key=icon_key,
129+
)
91130

92131
def item_groups(self, product_id: str) -> ItemGroupsService:
93132
"""Return item_groups service."""
@@ -135,37 +174,71 @@ def update_settings(self, product_id: str, settings: ResourceData) -> Product:
135174

136175

137176
class AsyncProductsService(
177+
AsyncCreateWithIconMixin[Product],
178+
AsyncUpdateWithIconMixin[Product],
138179
AsyncPublishableMixin[Product],
139-
AsyncModifiableResourceMixin[Product],
180+
AsyncGetMixin[Product],
181+
AsyncDeleteMixin,
140182
AsyncCollectionMixin[Product],
141183
AsyncService[Product],
142184
ProductsServiceConfig,
143185
):
144186
"""Products service."""
145187

188+
@override
146189
async def create(
147190
self,
148191
resource_data: ResourceData,
149192
icon: FileTypes,
193+
data_key: str = "product",
194+
icon_key: str = "icon",
150195
) -> Product:
151196
"""Create product with icon.
152197
153198
Args:
154199
resource_data: Product data.
155200
icon: Icon image in jpg, png, GIF, etc.
201+
data_key: Key for the product data.
202+
icon_key: Key for the icon.
156203
157204
Returns:
158205
Created resource.
159206
"""
160-
files: dict[str, FileTypes] = {}
161-
files["product"] = (
162-
None,
163-
json.dumps(resource_data),
164-
"application/json",
165-
)
166-
files["icon"] = icon
167-
response = await self.http_client.request("post", self.path, files=files)
168-
return self._model_class.from_response(response)
207+
return await super().create(
208+
resource_data=resource_data,
209+
data_key=data_key,
210+
icon=icon,
211+
icon_key=icon_key,
212+
)
213+
214+
@override
215+
async def update(
216+
self,
217+
resource_id: str,
218+
resource_data: ResourceData,
219+
icon: FileTypes,
220+
data_key: str = "product",
221+
icon_key: str = "icon",
222+
) -> Product:
223+
"""Update product with icon.
224+
225+
Args:
226+
resource_id: Product ID.
227+
resource_data: Product data.
228+
icon: Icon image in jpg, png, GIF, etc.
229+
data_key: Key for the product data.
230+
icon_key: Key for the icon.
231+
232+
Returns:
233+
Updated resource.
234+
"""
235+
return await super().update(
236+
resource_id=resource_id,
237+
resource_data=resource_data,
238+
data_key=data_key,
239+
icon=icon,
240+
icon_key=icon_key,
241+
)
169242

170243
def item_groups(self, product_id: str) -> AsyncItemGroupsService:
171244
"""Return item_groups service."""

seed/catalog/product.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ async def init_product(
4848
logger.debug("Creating product ...")
4949
with pathlib.Path.open(icon, "rb") as icon_file:
5050
product = await mpt_vendor.catalog.products.create(
51-
{"name": "E2E Seeded", "website": "https://www.example.com"}, icon=icon_file
51+
{"name": "E2E Seeded", "website": "https://www.example.com"},
52+
data_key="product",
53+
icon=icon_file,
54+
icon_key="icon",
5255
)
5356
context.set_resource(namespace, product)
5457
context[f"{namespace}.id"] = product.id

0 commit comments

Comments
 (0)