karrio-server-core 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.

Potentially problematic release.


This version of karrio-server-core might be problematic. Click here for more details.

Files changed (241) hide show
  1. karrio/server/conf.py +54 -0
  2. karrio/server/core/__init__.py +3 -0
  3. karrio/server/core/admin.py +1 -0
  4. karrio/server/core/apps.py +10 -0
  5. karrio/server/core/authentication.py +313 -0
  6. karrio/server/core/context_processors.py +12 -0
  7. karrio/server/core/datatypes.py +369 -0
  8. karrio/server/core/dataunits.py +156 -0
  9. karrio/server/core/exceptions.py +200 -0
  10. karrio/server/core/fields.py +12 -0
  11. karrio/server/core/filters.py +823 -0
  12. karrio/server/core/gateway.py +720 -0
  13. karrio/server/core/management/commands/cli.py +19 -0
  14. karrio/server/core/management/commands/create_oauth_client.py +41 -0
  15. karrio/server/core/middleware.py +95 -0
  16. karrio/server/core/migrations/0001_initial.py +28 -0
  17. karrio/server/core/migrations/0002_apilogindex.py +69 -0
  18. karrio/server/core/migrations/0003_apilogindex_test_mode.py +62 -0
  19. karrio/server/core/migrations/0004_metafield.py +74 -0
  20. karrio/server/core/migrations/0005_alter_metafield_type_alter_metafield_value.py +23 -0
  21. karrio/server/core/migrations/__init__.py +0 -0
  22. karrio/server/core/models/__init__.py +48 -0
  23. karrio/server/core/models/base.py +70 -0
  24. karrio/server/core/models/entity.py +22 -0
  25. karrio/server/core/models/metafield.py +144 -0
  26. karrio/server/core/models/third_party.py +21 -0
  27. karrio/server/core/oauth_validators.py +171 -0
  28. karrio/server/core/permissions.py +37 -0
  29. karrio/server/core/renderers.py +11 -0
  30. karrio/server/core/router.py +3 -0
  31. karrio/server/core/serializers.py +1898 -0
  32. karrio/server/core/signals.py +57 -0
  33. karrio/server/core/tests.py +98 -0
  34. karrio/server/core/urls.py +12 -0
  35. karrio/server/core/utils.py +479 -0
  36. karrio/server/core/validators.py +416 -0
  37. karrio/server/core/views/__init__.py +2 -0
  38. karrio/server/core/views/api.py +133 -0
  39. karrio/server/core/views/metadata.py +44 -0
  40. karrio/server/core/views/oauth.py +74 -0
  41. karrio/server/core/views/references.py +82 -0
  42. karrio/server/core/views/schema.py +310 -0
  43. karrio/server/filters/__init__.py +2 -0
  44. karrio/server/filters/abstract.py +26 -0
  45. karrio/server/iam/__init__.py +0 -0
  46. karrio/server/iam/admin.py +3 -0
  47. karrio/server/iam/apps.py +21 -0
  48. karrio/server/iam/migrations/0001_initial.py +33 -0
  49. karrio/server/iam/migrations/__init__.py +0 -0
  50. karrio/server/iam/models.py +48 -0
  51. karrio/server/iam/permissions.py +134 -0
  52. karrio/server/iam/serializers.py +39 -0
  53. karrio/server/iam/signals.py +20 -0
  54. karrio/server/iam/tests.py +3 -0
  55. karrio/server/iam/views.py +3 -0
  56. karrio/server/openapi.py +75 -0
  57. karrio/server/providers/__init__.py +1 -0
  58. karrio/server/providers/admin.py +364 -0
  59. karrio/server/providers/apps.py +10 -0
  60. karrio/server/providers/extension/__init__.py +1 -0
  61. karrio/server/providers/extension/models/__init__.py +1 -0
  62. karrio/server/providers/extension/models/allied_express.py +22 -0
  63. karrio/server/providers/extension/models/allied_express_local.py +22 -0
  64. karrio/server/providers/extension/models/amazon_shipping.py +27 -0
  65. karrio/server/providers/extension/models/aramex.py +25 -0
  66. karrio/server/providers/extension/models/asendia_us.py +21 -0
  67. karrio/server/providers/extension/models/australiapost.py +20 -0
  68. karrio/server/providers/extension/models/boxknight.py +19 -0
  69. karrio/server/providers/extension/models/bpost.py +21 -0
  70. karrio/server/providers/extension/models/canadapost.py +21 -0
  71. karrio/server/providers/extension/models/canpar.py +19 -0
  72. karrio/server/providers/extension/models/chronopost.py +22 -0
  73. karrio/server/providers/extension/models/colissimo.py +22 -0
  74. karrio/server/providers/extension/models/dhl_express.py +23 -0
  75. karrio/server/providers/extension/models/dhl_parcel_de.py +25 -0
  76. karrio/server/providers/extension/models/dhl_poland.py +22 -0
  77. karrio/server/providers/extension/models/dhl_universal.py +19 -0
  78. karrio/server/providers/extension/models/dicom.py +20 -0
  79. karrio/server/providers/extension/models/dpd.py +37 -0
  80. karrio/server/providers/extension/models/dpdhl.py +26 -0
  81. karrio/server/providers/extension/models/easypost.py +20 -0
  82. karrio/server/providers/extension/models/eshipper.py +21 -0
  83. karrio/server/providers/extension/models/fedex.py +25 -0
  84. karrio/server/providers/extension/models/fedex_ws.py +24 -0
  85. karrio/server/providers/extension/models/freightcom.py +21 -0
  86. karrio/server/providers/extension/models/generic.py +35 -0
  87. karrio/server/providers/extension/models/geodis.py +22 -0
  88. karrio/server/providers/extension/models/hay_post.py +22 -0
  89. karrio/server/providers/extension/models/laposte.py +19 -0
  90. karrio/server/providers/extension/models/locate2u.py +22 -0
  91. karrio/server/providers/extension/models/nationex.py +22 -0
  92. karrio/server/providers/extension/models/purolator.py +21 -0
  93. karrio/server/providers/extension/models/roadie.py +18 -0
  94. karrio/server/providers/extension/models/royalmail.py +19 -0
  95. karrio/server/providers/extension/models/sendle.py +22 -0
  96. karrio/server/providers/extension/models/tge.py +63 -0
  97. karrio/server/providers/extension/models/tnt.py +23 -0
  98. karrio/server/providers/extension/models/ups.py +23 -0
  99. karrio/server/providers/extension/models/usps.py +23 -0
  100. karrio/server/providers/extension/models/usps_international.py +23 -0
  101. karrio/server/providers/extension/models/usps_wt.py +24 -0
  102. karrio/server/providers/extension/models/usps_wt_international.py +24 -0
  103. karrio/server/providers/extension/models/zoom2u.py +23 -0
  104. karrio/server/providers/migrations/0001_initial.py +140 -0
  105. karrio/server/providers/migrations/0002_carrier_active.py +18 -0
  106. karrio/server/providers/migrations/0003_auto_20201230_0820.py +24 -0
  107. karrio/server/providers/migrations/0004_auto_20210212_0554.py +178 -0
  108. karrio/server/providers/migrations/0005_auto_20210212_0555.py +18 -0
  109. karrio/server/providers/migrations/0006_australiapostsettings.py +29 -0
  110. karrio/server/providers/migrations/0007_auto_20210213_0206.py +21 -0
  111. karrio/server/providers/migrations/0008_auto_20210214_0409.py +30 -0
  112. karrio/server/providers/migrations/0009_auto_20210308_0302.py +18 -0
  113. karrio/server/providers/migrations/0010_auto_20210409_0852.py +32 -0
  114. karrio/server/providers/migrations/0011_auto_20210409_0853.py +21 -0
  115. karrio/server/providers/migrations/0012_alter_carrier_options.py +17 -0
  116. karrio/server/providers/migrations/0013_tntsettings.py +30 -0
  117. karrio/server/providers/migrations/0014_auto_20210612_1608.py +46 -0
  118. karrio/server/providers/migrations/0015_auto_20210615_1601.py +28 -0
  119. karrio/server/providers/migrations/0016_alter_purolatorsettings_user_token.py +18 -0
  120. karrio/server/providers/migrations/0017_auto_20210805_0359.py +1293 -0
  121. karrio/server/providers/migrations/0018_alter_fedexsettings_user_key.py +18 -0
  122. karrio/server/providers/migrations/0019_dhlpolandsettings_servicelevel.py +65 -0
  123. karrio/server/providers/migrations/0020_genericsettings_labeltemplate.py +52 -0
  124. karrio/server/providers/migrations/0021_auto_20211231_2353.py +40 -0
  125. karrio/server/providers/migrations/0022_carrier_metadata.py +18 -0
  126. karrio/server/providers/migrations/0023_auto_20220124_1916.py +27 -0
  127. karrio/server/providers/migrations/0024_alter_genericsettings_custom_carrier_name.py +19 -0
  128. karrio/server/providers/migrations/0025_alter_servicelevel_service_code.py +19 -0
  129. karrio/server/providers/migrations/0026_auto_20220208_0132.py +59 -0
  130. karrio/server/providers/migrations/0027_auto_20220304_1340.py +29 -0
  131. karrio/server/providers/migrations/0028_auto_20220323_1500.py +33 -0
  132. karrio/server/providers/migrations/0029_easypostsettings.py +27 -0
  133. karrio/server/providers/migrations/0030_amazonmwssettings.py +29 -0
  134. karrio/server/providers/migrations/0031_delete_amazonmwssettings.py +18 -0
  135. karrio/server/providers/migrations/0032_alter_carrier_test.py +18 -0
  136. karrio/server/providers/migrations/0033_auto_20220708_1350.py +22 -0
  137. karrio/server/providers/migrations/0034_amazonmwssettings_dpdhlsettings.py +47 -0
  138. karrio/server/providers/migrations/0035_alter_carrier_capabilities.py +43 -0
  139. karrio/server/providers/migrations/0036_upsfreightsettings.py +31 -0
  140. karrio/server/providers/migrations/0037_chronopostsettings.py +29 -0
  141. karrio/server/providers/migrations/0038_alter_genericsettings_label_template.py +19 -0
  142. karrio/server/providers/migrations/0039_auto_20220906_0612.py +23 -0
  143. karrio/server/providers/migrations/0040_dpdhlsettings_services.py +18 -0
  144. karrio/server/providers/migrations/0041_auto_20221105_0705.py +38 -0
  145. karrio/server/providers/migrations/0042_auto_20221215_1642.py +23 -0
  146. karrio/server/providers/migrations/0043_alter_genericsettings_account_number_and_more.py +39 -0
  147. karrio/server/providers/migrations/0044_carrier_carrier_capabilities.py +64 -0
  148. karrio/server/providers/migrations/0045_alter_carrier_active_alter_carrier_carrier_id.py +31 -0
  149. karrio/server/providers/migrations/0046_remove_dpdhlsettings_signature_and_more.py +41 -0
  150. karrio/server/providers/migrations/0047_dpdsettings.py +286 -0
  151. karrio/server/providers/migrations/0048_servicelevel_min_weight_servicelevel_transit_days_and_more.py +64 -0
  152. karrio/server/providers/migrations/0049_boxknightsettings_geodissettings_lapostesettings_and_more.py +156 -0
  153. karrio/server/providers/migrations/0050_carrier_is_system_alter_carrier_metadata_and_more.py +106 -0
  154. karrio/server/providers/migrations/0051_rename_username_upssettings_client_id_and_more.py +31 -0
  155. karrio/server/providers/migrations/0052_alter_upssettings_account_number_and_more.py +20 -0
  156. karrio/server/providers/migrations/0053_locate2usettings.py +281 -0
  157. karrio/server/providers/migrations/0054_zoom2usettings.py +280 -0
  158. karrio/server/providers/migrations/0055_rename_amazonmwssettings_amazonshippingsettings_and_more.py +44 -0
  159. karrio/server/providers/migrations/0056_asendiaussettings_geodissettings_code_client_and_more.py +75 -0
  160. karrio/server/providers/migrations/0057_alter_servicelevel_weight_unit_belgianpostsettings.py +51 -0
  161. karrio/server/providers/migrations/0058_alliedexpresssettings.py +38 -0
  162. karrio/server/providers/migrations/0059_ratesheet.py +81 -0
  163. karrio/server/providers/migrations/0060_belgianpostsettings_rate_sheet_and_more.py +73 -0
  164. karrio/server/providers/migrations/0061_alliedexpresssettings_service_type.py +17 -0
  165. karrio/server/providers/migrations/0062_sendlesettings_account_country_code.py +257 -0
  166. karrio/server/providers/migrations/0063_servicelevel_metadata.py +25 -0
  167. karrio/server/providers/migrations/0064_alliedexpresslocalsettings.py +43 -0
  168. karrio/server/providers/migrations/0065_servicelevel_carrier_service_code_and_more.py +66 -0
  169. karrio/server/providers/migrations/0066_rename_fedexsettings_fedexwssettings_and_more.py +28 -0
  170. karrio/server/providers/migrations/0067_fedexsettings.py +283 -0
  171. karrio/server/providers/migrations/0068_fedexsettings_track_api_key_and_more.py +38 -0
  172. karrio/server/providers/migrations/0069_alter_canadapostsettings_contract_id_and_more.py +23 -0
  173. karrio/server/providers/migrations/0070_tgesettings_alter_carrier_capabilities.py +65 -0
  174. karrio/server/providers/migrations/0071_alter_tgesettings_my_toll_token.py +18 -0
  175. karrio/server/providers/migrations/0072_rename_eshippersettings_eshipperxmlsettings_and_more.py +28 -0
  176. karrio/server/providers/migrations/0073_delete_eshipperxmlsettings.py +41 -0
  177. karrio/server/providers/migrations/0074_eshippersettings.py +38 -0
  178. karrio/server/providers/migrations/0075_haypostsettings.py +40 -0
  179. karrio/server/providers/migrations/0076_rename_customer_registration_id_uspsinternationalsettings_account_number_and_more.py +125 -0
  180. karrio/server/providers/migrations/0077_uspswtinternationalsettings_uspswtsettings_and_more.py +165 -0
  181. karrio/server/providers/migrations/0078_auto_20240813_1552.py +120 -0
  182. karrio/server/providers/migrations/0079_alter_carrier_options_alter_ratesheet_created_by.py +31 -0
  183. karrio/server/providers/migrations/0080_alter_aramexsettings_account_country_code_and_more.py +3025 -0
  184. karrio/server/providers/migrations/0081_remove_alliedexpresssettings_carrier_ptr_and_more.py +338 -0
  185. karrio/server/providers/migrations/__init__.py +0 -0
  186. karrio/server/providers/models/__init__.py +17 -0
  187. karrio/server/providers/models/carrier.py +309 -0
  188. karrio/server/providers/models/config.py +30 -0
  189. karrio/server/providers/models/service.py +62 -0
  190. karrio/server/providers/models/sheet.py +60 -0
  191. karrio/server/providers/models/template.py +39 -0
  192. karrio/server/providers/models/utils.py +58 -0
  193. karrio/server/providers/router.py +3 -0
  194. karrio/server/providers/serializers/__init__.py +3 -0
  195. karrio/server/providers/serializers/base.py +277 -0
  196. karrio/server/providers/signals.py +27 -0
  197. karrio/server/providers/tests.py +3 -0
  198. karrio/server/providers/urls.py +11 -0
  199. karrio/server/providers/views/__init__.py +0 -0
  200. karrio/server/providers/views/carriers.py +269 -0
  201. karrio/server/providers/views/connections.py +176 -0
  202. karrio/server/samples.py +352 -0
  203. karrio/server/serializers/__init__.py +2 -0
  204. karrio/server/serializers/abstract.py +506 -0
  205. karrio/server/tracing/__init__.py +0 -0
  206. karrio/server/tracing/admin.py +63 -0
  207. karrio/server/tracing/apps.py +8 -0
  208. karrio/server/tracing/migrations/0001_initial.py +41 -0
  209. karrio/server/tracing/migrations/0002_auto_20220710_1307.py +22 -0
  210. karrio/server/tracing/migrations/0003_auto_20221105_0317.py +43 -0
  211. karrio/server/tracing/migrations/0004_tracingrecord_carrier_account_idx.py +24 -0
  212. karrio/server/tracing/migrations/0005_optimise_tracingrecord_request_log_idx.py +25 -0
  213. karrio/server/tracing/migrations/0006_alter_tracingrecord_options_and_more.py +49 -0
  214. karrio/server/tracing/migrations/__init__.py +0 -0
  215. karrio/server/tracing/models.py +80 -0
  216. karrio/server/tracing/tests.py +3 -0
  217. karrio/server/tracing/utils.py +112 -0
  218. karrio/server/user/__init__.py +0 -0
  219. karrio/server/user/admin.py +96 -0
  220. karrio/server/user/apps.py +7 -0
  221. karrio/server/user/forms.py +35 -0
  222. karrio/server/user/migrations/0001_initial.py +41 -0
  223. karrio/server/user/migrations/0002_token.py +29 -0
  224. karrio/server/user/migrations/0003_token_test_mode.py +20 -0
  225. karrio/server/user/migrations/0004_group.py +26 -0
  226. karrio/server/user/migrations/0005_token_label.py +21 -0
  227. karrio/server/user/migrations/0006_workspaceconfig.py +63 -0
  228. karrio/server/user/migrations/__init__.py +0 -0
  229. karrio/server/user/models.py +203 -0
  230. karrio/server/user/serializers.py +46 -0
  231. karrio/server/user/templates/registration/login.html +108 -0
  232. karrio/server/user/templates/registration/registration_confirm_email.html +10 -0
  233. karrio/server/user/templates/registration/registration_confirm_email.txt +3 -0
  234. karrio/server/user/tests.py +3 -0
  235. karrio/server/user/urls.py +10 -0
  236. karrio/server/user/utils.py +60 -0
  237. karrio/server/user/views.py +9 -0
  238. karrio_server_core-2025.5rc1.dist-info/METADATA +32 -0
  239. karrio_server_core-2025.5rc1.dist-info/RECORD +241 -0
  240. karrio_server_core-2025.5rc1.dist-info/WHEEL +5 -0
  241. karrio_server_core-2025.5rc1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,19 @@
