karrio-server-graph 2025.5rc34__py3-none-any.whl → 2025.5rc36__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.
@@ -10,6 +10,7 @@ import karrio.server.graph.utils as utils
10
10
 
11
11
  @strawberry.input
12
12
  class LogFilter(utils.Paginated):
13
+ query: typing.Optional[str] = strawberry.UNSET
13
14
  api_endpoint: typing.Optional[str] = strawberry.UNSET
14
15
  remote_addr: typing.Optional[str] = strawberry.UNSET
15
16
  date_after: typing.Optional[datetime.datetime] = strawberry.UNSET
@@ -868,7 +868,7 @@ class CreateCarrierConnectionMutation(utils.BaseMutation):
868
868
  @staticmethod
869
869
  @utils.error_wrapper
870
870
  @utils.authentication_required
871
- @utils.authorization_required(["manage_carriers"])
871
+ @utils.authorization_required(["write_carriers"])
872
872
  def mutate(info: Info, **input) -> "CreateCarrierConnectionMutation":
873
873
  data = input.copy()
874
874
 
@@ -893,7 +893,7 @@ class UpdateCarrierConnectionMutation(utils.BaseMutation):
893
893
  @staticmethod
894
894
  @utils.error_wrapper
895
895
  @utils.authentication_required
896
- @utils.authorization_required(["manage_carriers"])
896
+ @utils.authorization_required(["write_carriers"])
897
897
  def mutate(info: Info, **input) -> "UpdateCarrierConnectionMutation":
898
898
  data = input.copy()
899
899
  id = data.get("id")
@@ -1067,7 +1067,6 @@ class PaymentType:
1067
1067
  paid_by: typing.Optional[utils.PaidByEnum] = None
1068
1068
  currency: typing.Optional[utils.CurrencyCodeEnum] = None
1069
1069
 
1070
-
1071
1070
  @strawberry.type
1072
1071
  class ShipmentType:
1073
1072
  id: str
@@ -1316,7 +1315,9 @@ class SystemConnectionType:
1316
1315
  _filter = filter if not utils.is_unset(filter) else inputs.CarrierFilter()
