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,82 @@
1
+ import yaml # type: ignore
2
+ from rest_framework import status
3
+ from rest_framework.decorators import api_view, renderer_classes, permission_classes
4
+ from rest_framework.permissions import AllowAny
5
+ from rest_framework.response import Response
6
+ from rest_framework.request import Request
7
+ from rest_framework.renderers import JSONRenderer
8
+ from django.urls import path
9
+ from django.conf import settings
10
+
11
+ from karrio.server.conf import FEATURE_FLAGS
12
+ from karrio.server.core.router import router
13
+ import karrio.server.core.dataunits as dataunits
14
+ import karrio.server.openapi as openapi
15
+
16
+ ENDPOINT_ID = "&&" # This endpoint id is used to make operation ids unique make sure not to duplicate
17
+ BASE_PATH = getattr(settings, "BASE_PATH", "")
18
+ References = openapi.OpenApiResponse(
19
+ openapi.OpenApiTypes.OBJECT,
20
+ examples=[
21
+ openapi.OpenApiExample(
22
+ name="References",
23
+ value={
24
+ "VERSION": "",
25
+ "APP_NAME": "",
26
+ "APP_WEBSITE": "",
27
+ "HOST": "",
28
+ "ADMIN": "",
29
+ "OPENAPI": "",
30
+ "GRAPHQL": "",
31
+ **{flag: True for flag in FEATURE_FLAGS},
32
+ "ADDRESS_AUTO_COMPLETE": {},
33
+ "countries": {},
34
+ "currencies": {},
35
+ "carriers": {},
36
+ "customs_content_type": {},
37
+ "incoterms": {},
38
+ "states": {},
39
+ "services": {},
40
+ "connection_configs": {},
41
+ "service_names": {},
42
+ "options": {},
43
+ "option_names": {},
44
+ "package_presets": {},
45
+ "packaging_types": {},
46
+ "payment_types": {},
47
+ "carrier_capabilities": {},
48
+ "service_levels": {},
49
+ "integration_status": {},
50
+ },
51
+ )
52
+ ],
53
+ )
54
+
55
+
56
+ @openapi.extend_schema(
57
+ auth=[],
58
+ methods=["get"],
59
+ tags=["API"],
60
+ operation_id=f"{ENDPOINT_ID}data",
61
+ summary="Data References",
62
+ responses={200: References},
63
+ )
64
+ @api_view(["GET"])
65
+ @permission_classes([AllowAny])
66
+ @renderer_classes([JSONRenderer])
67
+ def references(request: Request):
68
+ try:
69
+ reduced = bool(yaml.safe_load(request.query_params.get("reduced", "true")))
70
+
71
+ return Response(
72
+ dataunits.contextual_reference(reduced=reduced),
73
+ status=status.HTTP_200_OK,
74
+ )
75
+ except Exception as e:
76
+ import logging
77
+
78
+ logging.exception(e)
79
+ raise e
80
+
81
+
82
+ router.urls.append(path("references", references))
@@ -0,0 +1,310 @@
1
+ import jinja2
2
+ import django.conf as django
3
+ import drf_spectacular.views as views
4
+ import rest_framework.response as response
5
+
6
+ import django.urls as urls
7
+ import karrio.server.conf as conf
8
+ import karrio.server.core.dataunits as dataunits
9
+
10
+ VERSION = getattr(django.settings, "VERSION", "")
11
+ non_null = lambda items: [i for i in items if i is not None]
12
+ RedocView = views.SpectacularRedocView.as_view(
13
+ url_name="shipping-openapi",
14
+ template_name="openapi/openapi.html",
15
+ )
16
+
17
+
18
+ class ShippingOpenAPIView(views.SpectacularAPIView):
19
+ def _get_schema_response(self, request):
20
+ version = (
21
+ self.api_version or request.version or self._get_version_parameter(request)
22
+ )
23
+ generator = self.generator_class(
24
+ urlconf=self.urlconf, api_version=version, patterns=self.patterns
25
+ )
26
+ data = generator.get_schema(request=request, public=self.serve_public)
27
+
28
+ data["tags"] = render_tags(request, conf.settings.APP_NAME)
29
+ data["components"]["securitySchemes"] = {
30
+ k: v
31
+ for k, v in data["components"]["securitySchemes"].items()
32
+ if k in ["JWT", "OAuth2", "Token", "TokenBasic"]
33
+ }
34
+ data["info"] = dict(
35
+ description=render_schema_description(conf.settings.APP_NAME),
36
+ title=f"{conf.settings.APP_NAME} API",
37
+ version=conf.settings.VERSION,
38
+ )
39
+
40
+ return response.Response(
41
+ data=data,
42
+ headers={
43
+ "Content-Disposition": f'inline; filename="{self._get_filename(request, version)}"'
44
+ },
45
+ )
46
+
47
+
48
+ urlpatterns = [
49
+ urls.path(
50
+ django.settings.OPEN_API_PATH,
51
+ RedocView,
52
+ name="schema-rapi",
53
+ ),
54
+ urls.path(
55
+ "shipping-openapi",
56
+ ShippingOpenAPIView.as_view(),
57
+ name="shipping-openapi",
58
+ ),
59
+ ]
60
+
61
+
62
+ def render_schema_description(APP_NAME):
63
+ return f"""
64
+ {APP_NAME} is a multi-carrier shipping API that simplifies the integration of logistics carrier services.
65
+
66
+ The {APP_NAME} API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded
67
+ request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
68
+
69
+ The {APP_NAME} API differs for every account as we release new versions.
70
+ These docs are customized to your version of the API.
71
+
72
+
73
+ ## Versioning
74
+
75
+ When backwards-incompatible changes are made to the API, a new, dated version is released.
76
+ The current version is `{VERSION}`.
77
+
78
+ Read our API changelog to learn more about backwards compatibility.
79
+
80
+ As a precaution, use API versioning to check a new API version before committing to an upgrade.
81
+
82
+
83
+ ## Environments
84
+
85
+ The {APP_NAME} API offer the possibility to create and retrieve certain objects in `test_mode`.
86
+ In development, it is therefore possible to add carrier connections, get live rates,
87
+ buy labels, create trackers and schedule pickups in `test_mode`.
88
+
89
+
90
+ ## Pagination
91
+
92
+ All top-level API resources have support for bulk fetches via "list" API methods. For instance, you can list addresses,
93
+ list shipments, and list trackers. These list API methods share a common structure, taking at least these
94
+ two parameters: limit, and offset.
95
+
96
+ {APP_NAME} utilizes offset-based pagination via the offset and limit parameters.
97
+ Both parameters take a number as value (see below) and return objects in reverse chronological order.
98
+ The offset parameter returns objects listed after an index.
99
+ The limit parameter take a limit on the number of objects to be returned from 1 to 100.
100
+
101
+
102
+ ```json
103
+ {{
104
+ "count": 100,
105
+ "next": "/v1/shipments?limit=25&offset=50",
106
+ "previous": "/v1/shipments?limit=25&offset=25",
107
+ "results": [
108
+ {{ ... }},
109
+ ]
110
+ }}
111
+ ```
112
+
113
+ ## Metadata
114
+
115
+ Updateable {APP_NAME} objects—including Shipment and Order have a metadata parameter.
116
+ You can use this parameter to attach key-value data to these {APP_NAME} objects.
117
+
118
+ Metadata is useful for storing additional, structured information on an object.
119
+ As an example, you could store your user's full name and corresponding unique identifier
120
+ from your system on a {APP_NAME} Order object.
121
+
122
+ Do not store any sensitive information as metadata.
123
+
124
+ ## Authentication
125
+
126
+ API keys are used to authenticate requests. You can view and manage your API keys in the Dashboard.
127
+
128
+ Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret
129
+ API keys in publicly accessible areas such as GitHub, client-side code, and so forth.
130
+
131
+ Authentication to the API is performed via HTTP Basic Auth. Provide your API token as
132
+ the basic auth username value. You do not need to provide a password.
133
+
134
+ ```shell
135
+ $ curl https://instance.api.com/v1/shipments \\
136
+ -u key_xxxxxx:
137
+ # The colon prevents curl from asking for a password.
138
+ ```
139
+
140
+ If you need to authenticate via bearer auth (e.g., for a cross-origin request),
141
+ use `-H "Authorization: Token key_xxxxxx"` instead of `-u key_xxxxxx`.
142
+
143
+ All API requests must be made over [HTTPS](http://en.wikipedia.org/wiki/HTTP_Secure).
144
+ API requests without authentication will also fail.
145
+ """
146
+
147
+
148
+ def render_reference_descriptions(request):
149
+ refs = dataunits.contextual_reference(request, reduced=False)
150
+
151
+ def format_preset(preset: dict):
152
+ vals = [
153
+ str(v)
154
+ for v in [
155
+ preset.get("width"),
156
+ preset.get("height"),
157
+ preset.get("length"),
158
+ ]
159
+ if v is not None
160
+ ]
161
+
162
+ return f'{" x ".join(vals)} {preset.get("dimension_unit").lower()}'
163
+
164
+ template = """## Carriers
165
+ | Carrier Name | Display Name |
166
+ | ------------ | ------------ |
167
+ {% for carrier, name in refs.get("carriers", {}).items() -%}{% if carrier != "generic" -%}
168
+ | {{ carrier }} | {{ name }} |
169
+ {% endif -%}{% endfor %}
170
+ ---
171
+ ## Services
172
+ The following service level codes can be used to reference specific rates
173
+ when purchasing shipping labels using single call label creation.
174
+ You can also find all of the possible service levels for each of your carrier
175
+ accounts by using [this endpoint](#operation/&&get_services).
176
+ {% for carrier, services in refs.get("services", {}).items() -%}{% if carrier != "generic" -%}
177
+ ### {{ refs.get("carriers", {}).get(carrier, "") }}
178
+ | Code | Service Name |
179
+ | ------------ | ------------ |
180
+ {% for code, name in services.items() -%}
181
+ | {{ code }} | {{ name }} |
182
+ {% endfor %}
183
+ {% endif -%}{% endfor %}
184
+ ---
185
+ ## Parcel Templates
186
+ Use any of the following templates when you ship with special carrier packaging.
187
+ {% for carrier, presets in refs.get("package_presets", {}).items() -%}
188
+ ### {{ refs.get("carriers", {}).get(carrier, "") }}
189
+ | Code | Dimensions |
190
+ | ------------ | ------------ |
191
+ {% for code, preset in presets.items() -%}
192
+ | {{ code }} | {{ format_preset(preset) }} |
193
+ {% endfor %}
194
+ {% endfor %}
195
+ """
196
+
197
+ return jinja2.Template(template).render(refs=refs, format_preset=format_preset)
198
+
199
+
200
+ def render_tags(request, APP_NAME):
201
+ return non_null(
202
+ [
203
+ {
204
+ "name": "API",
205
+ "description": """API instance metadata resources.
206
+ """,
207
+ },
208
+ {
209
+ "name": "Auth",
210
+ "description": """API authentication resources.
211
+ """,
212
+ },
213
+ {
214
+ "name": "Carriers",
215
+ "description": f"""This is an object representing your {APP_NAME} carrier extension.
216
+ You can retrieve all supported carrier extensions available.
217
+ """,
218
+ },
219
+ {
220
+ "name": "Connections",
221
+ "description": f"""This is an object representing your {APP_NAME} carrier connections.
222
+ You can retrieve all carrier connections available to your account.
223
+ The `carrier_id` is a friendly name you assign to your connection.
224
+ """,
225
+ },
226
+ {
227
+ "name": "Addresses",
228
+ "description": f"""This is an object representing your {APP_NAME} shipping address.
229
+ You can retrieve all addresses related to your {APP_NAME} account.
230
+ Address objects are linked to your shipment history, and can be used for recurring shipping
231
+ to / from the same locations.
232
+ """,
233
+ },
234
+ {
235
+ "name": "Parcels",
236
+ "description": f"""This is an object representing your {APP_NAME} shipping parcel.
237
+ Parcel objects are linked to your shipment history, and can be used for recurring shipping
238
+ using the same packaging.
239
+ """,
240
+ },
241
+ {
242
+ "name": "Shipments",
243
+ "description": f"""This is an object representing your {APP_NAME} shipment.
244
+ A Shipment guides you through process of preparing and purchasing a label for an order.
245
+ A Shipment transitions through multiple statuses throughout its lifetime as the package
246
+ shipped makes its journey to it's destination.
247
+ """,
248
+ },
249
+ {
250
+ "name": "Documents",
251
+ "description": f"""This is an object representing your {APP_NAME} document upload record.
252
+ A Document upload record keep traces of shipping trade documents uploaded to carriers
253
+ to fast track customs and border processing.
254
+ """,
255
+ },
256
+ {
257
+ "name": "Manifests",
258
+ "description": f"""This is an object representing your {APP_NAME} manifest details.
259
+ Some carriers require manifests to be created after labels are generated.
260
+ A manifest is a summary of all the shipments that are being sent out.
261
+ """,
262
+ },
263
+ {
264
+ "name": "Trackers",
265
+ "description": f"""This is an object representing your {APP_NAME} shipment tracker.
266
+ A shipment tracker is an object attached to a shipment by it's tracking number.
267
+ The tracker provide the latest tracking status and events associated with a shipment
268
+ """,
269
+ },
270
+ {
271
+ "name": "Pickups",
272
+ "description": f"""This is an object representing your {APP_NAME} pickup booking.
273
+ You can retrieve all pickup booked historically for your {APP_NAME} account shipments.
274
+ """,
275
+ },
276
+ {
277
+ "name": "Proxy",
278
+ "description": f"""In some scenarios, all we need is to send request to a carrier using the {APP_NAME} unified API.
279
+ The Proxy API comes handy for that as it turn {APP_NAME} into a simple middleware that converts and
280
+ validate your request and simply forward it to the shipping carrier server.<br/>
281
+ **Note:**<br/>
282
+ When using the proxy API, no objects are created in the {APP_NAME} system.
283
+ excpet API logs and tracing records for debugging purposes.
284
+ """,
285
+ },
286
+ {
287
+ "name": "Orders",
288
+ "description": f"""This is an object representing your {APP_NAME} order.
289
+ You can create {APP_NAME} orders to organize your shipments and ship line items separately.
290
+ """,
291
+ },
292
+ {
293
+ "name": "Webhooks",
294
+ "description": f"""This is an object representing your {APP_NAME} webhook.
295
+ You can configure webhook endpoints via the API to be notified about events happen in your
296
+ {APP_NAME} account.
297
+ """,
298
+ },
299
+ {
300
+ "name": "Batches",
301
+ "description": f"""This is an object representing your {APP_NAME} batch operation.
302
+ You can retrieve all batch operations historically for your {APP_NAME} account.
303
+ """,
304
+ },
305
+ {
306
+ "name": "Reference & Enums",
307
+ "description": render_reference_descriptions(request),
308
+ },
309
+ ]
310
+ )
@@ -0,0 +1,2 @@
1
+ from django_filters import *
2
+ from karrio.server.filters.abstract import *
@@ -0,0 +1,26 @@
1
+ import django_filters
2
+ import karrio.lib as lib
3
+
4
+
5
+ class CharInFilter(django_filters.BaseInFilter, django_filters.CharFilter):
6
+ pass
7
+
8
+
9
+ class FilterSet(django_filters.FilterSet):
10
+ def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
11
+ data = {
12
+ **data,
13
+ **{
14
+ key: (
15
+ ",".join(val)
16
+ if self.base_filters.get(key).__class__ == CharInFilter
17
+ else val
18
+ )
19
+ for key, val in data.items()
20
+ },
21
+ }
22
+ super().__init__(data, queryset, request=request, prefix=prefix)
23
+
24
+ def to_dict(self):
25
+ self.form.is_valid()
26
+ return lib.to_dict(self.form.cleaned_data)
File without changes
@@ -0,0 +1,3 @@
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
@@ -0,0 +1,21 @@
1
+ from django.apps import AppConfig
2
+ from django.utils.translation import gettext_lazy as _
3
+
4
+
5
+ class IamConfig(AppConfig):
6
+ name = "karrio.server.iam"
7
+ verbose_name = _("IAM")
8
+ default_auto_field = "django.db.models.BigAutoField"
9
+
10
+ def ready(self):
11
+ from karrio.server.core import utils
12
+ from karrio.server.iam import signals, permissions
13
+
14
+ @utils.skip_on_commands()
15
+ def _init():
16
+ signals.register_all()
17
+
18
+ # Setup default permission groups and apply to existing orgs on start up
19
+ utils.run_on_all_tenants(permissions.setup_groups)()
20
+
21
+ _init()
@@ -0,0 +1,33 @@
1
+ # Generated by Django 3.2.14 on 2022-09-03 12:25
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ initial = True
10
+
11
+ dependencies = [
12
+ ('user', '0004_group'),
13
+ ('auth', '0012_alter_user_first_name_max_length'),
14
+ ('contenttypes', '0002_remove_content_type_name'),
15
+ ]
16
+
17
+ operations = [
18
+ migrations.CreateModel(
19
+ name='ContextPermission',
20
+ fields=[
21
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
23
+ ('object_pk', models.CharField(db_index=True, max_length=50, verbose_name='object pk')),
24
+ ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype', verbose_name='content type')),
25
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user context belongs to. A user will get all permissions granted to each of their groups.', related_name='context', related_query_name='context', to='user.Group', verbose_name='groups')),
26
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user context.', related_name='context', related_query_name='context', to='auth.Permission', verbose_name='user context permissions')),
27
+ ],
28
+ options={
29
+ 'verbose_name': 'context permission',
30
+ 'verbose_name_plural': 'context permission',
31
+ },
32
+ ),
33
+ ]
File without changes
@@ -0,0 +1,48 @@
1
+ from django.db import models
2
+ from django.contrib.auth.models import PermissionsMixin, Permission
3
+ from django.contrib.contenttypes.fields import GenericForeignKey
4
+ from django.utils.translation import gettext_lazy as _
5
+
6
+ import karrio.server.user.models as user
7
+
8
+ User = user.User
9
+ Group = user.Group
10
+
11
+
12
+ class ContextPermission(PermissionsMixin):
13
+ class Meta:
14
+ verbose_name = _("context permission")
15
+ verbose_name_plural = _("context permission")
16
+
17
+ def __str__(self) -> str:
18
+ return f"{self.object_pk} - {self.content_type}"
19
+
20
+ content_type = models.ForeignKey(
21
+ to="contenttypes.ContentType",
22
+ on_delete=models.CASCADE,
23
+ related_name="+",
24
+ verbose_name=_("content type"),
25
+ )
26
+ object_pk = models.CharField(
27
+ db_index=True, max_length=50, verbose_name=_("object pk")
28
+ )
29
+ content_object = GenericForeignKey("content_type", "object_pk")
30
+ groups = models.ManyToManyField(
31
+ Group,
32
+ verbose_name=_("groups"),
33
+ blank=True,
34
+ help_text=_(
35
+ "The groups this user context belongs to. A user will get all permissions "
36
+ "granted to each of their groups."
37
+ ),
38
+ related_name="context",
39
+ related_query_name="context",
40
+ )
41
+ user_permissions = models.ManyToManyField(
42
+ Permission,
43
+ verbose_name=_("user context permissions"),
44
+ blank=True,
45
+ help_text=_("Specific permissions for this user context."),
46
+ related_name="context",
47
+ related_query_name="context",
48
+ )
@@ -0,0 +1,134 @@
1
+ import typing
2
+ import logging
3
+ from django.db import models
4
+ from django.contrib.auth import get_user_model
5
+ from django.contrib.auth.models import Permission
6
+
7
+ import karrio.server.core.utils as utils
8
+ import karrio.server.user.models as users
9
+ import karrio.server.iam.serializers as serializers
10
+
11
+ logger = logging.getLogger(__name__)
12
+ User = get_user_model()
13
+
14
+
15
+ @utils.skip_on_loadata
16
+ @utils.async_wrapper
17
+ @utils.tenant_aware
18
+ def setup_groups(**_):
19
+ """This function create all standard group permissions if they don't exsist."""
20
+ print("> setting up permissions")
21
+
22
+ # manage_apps
23
+ setup_group(
24
+ serializers.PermissionGroup.manage_apps.name,
25
+ permissions=Permission.objects.filter(content_type__app_label="apps"),
26
+ )
27
+
28
+ # manage_carriers
29
+ setup_group(
30
+ serializers.PermissionGroup.manage_carriers.name,
31
+ permissions=[
32
+ *Permission.objects.filter(content_type__app_label="providers"),
33
+ *Permission.objects.filter(
34
+ models.Q(content_type__app_label="orgs")
35
+ & models.Q(name__icontains="carrier")
36
+ ),
37
+ ],
38
+ override=True,
39
+ )
40
+
41
+ # manage_orders
42
+ setup_group(
43
+ serializers.PermissionGroup.manage_orders.name,
44
+ permissions=Permission.objects.filter(content_type__app_label="orders"),
45
+ )
46
+
47
+ # manage_team
48
+ setup_group(
49
+ serializers.PermissionGroup.manage_team.name,
50
+ permissions=(
51
+ Permission.objects.filter(
52
+ content_type__app_label="orgs", name__icontains="organization"
53
+ ).exclude(name__icontains="owner")
54
+ ),
55
+ override=True,
56
+ )
57
+
58
+ # manage_org_owner
59
+ setup_group(
60
+ serializers.PermissionGroup.manage_org_owner.name,
61
+ permissions=Permission.objects.filter(
62
+ content_type__model="OrganizationOwner".lower()
63
+ ),
64
+ )
65
+
66
+ # manage_webhooks
67
+ setup_group(
68
+ serializers.PermissionGroup.manage_webhooks.name,
69
+ permissions=Permission.objects.filter(content_type__model="Webhook".lower()),
70
+ )
71
+
72
+ # manage_data
73
+ setup_group(
74
+ serializers.PermissionGroup.manage_data.name,
75
+ permissions=[
76
+ *Permission.objects.filter(
77
+ content_type__app_label__in=["data", "graph", "documents"]
78
+ ),
79
+ *Permission.objects.filter(
80
+ content_type__app_label="audit", name__icontains="view"
81
+ ),
82
+ *Permission.objects.filter(
83
+ content_type__app_label="rest_framework_tracking",
84
+ name__icontains="view",
85
+ ),
86
+ ],
87
+ override=True,
88
+ )
89
+
90
+ # manage_shipments
91
+ setup_group(
92
+ serializers.PermissionGroup.manage_shipments.name,
93
+ permissions=[
94
+ *Permission.objects.filter(content_type__app_label="manager"),
95
+ *Permission.objects.filter(
96
+ models.Q(content_type__app_label="orgs")
97
+ & (
98
+ models.Q(name__icontains="address")
99
+ | models.Q(name__icontains="parcel")
100
+ | models.Q(name__icontains="commodity")
101
+ | models.Q(name__icontains="customs")
102
+ | models.Q(name__icontains="pickup")
103
+ | models.Q(name__icontains="tracker")
104
+ | models.Q(name__icontains="shipment")
105
+ )
106
+ ),
107
+ ],
108
+ )
109
+
110
+ # manage_system
111
+ setup_group(
112
+ serializers.PermissionGroup.manage_system.name,
113
+ permissions=Permission.objects.filter(
114
+ content_type__app_label__in=[
115
+ "admin",
116
+ "user",
117
+ "pricing",
118
+ "providers",
119
+ "audit",
120
+ "database",
121
+ "rest_framework_tracking",
122
+ ]
123
+ ),
124
+ )
125
+
126
+
127
+ def setup_group(
128
+ name: str, permissions: typing.List[Permission], override: bool = False
129
+ ):
130
+ group, created = users.Group.objects.get_or_create(name=name)
131
+
132
+ if created or override:
133
+ group.permissions.set(permissions)
134
+ group.save()