karrio-server-graph 2025.5rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. karrio/server/graph/__init__.py +1 -0
  2. karrio/server/graph/admin.py +3 -0
  3. karrio/server/graph/apps.py +5 -0
  4. karrio/server/graph/forms.py +59 -0
  5. karrio/server/graph/management/__init__.py +0 -0
  6. karrio/server/graph/management/commands/__init__.py +0 -0
  7. karrio/server/graph/management/commands/export_schema.py +9 -0
  8. karrio/server/graph/migrations/0001_initial.py +37 -0
  9. karrio/server/graph/migrations/0002_auto_20210512_1353.py +22 -0
  10. karrio/server/graph/migrations/__init__.py +0 -0
  11. karrio/server/graph/models.py +44 -0
  12. karrio/server/graph/schema.py +46 -0
  13. karrio/server/graph/schemas/__init__.py +2 -0
  14. karrio/server/graph/schemas/base/__init__.py +367 -0
  15. karrio/server/graph/schemas/base/inputs.py +582 -0
  16. karrio/server/graph/schemas/base/mutations.py +871 -0
  17. karrio/server/graph/schemas/base/types.py +1365 -0
  18. karrio/server/graph/serializers.py +388 -0
  19. karrio/server/graph/templates/graphql/graphiql.html +142 -0
  20. karrio/server/graph/templates/karrio/email_change_email.html +13 -0
  21. karrio/server/graph/templates/karrio/email_change_email.txt +13 -0
  22. karrio/server/graph/templates/karrio/password_reset_email.html +14 -0
  23. karrio/server/graph/tests/__init__.py +9 -0
  24. karrio/server/graph/tests/base.py +124 -0
  25. karrio/server/graph/tests/test_carrier_connections.py +219 -0
  26. karrio/server/graph/tests/test_metafield.py +404 -0
  27. karrio/server/graph/tests/test_rate_sheets.py +348 -0
  28. karrio/server/graph/tests/test_templates.py +677 -0
  29. karrio/server/graph/tests/test_user_info.py +71 -0
  30. karrio/server/graph/urls.py +10 -0
  31. karrio/server/graph/utils.py +304 -0
  32. karrio/server/graph/views.py +93 -0
  33. karrio/server/settings/graph.py +7 -0
  34. karrio_server_graph-2025.5rc1.dist-info/METADATA +29 -0
  35. karrio_server_graph-2025.5rc1.dist-info/RECORD +37 -0
  36. karrio_server_graph-2025.5rc1.dist-info/WHEEL +5 -0
  37. karrio_server_graph-2025.5rc1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,404 @@