1317
1316
  connections = filters.CarrierFilters(
1318
1317
  _filter.to_dict(),
1319
- providers.Carrier.system_carriers.filter(
1318
+ providers.Carrier.system_carriers.resolve_config_for(
1319
+ info.context.request
1320
+ ).filter(
1320
1321
  active=True,
1321
1322
  test_mode=getattr(info.context.request, "test_mode", False),
1322
1323
  ),
@@ -1368,7 +1369,7 @@ class CarrierConnectionType:
1368
1369
  @staticmethod
1369
1370
  @utils.utils.error_wrapper
1370
1371
  @utils.authentication_required
1371
- @utils.authorization_required(["manage_carriers"])
1372
+ @utils.authorization_required(["read_carriers"])
1372
1373
  def resolve(
1373
1374
  info,
1374
1375
  id: str,
@@ -1381,7 +1382,7 @@ class CarrierConnectionType:
1381
1382
  @staticmethod
1382
1383
  @utils.utils.error_wrapper
1383
1384
  @utils.authentication_required
1384
- @utils.authorization_required(["manage_carriers"])
1385
+ @utils.authorization_required(["read_carriers"])
1385
1386
  def resolve_list(
1386
1387
  info,
1387
1388
  filter: typing.Optional[inputs.CarrierFilter] = strawberry.UNSET,
@@ -25,8 +25,28 @@ class GraphTestCase(BaseAPITestCase):
25
25
  self.user = get_user_model().objects.create_superuser(
26
26
  "admin@example.com", "test"
27
27
  )
28
+
28
29
  self.token = Token.objects.create(user=self.user, test_mode=False)
29
30
 
31
+ # Create organization for multi-org support (if enabled)
32
+ from django.conf import settings
33
+ if settings.MULTI_ORGANIZATIONS:
34
+ from karrio.server.orgs.models import Organization, TokenLink
35
+ self.organization = Organization.objects.create(
36
+ name="Test Organization",
37
+ slug="test-org"
38
+ )
39
+ # Add user as owner (triggers permission sync via signals)
40
+ owner = self.organization.add_user(self.user, is_admin=True)
41
+ self.organization.change_owner(owner)
42
+ self.organization.save()
43
+
44
+ # Link token to organization
45
+ TokenLink.objects.create(
46
+ item=self.token,
47
+ org=self.organization
48
+ )
49
+
30
50
  # Setup API client.
31
51
  self.client = APIClient()
32
52
  self.client.credentials(HTTP_AUTHORIZATION="Token " + self.token.key)
@@ -6,14 +6,14 @@ User = get_user_model()
6
6
 
7
7
 
8
8
  class TestUserRegistration(GraphTestCase):
9
-
10
- @patch('karrio.server.conf.settings.ALLOW_SIGNUP', True)
11
- @patch('karrio.server.conf.settings.EMAIL_ENABLED', False)
9
+
10
+ @patch("karrio.server.conf.settings.ALLOW_SIGNUP", True)
11
+ @patch("karrio.server.conf.settings.EMAIL_ENABLED", False)
12
12
  def test_register_user_mutation(self):
13
13
  """Test successful user registration"""
14
14
  # Ensure user doesn't exist
15
15
  User.objects.filter(email="newuser@example.com").delete()
16
-
16
+
17
17
  response = self.query(
18
18
  """
19
19
  mutation register_user($data: RegisterUserMutationInput!) {
@@ -33,21 +33,26 @@ class TestUserRegistration(GraphTestCase):
33
33
  "full_name": "New Test User",
34
34
  "password1": "TestPassword123!",
35
35
  "password2": "TestPassword123!",
36
- "redirect_url": "http://localhost:3000/email"
36
+ "redirect_url": "http://example.com/email",
37
37
  }
38
- }
38
+ },
39
39
  )
40
-
40
+
41
41
  self.assertResponseNoErrors(response)
42
- self.assertIsNotNone(response.data['data']['register_user']['user'])
43
- self.assertEqual(response.data['data']['register_user']['user']['email'], "newuser@example.com")
44
- self.assertEqual(response.data['data']['register_user']['user']['full_name'], "New Test User")
45
-
42
+ self.assertIsNotNone(response.data["data"]["register_user"]["user"])
43
+ self.assertEqual(
44
+ response.data["data"]["register_user"]["user"]["email"],
45
+ "newuser@example.com",
46
+ )
47
+ self.assertEqual(
48
+ response.data["data"]["register_user"]["user"]["full_name"], "New Test User"
49
+ )
50
+
46
51
  # Verify user was created in database
47
52
  user = User.objects.get(email="newuser@example.com")
48
53
  self.assertEqual(user.full_name, "New Test User")
49
-
50
- @patch('karrio.server.conf.settings.ALLOW_SIGNUP', True)
54
+
55
+ @patch("karrio.server.conf.settings.ALLOW_SIGNUP", True)
51
56
  def test_register_user_password_mismatch(self):
52
57
  """Test registration fails with mismatched passwords"""
53
58
  response = self.query(
@@ -67,25 +72,25 @@ class TestUserRegistration(GraphTestCase):
67
72
  "full_name": "Mismatch User",
68
73
  "password1": "TestPassword123!",
69
74
  "password2": "DifferentPassword123!",
70
- "redirect_url": "http://localhost:3000/email"
75
+ "redirect_url": "http://example.com/email",
71
76
  }
72
- }
77
+ },
73
78
  )
74
-
79
+
75
80
  # Should have errors
76
- self.assertIsNotNone(response.data.get('errors'))
77
- self.assertIn("password", str(response.data['errors'][0]))
78
-
79
- @patch('karrio.server.conf.settings.ALLOW_SIGNUP', True)
81
+ self.assertIsNotNone(response.data.get("errors"))
82
+ self.assertIn("password", str(response.data["errors"][0]))
83
+
84
+ @patch("karrio.server.conf.settings.ALLOW_SIGNUP", True)
80
85
  def test_register_user_duplicate_email(self):
81
86
  """Test registration fails with duplicate email"""
82
87
  # First create a user
83
88
  User.objects.create_user(
84
89
  email="existing@example.com",
85
90
  password="ExistingPass123!",
86
- full_name="Existing User"
91
+ full_name="Existing User",
87
92
  )
88
-
93
+
89
94
  response = self.query(
90
95
  """
91
96
  mutation register_user($data: RegisterUserMutationInput!) {
@@ -103,15 +108,15 @@ class TestUserRegistration(GraphTestCase):
103
108
  "full_name": "Duplicate User",
104
109
  "password1": "TestPassword123!",
105
110
  "password2": "TestPassword123!",
106
- "redirect_url": "http://localhost:3000/email"
111
+ "redirect_url": "http://example.com/email",
107
112
  }
108
- }
113
+ },
109
114
  )
110
-
115
+
111
116
  # Should have errors about duplicate email
112
- self.assertIsNotNone(response.data.get('errors'))
113
-
114
- @patch('karrio.server.conf.settings.ALLOW_SIGNUP', False)
117
+ self.assertIsNotNone(response.data.get("errors"))
118
+
119
+ @patch("karrio.server.conf.settings.ALLOW_SIGNUP", False)
115
120
  def test_register_user_signup_disabled(self):
116
121
  """Test registration fails when signup is disabled"""
117
122
  response = self.query(
@@ -131,28 +136,28 @@ class TestUserRegistration(GraphTestCase):
131
136
  "full_name": "Disabled User",
132
137
  "password1": "TestPassword123!",
133
138
  "password2": "TestPassword123!",
134
- "redirect_url": "http://localhost:3000/email"
139
+ "redirect_url": "http://example.com/email",
135
140
  }
136
- }
141
+ },
137
142
  )
