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.
- karrio/server/conf.py +54 -0
- karrio/server/core/__init__.py +3 -0
- karrio/server/core/admin.py +1 -0
- karrio/server/core/apps.py +10 -0
- karrio/server/core/authentication.py +313 -0
- karrio/server/core/context_processors.py +12 -0
- karrio/server/core/datatypes.py +369 -0
- karrio/server/core/dataunits.py +156 -0
- karrio/server/core/exceptions.py +200 -0
- karrio/server/core/fields.py +12 -0
- karrio/server/core/filters.py +823 -0
- karrio/server/core/gateway.py +720 -0
- karrio/server/core/management/commands/cli.py +19 -0
- karrio/server/core/management/commands/create_oauth_client.py +41 -0
- karrio/server/core/middleware.py +95 -0
- karrio/server/core/migrations/0001_initial.py +28 -0
- karrio/server/core/migrations/0002_apilogindex.py +69 -0
- karrio/server/core/migrations/0003_apilogindex_test_mode.py +62 -0
- karrio/server/core/migrations/0004_metafield.py +74 -0
- karrio/server/core/migrations/0005_alter_metafield_type_alter_metafield_value.py +23 -0
- karrio/server/core/migrations/__init__.py +0 -0
- karrio/server/core/models/__init__.py +48 -0
- karrio/server/core/models/base.py +70 -0
- karrio/server/core/models/entity.py +22 -0
- karrio/server/core/models/metafield.py +144 -0
- karrio/server/core/models/third_party.py +21 -0
- karrio/server/core/oauth_validators.py +171 -0
- karrio/server/core/permissions.py +37 -0
- karrio/server/core/renderers.py +11 -0
- karrio/server/core/router.py +3 -0
- karrio/server/core/serializers.py +1898 -0
- karrio/server/core/signals.py +57 -0
- karrio/server/core/tests.py +98 -0
- karrio/server/core/urls.py +12 -0
- karrio/server/core/utils.py +479 -0
- karrio/server/core/validators.py +416 -0
- karrio/server/core/views/__init__.py +2 -0
- karrio/server/core/views/api.py +133 -0
- karrio/server/core/views/metadata.py +44 -0
- karrio/server/core/views/oauth.py +74 -0
- karrio/server/core/views/references.py +82 -0
- karrio/server/core/views/schema.py +310 -0
- karrio/server/filters/__init__.py +2 -0
- karrio/server/filters/abstract.py +26 -0
- karrio/server/iam/__init__.py +0 -0
- karrio/server/iam/admin.py +3 -0
- karrio/server/iam/apps.py +21 -0
- karrio/server/iam/migrations/0001_initial.py +33 -0
- karrio/server/iam/migrations/__init__.py +0 -0
- karrio/server/iam/models.py +48 -0
- karrio/server/iam/permissions.py +134 -0
- karrio/server/iam/serializers.py +39 -0
- karrio/server/iam/signals.py +20 -0
- karrio/server/iam/tests.py +3 -0
- karrio/server/iam/views.py +3 -0
- karrio/server/openapi.py +75 -0
- karrio/server/providers/__init__.py +1 -0
- karrio/server/providers/admin.py +364 -0
- karrio/server/providers/apps.py +10 -0
- karrio/server/providers/extension/__init__.py +1 -0
- karrio/server/providers/extension/models/__init__.py +1 -0
- karrio/server/providers/extension/models/allied_express.py +22 -0
- karrio/server/providers/extension/models/allied_express_local.py +22 -0
- karrio/server/providers/extension/models/amazon_shipping.py +27 -0
- karrio/server/providers/extension/models/aramex.py +25 -0
- karrio/server/providers/extension/models/asendia_us.py +21 -0
- karrio/server/providers/extension/models/australiapost.py +20 -0
- karrio/server/providers/extension/models/boxknight.py +19 -0
- karrio/server/providers/extension/models/bpost.py +21 -0
- karrio/server/providers/extension/models/canadapost.py +21 -0
- karrio/server/providers/extension/models/canpar.py +19 -0
- karrio/server/providers/extension/models/chronopost.py +22 -0
- karrio/server/providers/extension/models/colissimo.py +22 -0
- karrio/server/providers/extension/models/dhl_express.py +23 -0
- karrio/server/providers/extension/models/dhl_parcel_de.py +25 -0
- karrio/server/providers/extension/models/dhl_poland.py +22 -0
- karrio/server/providers/extension/models/dhl_universal.py +19 -0
- karrio/server/providers/extension/models/dicom.py +20 -0
- karrio/server/providers/extension/models/dpd.py +37 -0
- karrio/server/providers/extension/models/dpdhl.py +26 -0
- karrio/server/providers/extension/models/easypost.py +20 -0
- karrio/server/providers/extension/models/eshipper.py +21 -0
- karrio/server/providers/extension/models/fedex.py +25 -0
- karrio/server/providers/extension/models/fedex_ws.py +24 -0
- karrio/server/providers/extension/models/freightcom.py +21 -0
- karrio/server/providers/extension/models/generic.py +35 -0
- karrio/server/providers/extension/models/geodis.py +22 -0
- karrio/server/providers/extension/models/hay_post.py +22 -0
- karrio/server/providers/extension/models/laposte.py +19 -0
- karrio/server/providers/extension/models/locate2u.py +22 -0
- karrio/server/providers/extension/models/nationex.py +22 -0
- karrio/server/providers/extension/models/purolator.py +21 -0
- karrio/server/providers/extension/models/roadie.py +18 -0
- karrio/server/providers/extension/models/royalmail.py +19 -0
- karrio/server/providers/extension/models/sendle.py +22 -0
- karrio/server/providers/extension/models/tge.py +63 -0
- karrio/server/providers/extension/models/tnt.py +23 -0
- karrio/server/providers/extension/models/ups.py +23 -0
- karrio/server/providers/extension/models/usps.py +23 -0
- karrio/server/providers/extension/models/usps_international.py +23 -0
- karrio/server/providers/extension/models/usps_wt.py +24 -0
- karrio/server/providers/extension/models/usps_wt_international.py +24 -0
- karrio/server/providers/extension/models/zoom2u.py +23 -0
- karrio/server/providers/migrations/0001_initial.py +140 -0
- karrio/server/providers/migrations/0002_carrier_active.py +18 -0
- karrio/server/providers/migrations/0003_auto_20201230_0820.py +24 -0
- karrio/server/providers/migrations/0004_auto_20210212_0554.py +178 -0
- karrio/server/providers/migrations/0005_auto_20210212_0555.py +18 -0
- karrio/server/providers/migrations/0006_australiapostsettings.py +29 -0
- karrio/server/providers/migrations/0007_auto_20210213_0206.py +21 -0
- karrio/server/providers/migrations/0008_auto_20210214_0409.py +30 -0
- karrio/server/providers/migrations/0009_auto_20210308_0302.py +18 -0
- karrio/server/providers/migrations/0010_auto_20210409_0852.py +32 -0
- karrio/server/providers/migrations/0011_auto_20210409_0853.py +21 -0
- karrio/server/providers/migrations/0012_alter_carrier_options.py +17 -0
- karrio/server/providers/migrations/0013_tntsettings.py +30 -0
- karrio/server/providers/migrations/0014_auto_20210612_1608.py +46 -0
- karrio/server/providers/migrations/0015_auto_20210615_1601.py +28 -0
- karrio/server/providers/migrations/0016_alter_purolatorsettings_user_token.py +18 -0
- karrio/server/providers/migrations/0017_auto_20210805_0359.py +1293 -0
- karrio/server/providers/migrations/0018_alter_fedexsettings_user_key.py +18 -0
- karrio/server/providers/migrations/0019_dhlpolandsettings_servicelevel.py +65 -0
- karrio/server/providers/migrations/0020_genericsettings_labeltemplate.py +52 -0
- karrio/server/providers/migrations/0021_auto_20211231_2353.py +40 -0
- karrio/server/providers/migrations/0022_carrier_metadata.py +18 -0
- karrio/server/providers/migrations/0023_auto_20220124_1916.py +27 -0
- karrio/server/providers/migrations/0024_alter_genericsettings_custom_carrier_name.py +19 -0
- karrio/server/providers/migrations/0025_alter_servicelevel_service_code.py +19 -0
- karrio/server/providers/migrations/0026_auto_20220208_0132.py +59 -0
- karrio/server/providers/migrations/0027_auto_20220304_1340.py +29 -0
- karrio/server/providers/migrations/0028_auto_20220323_1500.py +33 -0
- karrio/server/providers/migrations/0029_easypostsettings.py +27 -0
- karrio/server/providers/migrations/0030_amazonmwssettings.py +29 -0
- karrio/server/providers/migrations/0031_delete_amazonmwssettings.py +18 -0
- karrio/server/providers/migrations/0032_alter_carrier_test.py +18 -0
- karrio/server/providers/migrations/0033_auto_20220708_1350.py +22 -0
- karrio/server/providers/migrations/0034_amazonmwssettings_dpdhlsettings.py +47 -0
- karrio/server/providers/migrations/0035_alter_carrier_capabilities.py +43 -0
- karrio/server/providers/migrations/0036_upsfreightsettings.py +31 -0
- karrio/server/providers/migrations/0037_chronopostsettings.py +29 -0
- karrio/server/providers/migrations/0038_alter_genericsettings_label_template.py +19 -0
- karrio/server/providers/migrations/0039_auto_20220906_0612.py +23 -0
- karrio/server/providers/migrations/0040_dpdhlsettings_services.py +18 -0
- karrio/server/providers/migrations/0041_auto_20221105_0705.py +38 -0
- karrio/server/providers/migrations/0042_auto_20221215_1642.py +23 -0
- karrio/server/providers/migrations/0043_alter_genericsettings_account_number_and_more.py +39 -0
- karrio/server/providers/migrations/0044_carrier_carrier_capabilities.py +64 -0
- karrio/server/providers/migrations/0045_alter_carrier_active_alter_carrier_carrier_id.py +31 -0
- karrio/server/providers/migrations/0046_remove_dpdhlsettings_signature_and_more.py +41 -0
- karrio/server/providers/migrations/0047_dpdsettings.py +286 -0
- karrio/server/providers/migrations/0048_servicelevel_min_weight_servicelevel_transit_days_and_more.py +64 -0
- karrio/server/providers/migrations/0049_boxknightsettings_geodissettings_lapostesettings_and_more.py +156 -0
- karrio/server/providers/migrations/0050_carrier_is_system_alter_carrier_metadata_and_more.py +106 -0
- karrio/server/providers/migrations/0051_rename_username_upssettings_client_id_and_more.py +31 -0
- karrio/server/providers/migrations/0052_alter_upssettings_account_number_and_more.py +20 -0
- karrio/server/providers/migrations/0053_locate2usettings.py +281 -0
- karrio/server/providers/migrations/0054_zoom2usettings.py +280 -0
- karrio/server/providers/migrations/0055_rename_amazonmwssettings_amazonshippingsettings_and_more.py +44 -0
- karrio/server/providers/migrations/0056_asendiaussettings_geodissettings_code_client_and_more.py +75 -0
- karrio/server/providers/migrations/0057_alter_servicelevel_weight_unit_belgianpostsettings.py +51 -0
- karrio/server/providers/migrations/0058_alliedexpresssettings.py +38 -0
- karrio/server/providers/migrations/0059_ratesheet.py +81 -0
- karrio/server/providers/migrations/0060_belgianpostsettings_rate_sheet_and_more.py +73 -0
- karrio/server/providers/migrations/0061_alliedexpresssettings_service_type.py +17 -0
- karrio/server/providers/migrations/0062_sendlesettings_account_country_code.py +257 -0
- karrio/server/providers/migrations/0063_servicelevel_metadata.py +25 -0
- karrio/server/providers/migrations/0064_alliedexpresslocalsettings.py +43 -0
- karrio/server/providers/migrations/0065_servicelevel_carrier_service_code_and_more.py +66 -0
- karrio/server/providers/migrations/0066_rename_fedexsettings_fedexwssettings_and_more.py +28 -0
- karrio/server/providers/migrations/0067_fedexsettings.py +283 -0
- karrio/server/providers/migrations/0068_fedexsettings_track_api_key_and_more.py +38 -0
- karrio/server/providers/migrations/0069_alter_canadapostsettings_contract_id_and_more.py +23 -0
- karrio/server/providers/migrations/0070_tgesettings_alter_carrier_capabilities.py +65 -0
- karrio/server/providers/migrations/0071_alter_tgesettings_my_toll_token.py +18 -0
- karrio/server/providers/migrations/0072_rename_eshippersettings_eshipperxmlsettings_and_more.py +28 -0
- karrio/server/providers/migrations/0073_delete_eshipperxmlsettings.py +41 -0
- karrio/server/providers/migrations/0074_eshippersettings.py +38 -0
- karrio/server/providers/migrations/0075_haypostsettings.py +40 -0
- karrio/server/providers/migrations/0076_rename_customer_registration_id_uspsinternationalsettings_account_number_and_more.py +125 -0
- karrio/server/providers/migrations/0077_uspswtinternationalsettings_uspswtsettings_and_more.py +165 -0
- karrio/server/providers/migrations/0078_auto_20240813_1552.py +120 -0
- karrio/server/providers/migrations/0079_alter_carrier_options_alter_ratesheet_created_by.py +31 -0
- karrio/server/providers/migrations/0080_alter_aramexsettings_account_country_code_and_more.py +3025 -0
- karrio/server/providers/migrations/0081_remove_alliedexpresssettings_carrier_ptr_and_more.py +338 -0
- karrio/server/providers/migrations/__init__.py +0 -0
- karrio/server/providers/models/__init__.py +17 -0
- karrio/server/providers/models/carrier.py +309 -0
- karrio/server/providers/models/config.py +30 -0
- karrio/server/providers/models/service.py +62 -0
- karrio/server/providers/models/sheet.py +60 -0
- karrio/server/providers/models/template.py +39 -0
- karrio/server/providers/models/utils.py +58 -0
- karrio/server/providers/router.py +3 -0
- karrio/server/providers/serializers/__init__.py +3 -0
- karrio/server/providers/serializers/base.py +277 -0
- karrio/server/providers/signals.py +27 -0
- karrio/server/providers/tests.py +3 -0
- karrio/server/providers/urls.py +11 -0
- karrio/server/providers/views/__init__.py +0 -0
- karrio/server/providers/views/carriers.py +269 -0
- karrio/server/providers/views/connections.py +176 -0
- karrio/server/samples.py +352 -0
- karrio/server/serializers/__init__.py +2 -0
- karrio/server/serializers/abstract.py +506 -0
- karrio/server/tracing/__init__.py +0 -0
- karrio/server/tracing/admin.py +63 -0
- karrio/server/tracing/apps.py +8 -0
- karrio/server/tracing/migrations/0001_initial.py +41 -0
- karrio/server/tracing/migrations/0002_auto_20220710_1307.py +22 -0
- karrio/server/tracing/migrations/0003_auto_20221105_0317.py +43 -0
- karrio/server/tracing/migrations/0004_tracingrecord_carrier_account_idx.py +24 -0
- karrio/server/tracing/migrations/0005_optimise_tracingrecord_request_log_idx.py +25 -0
- karrio/server/tracing/migrations/0006_alter_tracingrecord_options_and_more.py +49 -0
- karrio/server/tracing/migrations/__init__.py +0 -0
- karrio/server/tracing/models.py +80 -0
- karrio/server/tracing/tests.py +3 -0
- karrio/server/tracing/utils.py +112 -0
- karrio/server/user/__init__.py +0 -0
- karrio/server/user/admin.py +96 -0
- karrio/server/user/apps.py +7 -0
- karrio/server/user/forms.py +35 -0
- karrio/server/user/migrations/0001_initial.py +41 -0
- karrio/server/user/migrations/0002_token.py +29 -0
- karrio/server/user/migrations/0003_token_test_mode.py +20 -0
- karrio/server/user/migrations/0004_group.py +26 -0
- karrio/server/user/migrations/0005_token_label.py +21 -0
- karrio/server/user/migrations/0006_workspaceconfig.py +63 -0
- karrio/server/user/migrations/__init__.py +0 -0
- karrio/server/user/models.py +203 -0
- karrio/server/user/serializers.py +46 -0
- karrio/server/user/templates/registration/login.html +108 -0
- karrio/server/user/templates/registration/registration_confirm_email.html +10 -0
- karrio/server/user/templates/registration/registration_confirm_email.txt +3 -0
- karrio/server/user/tests.py +3 -0
- karrio/server/user/urls.py +10 -0
- karrio/server/user/utils.py +60 -0
- karrio/server/user/views.py +9 -0
- karrio_server_core-2025.5rc1.dist-info/METADATA +32 -0
- karrio_server_core-2025.5rc1.dist-info/RECORD +241 -0
- karrio_server_core-2025.5rc1.dist-info/WHEEL +5 -0
- 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,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,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.
|