1
+ import json
2
+ from datetime import datetime, date
3
+ from django.test import TestCase
4
+ from django.contrib.auth import get_user_model
5
+ from karrio.server.core.models import Metafield, MetafieldType
6
+ from karrio.server.graph.tests import GraphTestCase
7
+
8
+ User = get_user_model()
9
+
10
+
11
+ class MetafieldModelTest(TestCase):
12
+ def setUp(self):
13
+ self.user = User.objects.create_user(
14
+ email="test@example.com", password="test123"
15
+ )
16
+
17
+ def test_create_text_metafield(self):
18
+ """Test creating a text metafield"""
19
+ metafield = Metafield.objects.create(
20
+ key="test_text",
21
+ value="Hello World",
22
+ type=MetafieldType.text,
23
+ created_by=self.user
24
+ )
25
+ self.assertEqual(metafield.key, "test_text")
26
+ self.assertEqual(metafield.value, "Hello World")
27
+ self.assertEqual(metafield.get_parsed_value(), "Hello World")
28
+
29
+ def test_create_number_metafield(self):
30
+ """Test creating a number metafield"""
31
+ metafield = Metafield.objects.create(
32
+ key="test_number",
33
+ value=42,
34
+ type=MetafieldType.number,
35
+ created_by=self.user
36
+ )
37
+ self.assertEqual(metafield.key, "test_number")
38
+ self.assertEqual(metafield.value, 42)
39
+ self.assertEqual(metafield.get_parsed_value(), 42)
40
+
41
+ def test_create_boolean_metafield(self):
42
+ """Test creating a boolean metafield"""
43
+ metafield = Metafield.objects.create(
44
+ key="test_bool",
45
+ value=True,
46
+ type=MetafieldType.boolean,
47
+ created_by=self.user
48
+ )
49
+ self.assertEqual(metafield.key, "test_bool")
50
+ self.assertEqual(metafield.value, True)
51
+ self.assertEqual(metafield.get_parsed_value(), True)
52
+
53
+ def test_create_json_metafield(self):
54
+ """Test creating a JSON metafield"""
55
+ json_data = {"name": "John", "age": 30}
56
+ metafield = Metafield.objects.create(
57
+ key="test_json",
58
+ value=json_data,
59
+ type=MetafieldType.json,
60
+ created_by=self.user
61
+ )
62
+ self.assertEqual(metafield.key, "test_json")
63
+ self.assertEqual(metafield.get_parsed_value(), json_data)
64
+
65
+ def test_create_date_metafield(self):
66
+ """Test creating a date metafield"""
67
+ date_string = "2023-12-25"
68
+ metafield = Metafield.objects.create(
69
+ key="test_date",
70
+ value=date_string,
71
+ type=MetafieldType.date,
72
+ created_by=self.user
73
+ )
74
+ self.assertEqual(metafield.key, "test_date")
75
+ self.assertEqual(metafield.value, date_string)
76
+ self.assertEqual(metafield.get_parsed_value(), date(2023, 12, 25))
77
+
78
+ def test_create_datetime_metafield(self):
79
+ """Test creating a datetime metafield"""
80
+ datetime_string = "2023-12-25T10:30:00Z"
81
+ metafield = Metafield.objects.create(
82
+ key="test_datetime",
83
+ value=datetime_string,
84
+ type=MetafieldType.date_time,
85
+ created_by=self.user
86
+ )
87
+ self.assertEqual(metafield.key, "test_datetime")
88
+ self.assertEqual(metafield.value, datetime_string)
89
+ # The parsed value should be a datetime object
90
+ parsed_value = metafield.get_parsed_value()
91
+ self.assertIsInstance(parsed_value, datetime)
92
+
93
+ def test_create_password_metafield(self):
94
+ """Test creating a password metafield"""
95
+ metafield = Metafield.objects.create(
96
+ key="test_password",
97
+ value="secret123",
98
+ type=MetafieldType.password,
99
+ created_by=self.user
100
+ )
101
+ self.assertEqual(metafield.key, "test_password")
102
+ self.assertEqual(metafield.get_parsed_value(), "secret123")
103
+
104
+ def test_required_metafield(self):
105
+ """Test creating a required metafield"""
106
+ metafield = Metafield.objects.create(
107
+ key="required_field",
108
+ value="required value",
109
+ type=MetafieldType.text,
110
+ is_required=True,
111
+ created_by=self.user
112
+ )
113
+ self.assertTrue(metafield.is_required)
114
+
115
+
116
+ class MetafieldGraphQLTest(GraphTestCase):
117
+ def setUp(self):
118
+ super().setUp()
119
+
120
+ def test_create_text_metafield_graphql(self):
121
+ """Test creating a text metafield via GraphQL"""
122
+ query = '''
123
+ mutation CreateMetafield($input: CreateMetafieldInput!) {
124
+ create_metafield(input: $input) {
125
+ metafield {
126
+ id
127
+ key
128
+ value
129
+ type
130
+ parsed_value
131
+ is_required
132
+ }
133
+ errors {
134
+ field
135
+ messages
136
+ }
137
+ }
138
+ }
139
+ '''
140
+
141
+ variables = {
142
+ "input": {
143
+ "key": "test_text",
144
+ "value": "Hello World",
145
+ "type": "text",
146
+ "is_required": False
147
+ }
148
+ }
149
+
150
+ response = self.query(query, variables=variables)
151
+ self.assertResponseNoErrors(response)
152
+
153
+ metafield_data = response.data["data"]["create_metafield"]["metafield"]
154
+ expected_data = {
155
+ "create_metafield": {
156
+ "metafield": {
157
+ "id": metafield_data["id"], # Dynamic ID
158
+ "key": "test_text",
159
+ "value": "Hello World",
160
+ "type": "text",
161
+ "parsed_value": "Hello World",
162
+ "is_required": False
163
+ },
164
+ "errors": None
165
+ }
166
+ }
167
+ self.assertDictEqual(response.data["data"], expected_data)
168
+
169
+ def test_create_json_metafield_graphql(self):
170
+ """Test creating a JSON metafield via GraphQL"""
171
+ query = '''
172
+ mutation CreateMetafield($input: CreateMetafieldInput!) {
173
+ create_metafield(input: $input) {
174
+ metafield {
175
+ id
176
+ key
177
+ value
178
+ type
179
+ parsed_value
180
+ is_required
181
+ }
182
+ errors {
183
+ field
184
+ messages
185
+ }
186
+ }
187
+ }
188
+ '''
189
+
190
+ json_data = {"name": "John", "age": 30, "active": True}
191
+ variables = {
192
+ "input": {
193
+ "key": "test_json",
194
+ "value": json_data,
195
+ "type": "json",
196
+ "is_required": False
197
+ }
198
+ }
199
+
200
+ response = self.query(query, variables=variables)
201
+ self.assertResponseNoErrors(response)
202
+
203
+ metafield_data = response.data["data"]["create_metafield"]["metafield"]
204
+ expected_data = {
205
+ "create_metafield": {
206
+ "metafield": {
207
+ "id": metafield_data["id"], # Dynamic ID
208
+ "key": "test_json",
209
+ "value": json_data,
210
+ "type": "json",
211
+ "parsed_value": json_data,
212
+ "is_required": False
213
+ },
214
+ "errors": None
215
+ }
216
+ }
217
+ self.assertDictEqual(response.data["data"], expected_data)
218
+
219
+ def test_query_metafields_graphql(self):
220
+ """Test querying metafields via GraphQL"""
221
+ # Create some test metafields
222
+ Metafield.objects.create(
223
+ key="test_text_0",
224
+ value="Hello",
225
+ type=MetafieldType.text,
226
+ created_by=self.user
227
+ )
228
+ Metafield.objects.create(
229
+ key="test_number_0",
230
+ value=42,
231
+ type=MetafieldType.number,
232
+ created_by=self.user
233
+ )
234
+
235
+ query = '''
236
+ query GetMetafields($filter: MetafieldFilter) {
237
+ metafields(filter: $filter) {
238
+ edges {
239
+ node {
240
+ id
241
+ key
242
+ value
243
+ type
244
+ parsed_value
245
+ is_required
246
+ }
247
+ }
248
+ page_info {
249
+ has_next_page
250
+ has_previous_page
251
+ }
252
+ }
253
+ }
254
+ '''
255
+
256
+ response = self.query(query)
257
+ self.assertResponseNoErrors(response)
258
+
259
+ # Should return both metafields
260
+ edges = response.data["data"]["metafields"]["edges"]
261
+ self.assertEqual(len(edges), 2)
262
+
263
+ def test_update_metafield_graphql(self):
264
+ """Test updating a metafield via GraphQL"""
265
+ # Create a metafield first
266
+ metafield = Metafield.objects.create(
267
+ key="test_update",
268
+ value="original",
269
+ type=MetafieldType.text,
270
+ created_by=self.user
271
+ )
272
+
273
+ query = '''
274
+ mutation UpdateMetafield($input: UpdateMetafieldInput!) {
275
+ update_metafield(input: $input) {
276
+ metafield {
277
+ id
278
+ key
279
+ value
280
+ type
281
+ parsed_value
282
+ is_required
283
+ }
284
+ errors {
285
+ field
286
+ messages
287
+ }
288
+ }
289
+ }
290
+ '''
291
+
292
+ variables = {
293
+ "input": {
294
+ "id": metafield.id,
295
+ "key": "test_updated",
296
+ "value": "updated value",
297
+ "type": "text",
298
+ "is_required": True
299
+ }
300
+ }
301
+
302
+ response = self.query(query, variables=variables)
303
+ self.assertResponseNoErrors(response)
304
+
305
+ expected_data = {
306
+ "update_metafield": {
307
+ "metafield": {
308
+ "id": metafield.id,
309
+ "key": "test_updated",
310
+ "value": "updated value",
311
+ "type": "text",
312
+ "parsed_value": "updated value",
313
+ "is_required": True
314
+ },
315
+ "errors": None
316
+ }
317
+ }
318
+ self.assertDictEqual(response.data["data"], expected_data)
319
+
320
+ def test_delete_metafield_graphql(self):
321
+ """Test deleting a metafield via GraphQL"""
322
+ # Create a metafield first
323
+ metafield = Metafield.objects.create(
324
+ key="test_delete",
325
+ value="to be deleted",
326
+ type=MetafieldType.text,
327
+ created_by=self.user
328
+ )
329
+
330
+ query = '''
331
+ mutation DeleteMetafield($input: DeleteMutationInput!) {
332
+ delete_metafield(input: $input) {
333
+ id
334
+ errors {
335
+ field
336
+ messages
337
+ }
338
+ }
339
+ }
340
+ '''
341
+
342
+ variables = {
343
+ "input": {
344
+ "id": metafield.id
345
+ }
346
+ }
347
+
348
+ response = self.query(query, variables=variables)
349
+ self.assertResponseNoErrors(response)
350
+
351
+ expected_data = {
352
+ "delete_metafield": {
353
+ "id": metafield.id,
354
+ "errors": None
355
+ }
356
+ }
357
+ self.assertDictEqual(response.data["data"], expected_data)
358
+
359
+ # Verify the metafield was actually deleted
360
+ self.assertFalse(Metafield.objects.filter(id=metafield.id).exists())
361
+
362
+ def test_metafield_type_validation(self):
363
+ """Test that metafield type validation works"""
364
+ query = '''
365
+ mutation CreateMetafield($input: CreateMetafieldInput!) {
366
+ create_metafield(input: $input) {
367
+ metafield {
368
+ id
369
+ key
370
+ value
371
+ type
372
+ parsed_value
373
+ is_required
374
+ }
375
+ errors {
376
+ field
377
+ messages
378
+ }
379
+ }
380
+ }
381
+ '''
382
+
383
+ # Test with invalid JSON
384
+ variables = {
385
+ "input": {
386
+ "key": "invalid_json",
387
+ "value": "not valid json",
388
+ "type": "json",
389
+ "is_required": False
390
+ }
391
+ }
392
+
393
+ response = self.query(query, variables=variables)
394
+
395
+ # Check if we got a response (might have errors or succeed depending on validation)
396
+ self.assertEqual(response.status_code, 200)
397
+
398
+ # If the mutation succeeded, check the data
399
+ if response.data["data"]["create_metafield"]["metafield"]:
400
+ metafield_data = response.data["data"]["create_metafield"]["metafield"]
401
+ self.assertIsNotNone(metafield_data["id"])
402
+ # If it failed, there should be errors
403
+ elif response.data["data"]["create_metafield"]["errors"]:
404
+ self.assertIsNotNone(response.data["data"]["create_metafield"]["errors"])