138
-
143
+
139
144
  # Should have errors about signup not allowed
140
- self.assertIsNotNone(response.data.get('errors'))
141
- self.assertIn("Signup is not allowed", str(response.data['errors'][0]))
145
+ self.assertIsNotNone(response.data.get("errors"))
146
+ self.assertIn("Signup is not allowed", str(response.data["errors"][0]))
142
147
 
143
148
 
144
149
  class TestPasswordReset(GraphTestCase):
145
-
150
+
146
151
  def setUp(self):
147
152
  super().setUp()
148
153
  # Create a test user for password reset
149
154
  self.reset_user = User.objects.create_user(
150
155
  email="resetuser@example.com",
151
156
  password="OldPassword123!",
152
- full_name="Reset User"
157
+ full_name="Reset User",
153
158
  )
154
-
155
- @patch('django.core.mail.send_mail')
159
+
160
+ @patch("django.core.mail.send_mail")
156
161
  def test_request_password_reset(self, mock_send_mail):
157
162
  """Test requesting a password reset"""
158
163
  response = self.query(
@@ -168,22 +173,25 @@ class TestPasswordReset(GraphTestCase):
168
173
  variables={
169
174
  "data": {
170
175
  "email": "resetuser@example.com",
171
- "redirect_url": "http://localhost:3000/password/reset"
176
+ "redirect_url": "http://example.com/password/reset",
172
177
  }
173
- }
178
+ },
174
179
  )
175
-
180
+
176
181
  self.assertResponseNoErrors(response)
177
- self.assertEqual(response.data['data']['request_password_reset']['email'], "resetuser@example.com")
182
+ self.assertEqual(
183
+ response.data["data"]["request_password_reset"]["email"],
184
+ "resetuser@example.com",
185
+ )
178
186
 
179
187
 
180
188
  class TestEmailConfirmation(GraphTestCase):
181
-
182
- @patch('karrio.server.graph.schemas.base.mutations.email_verification.verify_token')
189
+
190
+ @patch("karrio.server.graph.schemas.base.mutations.email_verification.verify_token")
183
191
  def test_confirm_email(self, mock_verify):
184
192
  """Test email confirmation"""
185
193
  mock_verify.return_value = (True, None)
186
-
194
+
187
195
  response = self.query(
188
196
  """
189
197
  mutation confirm_email($data: ConfirmEmailMutationInput!) {
@@ -193,13 +201,9 @@ class TestEmailConfirmation(GraphTestCase):
193
201
  }
194
202
  """,
195
203
  operation_name="confirm_email",
196
- variables={
197
- "data": {
198
- "token": "test-confirmation-token"
199
- }
200
- }
204
+ variables={"data": {"token": "test-confirmation-token"}},
201
205
  )
202
-
206
+
203
207
  self.assertResponseNoErrors(response)
204
- self.assertTrue(response.data['data']['confirm_email']['success'])
205
- mock_verify.assert_called_once_with("test-confirmation-token")
208
+ self.assertTrue(response.data["data"]["confirm_email"]["success"])
209
+ mock_verify.assert_called_once_with("test-confirmation-token")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karrio_server_graph
3
- Version: 2025.5rc34
3
+ Version: 2025.5rc36
4
4
  Summary: Multi-carrier shipping API Graph module
5
5
  Author-email: karrio <hello@karrio.io>
6
6
  License-Expression: Apache-2.0
@@ -16,24 +16,24 @@ karrio/server/graph/migrations/0002_auto_20210512_1353.py,sha256=TnUwR9EP0qp3gJ3
16
16
  karrio/server/graph/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  karrio/server/graph/schemas/__init__.py,sha256=Kn-I1j3HP3jwZccpz6FL9r1k6b3UEAMVh2kFPCKNS0w,80
18
18
  karrio/server/graph/schemas/base/__init__.py,sha256=nnOfynQW842qOA0qD6bYz8GSHQCQeBW36vbq0sqRkJs,15121
