Skip to content

Commit 4505971

Browse files
authored
Merge pull request grll#3 from AdamQuadmon/product-image
add create product image
2 parents 60a3292 + cf5aa73 commit 4505971

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ As of now, `saleor-gql-loader` allows to create the following entities:
1414
- [x] category
1515
- [x] product
1616
- [x] product_variant
17+
- [x] product_image
1718

1819
and update the following entities:
1920

@@ -32,7 +33,7 @@ team/community._
3233
using Pypi:
3334

3435
```bash
35-
pip install saleor-gql-loader
36+
pip install saleor-gql-loader requests-toolbelt Django
3637
```
3738

3839
Or cloning the repo:

saleor_gql_loader/data_loader.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
project for easier testing.
1111
1212
"""
13-
from .utils import graphql_request, override_dict, handle_errors
13+
from .utils import graphql_request, graphql_multipart_request, override_dict, handle_errors, get_payload
1414

1515

1616
class ETLDataLoader:
@@ -677,3 +677,33 @@ def create_product_variant(self, product_id, **kwargs):
677677
handle_errors(errors)
678678

679679
return response["data"]["productVariantCreate"]["productVariant"]["id"]
680+
681+
def create_product_image(self, product_id, file_path):
682+
"""create a product image.
683+
684+
Parameters
685+
----------
686+
product_id : str
687+
id for which the product image will be created.
688+
file_path : str
689+
path to the image to upload.
690+
691+
Returns
692+
-------
693+
id : str
694+
the id of the product image created.
695+
696+
Raises
697+
------
698+
Exception
699+
when productErrors is not an empty list.
700+
"""
701+
body = get_payload(product_id, file_path)
702+
703+
response = graphql_multipart_request(
704+
body, self.headers, self.endpoint_url)
705+
706+
errors = response["data"]["productImageCreate"]["productErrors"]
707+
handle_errors(errors)
708+
709+
return response["data"]["productImageCreate"]["image"]["id"]

saleor_gql_loader/utils.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"""
88
import requests
99
import json
10+
from pathlib import Path
11+
from requests_toolbelt import MultipartEncoder
12+
from django.core.serializers.json import DjangoJSONEncoder
1013

1114
GQL_DEFAULT_ENDPOINT = "http://localhost:8000/graphql/"
1215

@@ -55,6 +58,45 @@ def graphql_request(query, variables={}, headers={},
5558
return parsed_response
5659

5760

61+
def graphql_multipart_request(body, headers, endpoint=GQL_DEFAULT_ENDPOINT):
62+
"""Execute a multipart graphQL query with `body` provided on the `endpoint`.
63+
64+
Parameters
65+
----------
66+
body : str
67+
payloads of graphQL query.
68+
headers : dict, optional
69+
headers added to the request (important for authentication).
70+
endpoint : str, optional
71+
the graphQL endpoint url that will be queried, default is
72+
`GQL_DEFAULT_ENDPOINT`.
73+
74+
Returns
75+
-------
76+
response : dict
77+
a dictionary corresponding to the parsed JSON graphQL response.
78+
79+
Raises
80+
------
81+
Exception
82+
when `response.status_code` is not 200.
83+
"""
84+
bodyEncoder = MultipartEncoder(body)
85+
base_headers = {
86+
"Content-Type": bodyEncoder.content_type,
87+
}
88+
override_dict(base_headers, headers)
89+
90+
response = requests.post(endpoint, data=bodyEncoder, headers=headers, timeout=90)
91+
92+
parsed_response = json.loads(response.text)
93+
if response.status_code != 200:
94+
raise Exception("{message}\n extensions: {extensions}".format(
95+
**parsed_response["errors"][0]))
96+
else:
97+
return parsed_response
98+
99+
58100
def override_dict(a, overrides):
59101
"""Override a dict with another one **only first non nested keys**.
60102
@@ -99,3 +141,57 @@ def handle_errors(errors):
99141
txt_list = [
100142
"{field} : {message}".format(**error) for error in errors]
101143
raise Exception("\n".join(txt_list))
144+
145+
def get_operations(product_id):
146+
"""Get ProductImageCreate operations
147+
148+
Parameters
149+
----------
150+
product_id : str
151+
id for which the product image will be created.
152+
153+
Returns
154+
-------
155+
query : str
156+
variables: dict
157+
"""
158+
query = """
159+
mutation ProductImageCreate($product: ID!, $image: Upload!, $alt: String) {
160+
productImageCreate(input: {alt: $alt, image: $image, product: $product}) {
161+
image{
162+
id
163+
}
164+
productErrors {
165+
field
166+
message
167+
}
168+
}
169+
}
170+
"""
171+
variables = {
172+
"product": product_id,
173+
"image": "0",
174+
"alt": ''
175+
}
176+
return {"query": query, "variables": variables}
177+
178+
def get_payload(product_id, file_path):
179+
"""Get ProductImageCreate operations
180+
181+
Parameters
182+
----------
183+
product_id : str
184+
id for which the product image will be created.
185+
186+
Returns
187+
-------
188+
query : str
189+
variables: dict
190+
"""
191+
return {
192+
"operations": json.dumps(
193+
get_operations(product_id), cls=DjangoJSONEncoder
194+
),
195+
"map": json.dumps({'0': ["variables.image"]}, cls=DjangoJSONEncoder),
196+
"0": (Path(file_path).name, open(file_path, 'rb'), 'image/png')
197+
}

0 commit comments

Comments
 (0)