karrio-server-core 2025.5__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.
- 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 +347 -0
- karrio/server/core/config.py +31 -0
- karrio/server/core/context_processors.py +12 -0
- karrio/server/core/datatypes.py +394 -0
- karrio/server/core/dataunits.py +187 -0
- karrio/server/core/exceptions.py +404 -0
- karrio/server/core/fields.py +12 -0
- karrio/server/core/filters.py +837 -0
- karrio/server/core/gateway.py +1011 -0
- karrio/server/core/logging.py +403 -0
- karrio/server/core/management/commands/cli.py +19 -0
- karrio/server/core/management/commands/create_oauth_client.py +41 -0
- karrio/server/core/management/commands/runserver.py +5 -0
- karrio/server/core/middleware.py +197 -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/0006_add_api_log_requested_at_index.py +22 -0
- karrio/server/core/migrations/__init__.py +0 -0
- karrio/server/core/models/__init__.py +48 -0
- karrio/server/core/models/base.py +103 -0
- karrio/server/core/models/entity.py +24 -0
- karrio/server/core/models/metafield.py +144 -0
- karrio/server/core/models/third_party.py +21 -0
- karrio/server/core/oauth_validators.py +170 -0
- karrio/server/core/permissions.py +36 -0
- karrio/server/core/renderers.py +11 -0
- karrio/server/core/router.py +3 -0
- karrio/server/core/serializers.py +1971 -0
- karrio/server/core/signals.py +55 -0
- karrio/server/core/telemetry.py +573 -0
- karrio/server/core/tests.py +99 -0
- karrio/server/core/tests_resource_token.py +411 -0
- karrio/server/core/urls.py +12 -0
- karrio/server/core/utils.py +1025 -0
- karrio/server/core/validators.py +264 -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 +75 -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 +155 -0
- karrio/server/iam/serializers.py +54 -0
- karrio/server/iam/signals.py +18 -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/management/commands/migrate_rate_sheets.py +101 -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/0082_add_zone_identifiers.py +50 -0
- karrio/server/providers/migrations/0083_add_optimized_rate_sheet_structure.py +33 -0
- karrio/server/providers/migrations/0084_alter_servicelevel_currency.py +168 -0
- karrio/server/providers/migrations/0085_populate_dhl_parcel_de_oauth_credentials.py +82 -0
- karrio/server/providers/migrations/0086_rename_dhl_parcel_de_customer_number_to_billing_number.py +71 -0
- karrio/server/providers/migrations/__init__.py +0 -0
- karrio/server/providers/models/__init__.py +16 -0
- karrio/server/providers/models/carrier.py +387 -0
- karrio/server/providers/models/config.py +30 -0
- karrio/server/providers/models/service.py +192 -0
- karrio/server/providers/models/sheet.py +287 -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 +538 -0
- karrio/server/providers/signals.py +25 -0
- karrio/server/providers/templates/providers/oauth_callback.html +105 -0
- karrio/server/providers/tests/__init__.py +5 -0
- karrio/server/providers/tests/test_connections.py +895 -0
- karrio/server/providers/urls.py +11 -0
- karrio/server/providers/views/__init__.py +0 -0
- karrio/server/providers/views/carriers.py +267 -0
- karrio/server/providers/views/connections.py +496 -0
- karrio/server/samples.py +352 -0
- karrio/server/serializers/__init__.py +2 -0
- karrio/server/serializers/abstract.py +602 -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/0007_tracingrecord_tracing_created_at_idx.py +19 -0
- karrio/server/tracing/migrations/__init__.py +0 -0
- karrio/server/tracing/models.py +82 -0
- karrio/server/tracing/tests.py +3 -0
- karrio/server/tracing/utils.py +109 -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/0007_user_metadata.py +25 -0
- karrio/server/user/migrations/__init__.py +0 -0
- karrio/server/user/models.py +218 -0
- karrio/server/user/serializers.py +47 -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.5.dist-info/METADATA +32 -0
- karrio_server_core-2025.5.dist-info/RECORD +213 -0
- karrio_server_core-2025.5.dist-info/WHEEL +5 -0
- karrio_server_core-2025.5.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Generated by Django 3.2.14 on 2022-09-01 18:44
|
|
2
|
+
|
|
3
|
+
import django.contrib.auth.models
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
import django.db.models.deletion
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('auth', '0012_alter_user_first_name_max_length'),
|
|
12
|
+
('user', '0003_token_test_mode'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='Group',
|
|
18
|
+
fields=[
|
|
19
|
+
('group_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='auth.group')),
|
|
20
|
+
],
|
|
21
|
+
bases=('auth.group',),
|
|
22
|
+
managers=[
|
|
23
|
+
('objects', django.contrib.auth.models.GroupManager()),
|
|
24
|
+
],
|
|
25
|
+
),
|
|
26
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Generated by Django 5.0 on 2023-12-08 05:41
|
|
2
|
+
|
|
3
|
+
import django.utils.timezone
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
dependencies = [
|
|
9
|
+
("user", "0004_group"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name="token",
|
|
15
|
+
name="label",
|
|
16
|
+
field=models.CharField(
|
|
17
|
+
default=django.utils.timezone.now, max_length=50, verbose_name="label"
|
|
18
|
+
),
|
|
19
|
+
preserve_default=False,
|
|
20
|
+
),
|
|
21
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Generated by Django 4.2.10 on 2024-03-12 18:03
|
|
2
|
+
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
import django.db.models.deletion
|
|
6
|
+
import functools
|
|
7
|
+
import karrio.server.core.models
|
|
8
|
+
import karrio.server.core.models.base
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Migration(migrations.Migration):
|
|
12
|
+
|
|
13
|
+
dependencies = [
|
|
14
|
+
("user", "0005_token_label"),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
operations = [
|
|
18
|
+
migrations.CreateModel(
|
|
19
|
+
name="WorkspaceConfig",
|
|
20
|
+
fields=[
|
|
21
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
22
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
|
23
|
+
(
|
|
24
|
+
"id",
|
|
25
|
+
models.CharField(
|
|
26
|
+
default=functools.partial(
|
|
27
|
+
karrio.server.core.models.base.uuid,
|
|
28
|
+
*(),
|
|
29
|
+
**{"prefix": "wcfg_"}
|
|
30
|
+
),
|
|
31
|
+
editable=False,
|
|
32
|
+
max_length=50,
|
|
33
|
+
primary_key=True,
|
|
34
|
+
serialize=False,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
(
|
|
38
|
+
"config",
|
|
39
|
+
models.JSONField(
|
|
40
|
+
default=functools.partial(
|
|
41
|
+
karrio.server.core.models._identity, *(), **{"value": {}}
|
|
42
|
+
)
|
|
43
|
+
),
|
|
44
|
+
),
|
|
45
|
+
(
|
|
46
|
+
"created_by",
|
|
47
|
+
models.ForeignKey(
|
|
48
|
+
blank=True,
|
|
49
|
+
editable=False,
|
|
50
|
+
null=True,
|
|
51
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
52
|
+
to=settings.AUTH_USER_MODEL,
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
],
|
|
56
|
+
options={
|
|
57
|
+
"verbose_name": "Workspace Config",
|
|
58
|
+
"verbose_name_plural": "Workspace Configs",
|
|
59
|
+
"db_table": "workspace-config",
|
|
60
|
+
},
|
|
61
|
+
bases=(karrio.server.core.models.base.ControlledAccessModel, models.Model),
|
|
62
|
+
),
|
|
63
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated by Django 5.2.7 on 2025-10-14 01:00
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import karrio.server.core.models
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
("user", "0006_workspaceconfig"),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.AddField(
|
|
16
|
+
model_name="user",
|
|
17
|
+
name="metadata",
|
|
18
|
+
field=models.JSONField(
|
|
19
|
+
default=functools.partial(
|
|
20
|
+
karrio.server.core.models._identity, *(), **{"value": {}}
|
|
21
|
+
),
|
|
22
|
+
help_text="User defined metadata",
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,218 @@
|
|
|
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
|
+
metadata = models.JSONField(
|
|
49
|
+
default=core.field_default({}), help_text="User defined metadata"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
USERNAME_FIELD = "email"
|
|
53
|
+
REQUIRED_FIELDS: list = []
|
|
54
|
+
|
|
55
|
+
objects = UserManager()
|
|
56
|
+
|
|
57
|
+
username = None
|
|
58
|
+
first_name = None
|
|
59
|
+
last_name = None
|
|
60
|
+
|
|
61
|
+
def __str__(self):
|
|
62
|
+
return self.email
|
|
63
|
+
|
|
64
|
+
def delete(self, *args, **kwargs):
|
|
65
|
+
self.tokens.all().delete()
|
|
66
|
+
super().delete(*args, **kwargs)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def object_type(self):
|
|
70
|
+
return "user"
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def permissions(self):
|
|
74
|
+
import karrio.server.conf as conf
|
|
75
|
+
import karrio.server.iam.models as iam
|
|
76
|
+
import karrio.server.core.middleware as middleware
|
|
77
|
+
from django.utils.functional import SimpleLazyObject
|
|
78
|
+
|
|
79
|
+
ctx = middleware.SessionContext.get_current_request()
|
|
80
|
+
|
|
81
|
+
# Helper to evaluate org safely
|
|
82
|
+
def get_org():
|
|
83
|
+
return (
|
|
84
|
+
None if not all([
|
|
85
|
+
conf.settings.MULTI_ORGANIZATIONS,
|
|
86
|
+
ctx is not None,
|
|
87
|
+
hasattr(ctx, "org"),
|
|
88
|
+
ctx.org is not None,
|
|
89
|
+
]) else (
|
|
90
|
+
ctx.org if not isinstance(ctx.org, SimpleLazyObject)
|
|
91
|
+
else (ctx.org if ctx.org else None)
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Helper to get context permissions
|
|
96
|
+
def get_context_perms():
|
|
97
|
+
org = get_org()
|
|
98
|
+
org_user = org.organization_users.filter(user_id=self.pk).first() if org else None
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
context_permission = iam.ContextPermission.objects.get(
|
|
102
|
+
object_pk=org_user.pk,
|
|
103
|
+
content_type=ContentType.objects.get_for_model(org_user),
|
|
104
|
+
) if org_user else None
|
|
105
|
+
|
|
106
|
+
return list(context_permission.groups.all().values_list("name", flat=True)) if context_permission else []
|
|
107
|
+
except iam.ContextPermission.DoesNotExist:
|
|
108
|
+
return []
|
|
109
|
+
|
|
110
|
+
# Functional chain of permission resolution
|
|
111
|
+
_permissions = get_context_perms() or list(self.groups.all().values_list("name", flat=True))
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
list(Group.objects.all().values_list("name", flat=True)) if self.is_superuser and not _permissions
|
|
115
|
+
else list(Group.objects.exclude(name__in=["manage_system", "manage_team", "manage_org_owner"]).values_list("name", flat=True)) if self.is_staff and not _permissions
|
|
116
|
+
else _permissions
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@core.register_model
|
|
121
|
+
class Token(authtoken.Token, core.ControlledAccessModel):
|
|
122
|
+
label = models.CharField(_("label"), max_length=50)
|
|
123
|
+
user = models.ForeignKey(
|
|
124
|
+
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="tokens"
|
|
125
|
+
)
|
|
126
|
+
test_mode = models.BooleanField(null=False, default=core.field_default(False))
|
|
127
|
+
|
|
128
|
+
class Meta:
|
|
129
|
+
verbose_name = _("Token")
|
|
130
|
+
verbose_name_plural = _("Tokens")
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def pk(self):
|
|
134
|
+
return self.key
|
|
135
|
+
|
|
136
|
+
@classmethod
|
|
137
|
+
def generate_key(cls):
|
|
138
|
+
return f"key_{binascii.hexlify(os.urandom(16)).decode()}"
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def organization(self):
|
|
142
|
+
return self.org.first() if hasattr(self, "org") else None
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def object_type(self):
|
|
146
|
+
return "token"
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def permissions(self):
|
|
150
|
+
import karrio.server.conf as conf
|
|
151
|
+
import karrio.server.iam.models as iam
|
|
152
|
+
|
|
153
|
+
_permissions = []
|
|
154
|
+
|
|
155
|
+
if iam.ContextPermission.objects.filter(object_pk=self.pk).exists():
|
|
156
|
+
_permissions = (
|
|
157
|
+
iam.ContextPermission.objects.get(
|
|
158
|
+
object_pk=self.pk,
|
|
159
|
+
content_type=ContentType.objects.get_for_model(Token),
|
|
160
|
+
)
|
|
161
|
+
.groups.all()
|
|
162
|
+
.values_list("name", flat=True)
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
not any(_permissions)
|
|
167
|
+
and conf.settings.MULTI_ORGANIZATIONS
|
|
168
|
+
and self.org.exists()
|
|
169
|
+
):
|
|
170
|
+
org_user = self.org.first().organization_users.filter(user_id=self.user_id)
|
|
171
|
+
_permissions = (
|
|
172
|
+
iam.ContextPermission.objects.get(
|
|
173
|
+
object_pk=org_user.first().pk,
|
|
174
|
+
content_type=ContentType.objects.get_for_model(org_user.first()),
|
|
175
|
+
)
|
|
176
|
+
.groups.all()
|
|
177
|
+
.values_list("name", flat=True)
|
|
178
|
+
if org_user.exists()
|
|
179
|
+
else []
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return _permissions if any(_permissions) else self.user.permissions
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@core.register_model
|
|
186
|
+
class Group(auth.Group):
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@core.register_model
|
|
191
|
+
class WorkspaceConfig(core.OwnedEntity):
|
|
192
|
+
class Meta:
|
|
193
|
+
db_table = "workspace-config"
|
|
194
|
+
verbose_name = "Workspace Config"
|
|
195
|
+
verbose_name_plural = "Workspace Configs"
|
|
196
|
+
|
|
197
|
+
id = models.CharField(
|
|
198
|
+
max_length=50,
|
|
199
|
+
editable=False,
|
|
200
|
+
primary_key=True,
|
|
201
|
+
default=functools.partial(core.uuid, prefix="wcfg_"),
|
|
202
|
+
)
|
|
203
|
+
config = models.JSONField(
|
|
204
|
+
null=False,
|
|
205
|
+
blank=False,
|
|
206
|
+
default=core.field_default({}),
|
|
207
|
+
)
|
|
208
|
+
created_by = models.ForeignKey(
|
|
209
|
+
User,
|
|
210
|
+
blank=True,
|
|
211
|
+
null=True,
|
|
212
|
+
on_delete=models.CASCADE,
|
|
213
|
+
editable=False,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def object_type(self):
|
|
218
|
+
return "workspace-config"
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
# Handle multi-organization mode
|
|
36
|
+
if org_id is not None and conf.settings.MULTI_ORGANIZATIONS:
|
|
37
|
+
import karrio.server.orgs.models as orgs
|
|
38
|
+
|
|
39
|
+
org = orgs.Organization.objects.get(id=org_id, users__id=context.user.id)
|
|
40
|
+
|
|
41
|
+
ctx = serializers.Context(
|
|
42
|
+
org=org,
|
|
43
|
+
user=getattr(context, "user", None),
|
|
44
|
+
test_mode=getattr(context, "test_mode", None),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
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
|
+
<p><a href="{{ link }}">{{ link }}</a></p>
|
|
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.5
|
|
4
|
+
Summary: Multi-carrier shipping API Core module
|
|
5
|
+
Author-email: karrio <hello@karrio.io>
|
|
6
|
+
License-Expression: LGPL-3.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.
|