19
- karrio/server/graph/schemas/base/inputs.py,sha256=QTnNwj8wmaeZrlE1sgIDFl_p2lwHG79j-GN1cJK9WQU,21368
20
- karrio/server/graph/schemas/base/mutations.py,sha256=Cc8xpix8LT5RmIhikNFf5RutQ2DTiOmKxqlQSRPgOiY,35045
21
- karrio/server/graph/schemas/base/types.py,sha256=G9oaksnqF6K1ml155AoRokuGpyvfg_33YUu_KUzLH-M,47547
19
+ karrio/server/graph/schemas/base/inputs.py,sha256=p6_u4sG1cbd18CpPjkyG3CD4cbvf4gBa3De4RDgCZ80,21419
20
+ karrio/server/graph/schemas/base/mutations.py,sha256=6ljP3_2UpUHpYIl06I7n-owQjUp2TT5jDgZ_fEzvB6o,35043
21
+ karrio/server/graph/schemas/base/types.py,sha256=FBayGYWlqcHK0tm43xFA6ZkUFlr1htM7-TutRKPmTkc,47613
22
22
  karrio/server/graph/templates/graphql/graphiql.html,sha256=MQjQbBqoRE0QLsOUck8SaXo6B2oJO8dT6YZzUqbDan0,3786
23
23
  karrio/server/graph/templates/karrio/email_change_email.html,sha256=gr55F97GYzY27TVKGl49037yd60eSYD0b0GXRlyoco4,552
24
24
  karrio/server/graph/templates/karrio/email_change_email.txt,sha256=NXXuzLR63hn2F1fVAjzmuguptuuTvujwqI7YLSrQoio,431
25
25
  karrio/server/graph/templates/karrio/password_reset_email.html,sha256=dttqYVL73cQNuTFsVdn2GV4Ckee8PTY8oEF53GbDRcg,553
26
26
  karrio/server/graph/tests/__init__.py,sha256=dPzsYY5hoO5gmY6fhL8tiz7Bfst8RB3JzsBVHZazHRE,338
27
- karrio/server/graph/tests/base.py,sha256=AlHWX5rRv7Ylz4OL7qcGTcSBQqalj6zDmagktkFavSg,4354
27
+ karrio/server/graph/tests/base.py,sha256=dzLiva3eTAsbBM5Ga8SI2fxSanBQgAqswS0YVdtTfEg,5122
28
28
  karrio/server/graph/tests/test_carrier_connections.py,sha256=qZ1OL8CgZrHuluKJd7cjFXaRZ0VpogN5Srjk2EApLWU,6892
29
29
  karrio/server/graph/tests/test_metafield.py,sha256=K7Oon0CLEm_MUMbmcu0t2iAZvFN8Wl7Kp4QAWeUXo_Y,12783
30
30
  karrio/server/graph/tests/test_partial_shipments.py,sha256=dPIdIq4wiyovOaIIzbIX69eZnBqCA4ZvBSiGKYADM2g,19031
31
31
  karrio/server/graph/tests/test_rate_sheets.py,sha256=cUzPV8dXQFPFh1r7W8bY6Lou3fjh8f9VGpyZrfbMXec,10300
32
- karrio/server/graph/tests/test_registration.py,sha256=jK8ZCmhtvKZ9L3yqSIK1-JXzYT2PWwxQ3Md1_ff9818,7192
32
+ karrio/server/graph/tests/test_registration.py,sha256=0vCTqlsLc0cl2m78umgfm7grnDgTI_NZJWNUrRUlQBY,7107
33
33
  karrio/server/graph/tests/test_templates.py,sha256=WVU6vcfr6tEk917uSn1dECU8bkQtgD7FNuE-GJuFido,21626
34
34
  karrio/server/graph/tests/test_user_info.py,sha256=K91BL7SgxLWflCZriSVI8Vt5M5RIqmSCHKrgN2w8GmM,1928
35
35
  karrio/server/settings/graph.py,sha256=cz2yQHbp3xCfyFKuUkPEFfkI2fFVggExIY49wGz7mt0,106
36
- karrio_server_graph-2025.5rc34.dist-info/METADATA,sha256=xFd0le0bef_XRWkn1FGyk1ovliVgFXSPjnb2Wr9A4Mo,744
37
- karrio_server_graph-2025.5rc34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- karrio_server_graph-2025.5rc34.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
39
- karrio_server_graph-2025.5rc34.dist-info/RECORD,,
36
+ karrio_server_graph-2025.5rc36.dist-info/METADATA,sha256=yn36YEqc52mn_0qvRKPzGOqZDH8H-q64jd4I-goLvgo,744
37
+ karrio_server_graph-2025.5rc36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ karrio_server_graph-2025.5rc36.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
39
+ karrio_server_graph-2025.5rc36.dist-info/RECORD,,