1
+ from django.core.management.base import BaseCommand
2
+ import sys
3
+
4
+ class Command(BaseCommand):
5
+ help = "Run kcli commands from the Django CLI."
6
+
7
+ def run_from_argv(self, argv):
8
+ # Remove the management command name ("kcli") from argv
9
+ kcli_args = argv[2:]
10
+ try:
11
+ from kcli.__main__ import app
12
+ # Call the Typer app with the forwarded arguments
13
+ app(prog_name="karrio cli", args=kcli_args)
14
+ except SystemExit as e:
15
+ # Typer uses SystemExit for normal CLI exit, so suppress traceback
16
+ sys.exit(e.code)
17
+ except ImportError:
18
+ self.stderr.write(self.style.ERROR("Could not import kcli CLI app."))
19
+ sys.exit(1)
@@ -0,0 +1,41 @@
1
+ from django.core.management.base import BaseCommand
2
+ from oauth2_provider.models import Application
3
+ from django.contrib.auth import get_user_model
4
+
5
+ User = get_user_model()
6
+
7
+ class Command(BaseCommand):
8
+ help = 'Creates an OAuth2 client application'
9
+
10
+ def add_arguments(self, parser):
11
+ parser.add_argument('--name', required=True)
12
+ parser.add_argument('--client_id', required=True)
13
+ parser.add_argument('--client_secret', required=True)
14
+ parser.add_argument('--redirect_uri', required=True)
15
+ parser.add_argument('--user_email', required=True)
16
+
17
+ def handle(self, *args, **options):
18
+ try:
19
+ user = User.objects.get(email=options['user_email'])
20
+ except User.DoesNotExist:
21
+ self.stdout.write(self.style.ERROR(f"User with email {options['user_email']} does not exist"))
22
+ return
23
+
24
+ # Check if application with this client_id already exists
25
+ app, created = Application.objects.update_or_create(
26
+ client_id=options['client_id'],
27
+ defaults={
28
+ 'name': options['name'],
29
+ 'user': user,
30
+ 'client_type': Application.CLIENT_CONFIDENTIAL,
31
+ 'authorization_grant_type': Application.GRANT_AUTHORIZATION_CODE,
32
+ 'client_secret': options['client_secret'],
33
+ 'redirect_uris': options['redirect_uri'],
34
+ 'skip_authorization': True,
35
+ }
36
+ )
37
+
38
+ if created:
39
+ self.stdout.write(self.style.SUCCESS(f"Successfully created OAuth2 application: {options['name']}"))
40
+ else:
41
+ self.stdout.write(self.style.SUCCESS(f"Successfully updated OAuth2 application: {options['name']}"))
@@ -0,0 +1,95 @@
1
+ import json
2
+ import threading
3
+ from django.db.models import Q
4
+ from django.http import HttpResponse
5
+ from karrio.core.utils import Tracer
6
+ from karrio.server.conf import settings
7
+
8
+
9
+ class CreatorAccess:
10
+ def __call__(self, context, key: str = "created_by", **kwargs) -> Q:
11
+ user_key = f"{key}_id"
12
+ user = getattr(context, "user", None)
13
+
14
+ return Q(**{user_key: getattr(user, "id", None)})
15
+
16
+
17
+ class WideAccess:
18
+ def __call__(self, *args, **kwargs) -> Q:
19
+ return Q()
20
+
21
+
22
+ class UserToken:
23
+ def __call__(self, context, **kwargs) -> dict:
24
+ return dict(user=getattr(context, "user", context))
25
+
26
+
27
+ class SessionContext:
28
+ _threadmap: dict = {}
29
+
30
+ def __init__(self, get_response):
31
+ self.get_response = get_response
32
+ # One-time configuration and initialization.
33
+
34
+ def __call__(self, request):
35
+ # Code to be executed for each request before
36
+ # the view (and later middleware) are called.
37
+ request.tracer = Tracer()
38
+ self._threadmap[threading.get_ident()] = request
39
+
40
+ response = self.get_response(request)
41
+
42
+ # Code to be executed for each request/response after
43
+ # the view is called.
44
+ try:
45
+ self._save_tracing_records(request, schema=settings.schema)
46
+ del self._threadmap[threading.get_ident()]
47
+ except KeyError:
48
+ pass
49
+
50
+ return response
51
+
52
+ def _save_tracing_records(self, request, schema: str = None):
53
+ from karrio.server.tracing.utils import save_tracing_records
54
+
55
+ save_tracing_records(request, schema=schema)
56
+
57
+ @classmethod
58
+ def get_current_request(cls):
59
+ return cls._threadmap.get(threading.get_ident())
60
+
61
+
62
+ class NonHtmlDebugToolbarMiddleware:
63
+ """
64
+ The Django Debug Toolbar usually only works for views that return HTML.
65
+ This middleware wraps any non-HTML response in HTML if the request
66
+ has a 'debug' query parameter (e.g. http://localhost/foo?debug)
67
+ Special handling for json (pretty printing) and
68
+ binary data (only show data length)
69
+ """
70
+
71
+ def __init__(self, get_response):
72
+ self.get_response = get_response
73
+
74
+ def __call__(self, request):
75
+ response = self.get_response(request)
76
+
77
+ if request.GET.get("debug") == "":
78
+ if response["Content-Type"] == "application/octet-stream":
79
+ new_content = (
80
+ "<html><body>Binary Data, "
81
+ "Length: {}</body></html>".format(len(response.content))
82
+ )
83
+ response = HttpResponse(new_content)
84
+ elif response["Content-Type"] != "text/html":
85
+ content = response.content
86
+ try:
87
+ json_ = json.loads(content)
88
+ content = json.dumps(json_, sort_keys=True, indent=2)
89
+ except ValueError:
90
+ pass
91
+ response = HttpResponse(
92
+ "<html><body><pre>{}" "</pre></body></html>".format(content)
93
+ )
94
+
95
+ return response
@@ -0,0 +1,28 @@
1
+ # Generated by Django 3.2.3 on 2021-05-18 10:53
2
+
3
+ from django.db import migrations
4
+ import karrio.server.core.models.base
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ initial = True
10
+
11
+ dependencies = [
12
+ ('rest_framework_tracking', '0011_auto_20201117_2016'),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name='APILog',
18
+ fields=[
19
+ ],
20
+ options={
21
+ 'ordering': ['-requested_at'],
22
+ 'proxy': True,
23
+ 'indexes': [],
24
+ 'constraints': [],
25
+ },
26
+ bases=('rest_framework_tracking.apirequestlog', karrio.server.core.models.base.ControlledAccessModel),
27
+ ),
28
+ ]
@@ -0,0 +1,69 @@
1
+ # Generated by Django 3.2.13 on 2022-07-18 12:05
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+ import karrio.server.core.utils as utils
6
+
7
+
8
+ def forwards_func(apps, schema_editor):
9
+ db_alias = schema_editor.connection.alias
10
+ APILog = apps.get_model("core", "APILog")
11
+ APILogIndex = apps.get_model("core", "APILogIndex")
12
+ logs = APILog.objects.using(db_alias).filter(response__isnull=False).iterator()
13
+
14
+ for log in logs:
15
+ response = utils.failsafe(
16
+ lambda: utils.DP.to_dict(utils.DP.to_dict(log.response))
17
+ )
18
+ entity_id = utils.failsafe(lambda: response["id"])
19
+
20
+ if entity_id is not None:
21
+ _index = APILogIndex(
22
+ apirequestlog_ptr=log,
23
+ entity_id=entity_id,
24
+ )
25
+ _index.save_base(raw=True)
26
+
27
+ if isinstance(response, dict):
28
+ log.response = utils.DP.jsonify(response)
29
+ log.save()
30
+
31
+
32
+ def reverse_func(apps, schema_editor):
33
+ pass
34
+
35
+
36
+ class Migration(migrations.Migration):
37
+ dependencies = [
38
+ ("rest_framework_tracking", "0011_auto_20201117_2016"),
39
+ ("core", "0001_initial"),
40
+ ]
41
+
42
+ operations = [
43
+ migrations.CreateModel(
44
+ name="APILogIndex",
45
+ fields=[
46
+ (
47
+ "apirequestlog_ptr",
48
+ models.OneToOneField(
49
+ auto_created=True,
50
+ on_delete=django.db.models.deletion.CASCADE,
51
+ parent_link=True,
52
+ primary_key=True,
53
+ serialize=False,
54
+ to="rest_framework_tracking.apirequestlog",
55
+ ),
56
+ ),
57
+ (
58
+ "entity_id",
59
+ models.CharField(db_index=True, max_length=50, null=True),
60
+ ),
61
+ ],
62
+ options={
63
+ "verbose_name": "API Request Log",
64
+ "abstract": False,
65
+ },
66
+ bases=("core.apilog",),
67
+ ),
68
+ migrations.RunPython(forwards_func, reverse_func),
69
+ ]
@@ -0,0 +1,62 @@
1
+ # Generated by Django 4.1.4 on 2022-12-17 11:46
2
+
3
+ from django.db import migrations, models
4
+ import karrio.server.core.utils as utils
5
+ import karrio.lib as lib
6
+
7
+
8
+ def forwards_func(apps, schema_editor):
9
+ db_alias = schema_editor.connection.alias
10
+ APILog = apps.get_model("core", "APILog")
11
+ APILogIndex = apps.get_model("core", "APILogIndex")
12
+ logs = (
13
+ APILog.objects.using(db_alias)
14
+ .filter(models.Q(response__icontains="test_mode"))
15
+ .iterator()
16
+ )
17
+
18
+ for log in logs:
19
+ response = utils.failsafe(lambda: lib.to_dict(lib.to_dict(log.response)))
20
+ entity_id = utils.failsafe(lambda: response["id"])
21
+ test_mode = utils.failsafe(lambda: response["test_mode"])
22
+
23
+ if test_mode is None and '"test_mode": true' in log.response:
24
+ test_mode = True
25
+ if test_mode is None and '"test_mode": false' in log.response:
26
+ test_mode = False
27
+
28
+ if test_mode is not None and hasattr(log, "apilogindex"):
29
+ log.apilogindex.test_mode = test_mode
30
+ log.apilogindex.save()
31
+
32
+ if hasattr(log, "apilogindex") is False:
33
+ _index = APILogIndex(
34
+ apirequestlog_ptr=log,
35
+ entity_id=entity_id,
36
+ test_mode=test_mode,
37
+ )
38
+ _index.save_base(raw=True)
39
+
40
+ log.response = utils.DP.jsonify(response)
41
+ log.save()
42
+
43
+
44
+ def reverse_func(apps, schema_editor):
45
+ pass
46
+
47
+
48
+ class Migration(migrations.Migration):
49
+ dependencies = [
50
+ ("core", "0002_apilogindex"),
51
+ ]
52
+
53
+ operations = [
54
+ migrations.AddField(
55
+ model_name="apilogindex",
56
+ name="test_mode",
57
+ field=models.BooleanField(
58
+ default=True, help_text="execution context", null=True
59
+ ),
60
+ ),
61
+ migrations.RunPython(forwards_func, reverse_func),
62
+ ]
@@ -0,0 +1,74 @@
1
+ # Generated by Django 4.2.8 on 2024-01-13 22:41
2
+
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+ import django.db.models.deletion
6
+ import functools
7
+ import karrio.server.core.models.base
8
+
9
+
10
+ class Migration(migrations.Migration):
11
+ dependencies = [
12
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+ ("core", "0003_apilogindex_test_mode"),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.CreateModel(
18
+ name="Metafield",
19
+ fields=[
20
+ ("created_at", models.DateTimeField(auto_now_add=True)),
21
+ ("updated_at", models.DateTimeField(auto_now=True)),
22
+ (
23
+ "id",
24
+ models.CharField(
25
+ default=functools.partial(
26
+ karrio.server.core.models.base.uuid,
27
+ *(),
28
+ **{"prefix": "metaf_"}
29
+ ),
30
+ editable=False,
31
+ max_length=50,
32
+ primary_key=True,
33
+ serialize=False,
34
+ ),
35
+ ),
36
+ (
37
+ "key",
38
+ models.CharField(db_index=True, max_length=50, verbose_name="name"),
39
+ ),
40
+ ("value", models.CharField(blank=True, max_length=250, null=True)),
41
+ (
42
+ "type",
43
+ models.CharField(
44
+ choices=[
45
+ ("text", "text"),
46
+ ("number", "number"),
47
+ ("boolean", "boolean"),
48
+ ],
49
+ db_index=True,
50
+ default="text",
51
+ max_length=50,
52
+ verbose_name="type",
53
+ ),
54
+ ),
55
+ ("is_required", models.BooleanField(default=False)),
56
+ (
57
+ "created_by",
58
+ models.ForeignKey(
59
+ blank=True,
60
+ editable=False,
61
+ null=True,
62
+ on_delete=django.db.models.deletion.CASCADE,
63
+ to=settings.AUTH_USER_MODEL,
64
+ ),
65
+ ),
66
+ ],
67
+ options={
68
+ "verbose_name": "Metafield",
69
+ "verbose_name_plural": "Metafields",
70
+ "db_table": "metafield",
71
+ },
72
+ bases=(karrio.server.core.models.base.ControlledAccessModel, models.Model),
73
+ ),
74
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 5.2.3 on 2025-06-19 05:27
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0004_metafield'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='metafield',
15
+ name='type',
16
+ field=models.CharField(choices=[('text', 'text'), ('number', 'number'), ('boolean', 'boolean'), ('json', 'json'), ('date', 'date'), ('date_time', 'date_time'), ('password', 'password')], db_index=True, default='text', max_length=50, verbose_name='type'),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='metafield',
20
+ name='value',
21
+ field=models.JSONField(blank=True, null=True),
22
+ ),
23
+ ]
File without changes
@@ -0,0 +1,48 @@
1
+ import ast
2
+ import yaml
3
+ import typing
4
+ import functools
5
+
6
+ import karrio.lib as lib
7
+ from karrio.server.core.models.base import (
8
+ ControlledAccessModel,
9
+ get_access_filter,
10
+ register_model,
11
+ uuid,
12
+ MetafieldType,
13
+ METAFIELD_TYPE,
14
+ )
15
+ from karrio.server.core.models.third_party import (
16
+ APILog,
17
+ APILogIndex,
18
+ )
19
+ from karrio.server.core.models.metafield import (
20
+ Metafield,
21
+ )
22
+ from karrio.server.core.models.entity import Entity, OwnedEntity
23
+
24
+
25
+ def _identity(value: typing.Any):
26
+ return value
27
+
28
+
29
+ def field_default(value: typing.Any) -> typing.Callable:
30
+ return functools.partial(_identity, value=value)
31
+
32
+
33
+ def metafields_to_dict(metafields: typing.List[Metafield]) -> dict:
34
+ _values = {}
35
+
36
+ for _ in metafields:
37
+ # Skip metafields with None or empty values
38
+ if _.value is None or _.value == "":
39
+ continue
40
+
41
+ if _.type == "number":
42
+ _values.update({_.key: lib.failsafe(lambda: ast.literal_eval(_.value))})
43
+ elif _.type == "boolean":
44
+ _values.update({_.key: lib.failsafe(lambda: bool(yaml.safe_load(_.value)))})
45
+ else:
46
+ _values.update({_.key: _.value})
47
+
48
+ return _values
@@ -0,0 +1,70 @@
1
+ import pydoc
2
+ import typing
3
+ import functools
4
+ from uuid import uuid4
5
+ from django.db import models
6
+ from django.conf import settings
7
+
8
+ import karrio.lib as lib
9
+
10
+ T = typing.TypeVar("T")
11
+ MODEL_TRANSFORMERS = getattr(settings, "MODEL_TRANSFORMERS", [])
12
+ ACCESS_METHOD = getattr(
13
+ settings,
14
+ "KARRIO_ENTITY_ACCESS_METHOD",
15
+ "karrio.server.core.middleware.WideAccess",
16
+ )
17
+ get_access_filter = pydoc.locate(ACCESS_METHOD)()
18
+
19
+
20
+ def uuid(prefix: str = None):
21
+ return f'{prefix or ""}{uuid4().hex}'
22
+
23
+
24
+ class ControlledAccessModel:
25
+ @classmethod
26
+ def access_by(cls: models.Model, context, manager: str = "objects"):
27
+ test_mode = (
28
+ context.get("test_mode")
29
+ if isinstance(context, dict)
30
+ else getattr(context, "test_mode", None)
31
+ )
32
+
33
+ if hasattr(cls, "created_by"):
34
+ key = "created_by"
35
+ elif hasattr(cls, "actor"):
36
+ key = "actor"
37
+ else:
38
+ key = "user"
39
+
40
+ query = get_access_filter(context, key)
41
+
42
+ if hasattr(cls, "test_mode") and test_mode is not None:
43
+ query = query & models.Q(
44
+ models.Q(test_mode=context.test_mode) | models.Q(test_mode__isnull=True)
45
+ )
46
+
47
+ queryset = getattr(cls, manager, cls.objects)
48
+
49
+ return queryset.filter(query)
50
+
51
+
52
+ def register_model(model: T) -> T:
53
+ transform = lambda model, transformer: (
54
+ model if transformer is None else pydoc.locate(transformer)(model)
55
+ )
56
+
57
+ return functools.reduce(transform, MODEL_TRANSFORMERS, model)
58
+
59
+
60
+ class MetafieldType(lib.StrEnum):
61
+ text = "text"
62
+ number = "number"
63
+ boolean = "boolean"
64
+ json = "json"
65
+ date = "date"
66
+ date_time = "date_time"
67
+ password = "password"
68
+
69
+
70
+ METAFIELD_TYPE = [(c.name, c.name) for c in list(MetafieldType)]
@@ -0,0 +1,22 @@
1
+ from django.db import models
2
+ from django.conf import settings
3
+ from karrio.server.core.models.base import uuid, ControlledAccessModel
4
+
5
+
6
+ class Entity(models.Model):
7
+ class Meta:
8
+ abstract = True
9
+
10
+ id = models.CharField(max_length=50, primary_key=True, default=uuid, editable=False)
11
+ created_at = models.DateTimeField(auto_now_add=True)
12
+ updated_at = models.DateTimeField(auto_now=True)
13
+
14
+ def __str__(self):
15
+ return self.id
16
+
17
+
18
+ class OwnedEntity(ControlledAccessModel, Entity):
19
+ class Meta:
20
+ abstract = True
21
+
22
+ created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)