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,203 @@
1
+ import os
2
+ import binascii
3
+ import functools
4
+ from django.db import models
5
+ from django.conf import settings
6
+ from django.contrib.auth import models as auth
7
+ from rest_framework.authtoken import models as authtoken
8
+ from django.contrib.contenttypes.models import ContentType
9
+ from django.utils.translation import gettext_lazy as _
10
+
11
+ import karrio.server.core.models as core
12
+
13
+
14
+ class UserManager(auth.UserManager):
15
+ def _create_user(self, email, password, **extra_fields):
16
+ """
17
+ Create and save a user with the given username, email, and password.
18
+ """
19
+ if not email:
20
+ raise ValueError("The given email must be set")
21
+ email = self.normalize_email(email)
22
+ user = self.model(email=email, **extra_fields)
23
+ user.set_password(password)
24
+ user.save(using=self._db)
25
+ return user
26
+
27
+ def create_user(self, email, password=None, **extra_fields):
28
+ extra_fields.setdefault("is_staff", False)
29
+ extra_fields.setdefault("is_superuser", False)
30
+ return self._create_user(email, password, **extra_fields)
31
+
32
+ def create_superuser(self, email, password=None, **extra_fields):
33
+ extra_fields.setdefault("is_staff", True)
34
+ extra_fields.setdefault("is_superuser", True)
35
+
36
+ if extra_fields.get("is_staff") is not True:
37
+ raise ValueError("Superuser must have is_staff=True.")
38
+ if extra_fields.get("is_superuser") is not True:
39
+ raise ValueError("Superuser must have is_superuser=True.")
40
+
41
+ return self._create_user(email, password, **extra_fields)
42
+
43
+
44
+ @core.register_model
45
+ class User(auth.AbstractUser):
46
+ full_name = models.CharField(_("full name"), max_length=150, blank=True)
47
+ email = models.EmailField(_("email address"), unique=True)
48
+
49
+ USERNAME_FIELD = "email"
50
+ REQUIRED_FIELDS: list = []
51
+
52
+ objects = UserManager()
53
+
54
+ username = None
55
+ first_name = None
56
+ last_name = None
57
+
58
+ def __str__(self):
59
+ return self.email
60
+
61
+ def delete(self, *args, **kwargs):
62
+ self.tokens.all().delete()
63
+ super().delete(*args, **kwargs)
64
+
65
+ @property
66
+ def object_type(self):
67
+ return "user"
68
+
69
+ @property
70
+ def permissions(self):
71
+ import karrio.server.conf as conf
72
+ import karrio.server.iam.models as iam
73
+ import karrio.server.core.middleware as middleware
74
+
75
+ ctx = middleware.SessionContext.get_current_request()
76
+ _permissions = []
77
+
78
+ if conf.settings.MULTI_ORGANIZATIONS and ctx.org is not None:
79
+ org_user = ctx.org.organization_users.filter(user_id=self.pk)
80
+ _permissions = (
81
+ iam.ContextPermission.objects.get(
82
+ object_pk=org_user.first().pk,
83
+ content_type=ContentType.objects.get_for_model(org_user.first()),
84
+ )
85
+ .groups.all()
86
+ .values_list("name", flat=True)
87
+ if org_user.exists()
88
+ else []
89
+ )
90
+
91
+ if not any(_permissions):
92
+ _permissions = self.groups.all().values_list("name", flat=True)
93
+
94
+ if not any(_permissions) and self.is_superuser:
95
+ return Group.objects.all().values_list("name", flat=True)
96
+
97
+ if not any(_permissions) and self.is_staff:
98
+ return Group.objects.exclude(
99
+ name__in=["manage_system", "manage_team", "manage_org_owner"]
100
+ ).values_list("name", flat=True)
101
+
102
+ return _permissions
103
+
104
+
105
+ @core.register_model
106
+ class Token(authtoken.Token, core.ControlledAccessModel):
107
+ label = models.CharField(_("label"), max_length=50)
108
+ user = models.ForeignKey(
109
+ settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="tokens"
110
+ )
111
+ test_mode = models.BooleanField(null=False, default=core.field_default(False))
112
+
113
+ class Meta:
114
+ verbose_name = _("Token")
115
+ verbose_name_plural = _("Tokens")
116
+
117
+ @property
118
+ def pk(self):
119
+ return self.key
120
+
121
+ @classmethod
122
+ def generate_key(cls):
123
+ return f"key_{binascii.hexlify(os.urandom(16)).decode()}"
124
+
125
+ @property
126
+ def organization(self):
127
+ return self.org.first() if hasattr(self, "org") else None
128
+
129
+ @property
130
+ def object_type(self):
131
+ return "token"
132
+
133
+ @property
134
+ def permissions(self):
135
+ import karrio.server.conf as conf
136
+ import karrio.server.iam.models as iam
137
+
138
+ _permissions = []
139
+
140
+ if iam.ContextPermission.objects.filter(object_pk=self.pk).exists():
141
+ _permissions = (
142
+ iam.ContextPermission.objects.get(
143
+ object_pk=self.pk,
144
+ content_type=ContentType.objects.get_for_model(Token),
145
+ )
146
+ .groups.all()
147
+ .values_list("name", flat=True)
148
+ )
149
+
150
+ if (
151
+ not any(_permissions)
152
+ and conf.settings.MULTI_ORGANIZATIONS
153
+ and self.org.exists()
154
+ ):
155
+ org_user = self.org.first().organization_users.filter(user_id=self.user_id)
156
+ _permissions = (
157
+ iam.ContextPermission.objects.get(
158
+ object_pk=org_user.first().pk,
159
+ content_type=ContentType.objects.get_for_model(org_user.first()),
160
+ )
161
+ .groups.all()
162
+ .values_list("name", flat=True)
163
+ if org_user.exists()
164
+ else []
165
+ )
166
+
167
+ return _permissions if any(_permissions) else self.user.permissions
168
+
169
+
170
+ @core.register_model
171
+ class Group(auth.Group):
172
+ pass
173
+
174
+
175
+ @core.register_model
176
+ class WorkspaceConfig(core.OwnedEntity):
177
+ class Meta:
178
+ db_table = "workspace-config"
179
+ verbose_name = "Workspace Config"
180
+ verbose_name_plural = "Workspace Configs"
181
+
182
+ id = models.CharField(
183
+ max_length=50,
184
+ editable=False,
185
+ primary_key=True,
186
+ default=functools.partial(core.uuid, prefix="wcfg_"),
187
+ )
188
+ config = models.JSONField(
189
+ null=False,
190
+ blank=False,
191
+ default=core.field_default({}),
192
+ )
193
+ created_by = models.ForeignKey(
194
+ User,
195
+ blank=True,
196
+ null=True,
197
+ on_delete=models.CASCADE,
198
+ editable=False,
199
+ )
200
+
201
+ @property
202
+ def object_type(self):
203
+ return "workspace-config"
@@ -0,0 +1,46 @@
1
+ import karrio.server.conf as conf
2
+ import karrio.server.user.models as models
3
+ import karrio.server.serializers as serializers
4
+
5
+
6
+ @serializers.owned_model_serializer
7
+ class TokenSerializer(serializers.Serializer):
8
+ label = serializers.CharField(required=False)
9
+
10
+ def create(
11
+ self, validated_data: dict, context: serializers.Context
12
+ ) -> models.Token:
13
+ return models.Token.objects.create(
14
+ user=context.user,
15
+ test_mode=context.test_mode,
16
+ label=validated_data.get("label") or "Default API Key",
17
+ )
18
+
19
+ @staticmethod
20
+ def retrieve_token(context, org_id: str = None):
21
+ org = getattr(context, "org", None)
22
+ org_id = org_id or getattr(org, "id", None)
23
+
24
+ queyset = models.Token.objects.filter(
25
+ **{
26
+ "test_mode": getattr(context, "test_mode", None),
27
+ "user__id": getattr(getattr(context, "user", None), "id", None),
28
+ **({"org__id": org_id} if org_id is not None else {}),
29
+ }
30
+ )
31
+
32
+ if queyset.exists():
33
+ return queyset.first()
34
+
35
+ if org_id is not None and conf.settings.MULTI_ORGANIZATIONS:
36
+ import karrio.server.orgs.models as orgs
37
+
38
+ org = orgs.Organization.objects.get(id=org_id, users__id=context.user.id)
39
+
40
+ ctx = serializers.Context(
41
+ org=org,
42
+ user=getattr(context, "user", None),
43
+ test_mode=getattr(context, "test_mode", None),
44
+ )
45
+
46
+ return TokenSerializer.map(data={}, context=ctx).save().instance
@@ -0,0 +1,108 @@
1
+ {% extends "admin/base_site.html" %}
2
+ {% load i18n static %}
3
+
4
+ {% block extrastyle %}
5
+ {{ block.super }}
6
+ <link rel="stylesheet" type="text/css" href="{% static "css/login.css" %}">
7
+ {{ form.media }}
8
+ {% endblock %}
9
+
10
+
11
+ {% block bodyclass %}{{ block.super }} login{% endblock %}
12
+
13
+ {% block usertools %}{% endblock %}
14
+
15
+ {% block nav-global %}{% endblock %}
16
+
17
+ {% block nav-sidebar %}{% endblock %}
18
+
19
+ {% block content_title %}{% endblock %}
20
+
21
+ {% block breadcrumbs %}{% endblock %}
22
+
23
+ {% block content %}
24
+ <div id="content-main">
25
+
26
+ {% if wizard.steps.current == 'token' %}
27
+ {% if device.method == 'call' %}
28
+ <p>{% blocktrans trimmed %}We are calling your phone right now, please enter the
29
+ digits you hear.{% endblocktrans %}</p>
30
+ {% elif device.method == 'sms' %}
31
+ <p>{% blocktrans trimmed %}We sent you a text message, please enter the tokens we
32
+ sent.{% endblocktrans %}</p>
33
+ {% else %}
34
+ <p>{% blocktrans trimmed %}Please enter the tokens generated by your token
35
+ generator.{% endblocktrans %}</p>
36
+ {% endif %}
37
+ {% elif wizard.steps.current == 'backup' %}
38
+ <p>{% blocktrans trimmed %}Use this form for entering backup tokens for logging in.
39
+ These tokens have been generated for you to print and keep safe. Please
40
+ enter one of these backup tokens to login to your account.{% endblocktrans %}</p>
41
+ {% endif %}
42
+
43
+ {% if form.errors and not form.non_field_errors %}
44
+ <p class="errornote">
45
+ {% if form.errors.items|length == 1 %}
46
+ {% translate "Please correct the error below." %}
47
+ {% else %}
48
+ {% translate "Please correct the errors below." %}
49
+ {% endif %}
50
+ </p>
51
+ {% endif %}
52
+ {% if form.non_field_errors %}
53
+ {% for error in form.non_field_errors %}
54
+ <p class="errornote">{{ error }}</p>
55
+ {% endfor %}
56
+ {% endif %}
57
+
58
+ <form action="" method="post" id="login-form">{% csrf_token %}
59
+ {{ wizard.management_form }}
60
+
61
+ {% if wizard.steps.current == 'auth' %}
62
+ <div class="form-row">
63
+ {{ form.username.errors }}
64
+ {{ form.username.label_tag }} {{ form.username }}
65
+ </div>
66
+ <div class="form-row">
67
+ {{ form.password.errors }}
68
+ {{ form.password.label_tag }} {{ form.password }}
69
+ </div>
70
+ <div class="submit-row">
71
+ <input type="submit" value="{% translate 'Log in' %}">
72
+ </div>
73
+ {% else %}
74
+ <div class="form-row">
75
+ {{ form.otp_token.errors }}
76
+ {{ form.otp_token.label_tag }} {{ form.otp_token }}
77
+ </div>
78
+
79
+ <div class="submit-row">
80
+ <input type="submit" value="{% translate 'Continue' %}">
81
+ </div>
82
+ {% endif %}
83
+
84
+ {% if other_devices %}
85
+ <p>{% trans "Or, alternatively, use one of your backup phones:" %}</p>
86
+ <p>
87
+ {% for other in other_devices %}
88
+ <button name="challenge_device" value="{{ other.persistent_id }}"
89
+ class="btn btn-secondary btn-block" type="submit">
90
+ {{ other.generate_challenge_button_title }}
91
+ </button>
92
+ {% endfor %}</p>
93
+ {% endif %}
94
+ {% if backup_tokens %}
95
+ <p>{% trans "As a last resort, you can use a backup token:" %}</p>
96
+ <p>
97
+ <button name="wizard_goto_step" type="submit" value="backup"
98
+ class="btn btn-secondary btn-block">{% trans "Use Backup Token" %}</button>
99
+ </p>
100
+ {% endif %}
101
+
102
+ <input type="hidden" name="next" value="{{ request.GET.next }}"/>
103
+ {# hidden submit button to enable [enter] key #}
104
+ <input type="submit" value="" style="display: none;" />
105
+ </form>
106
+ </div>
107
+ {% endblock %}
108
+
@@ -0,0 +1,10 @@
1
+ {% load i18n %}{% autoescape off %}
2
+ {% block title %}Email confirmation{% endblock %}
3
+
4
+ <p>{% trans "You are almost there," %}</p>
5
+
6
+ <p>{% trans "Please click the following link to verify your email address." %}</p>
7
+
8
+ {{ link }}
9
+
10
+ {% endautoescape %}
@@ -0,0 +1,3 @@
1
+ You are almost there,
2
+ Please click the following link to verify your email address:
3
+ {{ link }}
@@ -0,0 +1,3 @@
1
+ from django.test import TestCase
2
+
3
+ # Create your tests here.
@@ -0,0 +1,10 @@
1
+ """
2
+ karrio server user module urls
3
+ """
4
+ from django.urls import include, path
5
+ from django_email_verification import urls as mail_urls
6
+
7
+ urlpatterns = [
8
+ path("email/", include(mail_urls)),
9
+ path("", include("karrio.server.user.views")),
10
+ ]
@@ -0,0 +1,60 @@
1
+ import datetime
2
+ from django_email_verification.token_utils import default_token_generator
3
+ from django_email_verification.confirm import (
4
+ Thread,
5
+ InvalidUserModel,
6
+ EmailMultiAlternatives,
7
+ _get_validated_field,
8
+ render_to_string,
9
+ )
10
+
11
+
12
+ def send_email(user, redirect_url, thread=True, expiry=None, **kwargs):
13
+ try:
14
+ user.save()
15
+
16
+ if kwargs.get("custom_salt"):
17
+ default_token_generator.key_salt = kwargs["custom_salt"]
18
+
19
+ _expiry = expiry or (datetime.datetime.now() + datetime.timedelta(days=30))
20
+ token, __expiry = default_token_generator.make_token(user, _expiry, kind="MAIL")
21
+
22
+ domain = redirect_url
23
+ sender = _get_validated_field("EMAIL_FROM_ADDRESS")
24
+ subject = _get_validated_field("EMAIL_MAIL_SUBJECT")
25
+ mail_plain = _get_validated_field("EMAIL_MAIL_PLAIN")
26
+ mail_html = _get_validated_field("EMAIL_MAIL_HTML")
27
+
28
+ args = (
29
+ user,
30
+ token,
31
+ __expiry,
32
+ sender,
33
+ domain,
34
+ subject,
35
+ mail_plain,
36
+ mail_html,
37
+ )
38
+ if thread:
39
+ t = Thread(target=send_email_thread, args=args)
40
+ t.start()
41
+ else:
42
+ send_email_thread(*args)
43
+ except AttributeError:
44
+ raise InvalidUserModel("The user model you provided is invalid")
45
+
46
+
47
+ def send_email_thread(
48
+ user, token, expiry, sender, domain, subject, mail_plain, mail_html
49
+ ):
50
+ domain += "/" if not domain.endswith("/") else ""
51
+ link = domain + token
52
+
53
+ context = {"link": link, "expiry": expiry, "user": user}
54
+
55
+ text = render_to_string(mail_plain, context)
56
+ html = render_to_string(mail_html, context)
57
+
58
+ msg = EmailMultiAlternatives(subject, text, sender, [user.email])
59
+ msg.attach_alternative(html, "text/html")
60
+ msg.send()
@@ -0,0 +1,9 @@
1
+ from django.urls import path
2
+ from two_factor.views import LoginView as BaseLoginView
3
+
4
+
5
+ class LoginView(BaseLoginView):
6
+ template_name = "registration/login.html"
7
+
8
+
9
+ urlpatterns = [path("login/", LoginView.as_view(), name="login")]
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: karrio_server_core
3
+ Version: 2025.5rc1
4
+ Summary: Multi-carrier shipping API Core module
5
+ Author-email: karrio <hello@karrio.io>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/karrioapi/karrio
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: karrio
12
+ Requires-Dist: psycopg2-binary
13
+ Requires-Dist: django-health-check
14
+ Requires-Dist: psutil
15
+ Requires-Dist: pyyaml
16
+ Requires-Dist: Jinja2
17
+
18
+ # karrio.server.core
19
+
20
+ This package is a module of the [karrio](https://pypi.org/project/karrio.server) universal shipping API.
21
+
22
+ ## Requirements
23
+
24
+ `Python 3.11+`
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install karrio.server.core
30
+ ```
31
+
32
+ Check the [karrio docs](https://docs.karrio.io) to get started.