trovesuite 1.0.1__py3-none-any.whl → 1.0.31__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.
trovesuite/__init__.py CHANGED
@@ -1,16 +1,23 @@
1
1
  """
2
- TroveSuite Auth Package
2
+ TroveSuite Package
3
3
 
4
- A comprehensive authentication and authorization service for ERP systems.
5
- Provides JWT token validation, user authorization, and permission checking.
4
+ A comprehensive authentication, authorization, notification, and storage service for ERP systems.
5
+ Provides JWT token validation, user authorization, permission checking, notification capabilities,
6
+ Azure Storage blob management, and utility functions for multi-tenant applications.
6
7
  """
7
8
 
8
9
  from .auth import AuthService
10
+ from .notification import NotificationService
11
+ from .storage import StorageService
12
+ from .utils import Helper
9
13
 
10
- __version__ = "1.0.8"
14
+ __version__ = "1.0.29"
11
15
  __author__ = "Bright Debrah Owusu"
12
16
  __email__ = "owusu.debrah@deladetech.com"
13
17
 
14
18
  __all__ = [
15
- "AuthService"
19
+ "AuthService",
20
+ "NotificationService",
21
+ "StorageService",
22
+ "Helper",
16
23
  ]
@@ -5,13 +5,10 @@ Authentication and authorization services for ERP systems.
5
5
  """
6
6
 
7
7
  from .auth_service import AuthService
8
- from .auth_base import AuthBase
9
- from .auth_read_dto import AuthServiceReadDto, AuthControllerReadDto
8
+ from .auth_write_dto import AuthServiceWriteDto
10
9
 
11
10
  __all__ = [
12
11
  "AuthService",
13
- "AuthBase",
14
- "AuthServiceReadDto",
15
- "AuthControllerReadDto"
12
+ "AuthServiceWriteDto"
16
13
  ]
17
14
 
@@ -1,10 +1,11 @@
1
1
  from fastapi import APIRouter
2
- from src.trovesuite.auth.auth_write_dto import AuthControllerWriteDto
3
- from src.trovesuite.auth.auth_read_dto import AuthControllerReadDto
4
- from src.trovesuite.auth.auth_service import AuthService
2
+ from .auth_write_dto import AuthControllerWriteDto
3
+ from .auth_read_dto import AuthControllerReadDto
4
+ from .auth_service import AuthService
5
+ from ..entities.sh_response import Respons
5
6
 
6
- auth_router = APIRouter()
7
+ auth_router = APIRouter(tags=["Auth"])
7
8
 
8
- @auth_router.post("/auth", response_model=AuthControllerReadDto)
9
+ @auth_router.post("/auth", response_model=Respons[AuthControllerReadDto])
9
10
  async def authorize(data: AuthControllerWriteDto):
10
11
  return AuthService.authorize(data=data)
@@ -3,16 +3,16 @@ from pydantic import BaseModel
3
3
 
4
4
  class AuthControllerReadDto(BaseModel):
5
5
  org_id: Optional[str] = None
6
- bus_id: Optional[str] = None
7
- app_id: Optional[str] = None
6
+ bus_id: Optional[str] = None
7
+ app_id: Optional[str] = None
8
8
  shared_resource_id: Optional[str] = None
9
9
  user_id: Optional[str] = None
10
10
  group_id: Optional[str] = None
11
11
  role_id: Optional[str] = None
12
12
  tenant_id: Optional[str] = None
13
13
  permissions: Optional[List[str]] = None
14
- shared_resource_id: Optional[str] = None
15
14
  resource_id: Optional[str] = None
15
+ resource_type: Optional[str] = None
16
16
 
17
17
  class AuthServiceReadDto(AuthControllerReadDto):
18
18
  pass
@@ -45,7 +45,7 @@ class AuthService:
45
45
 
46
46
  @staticmethod
47
47
  def authorize(data: AuthServiceWriteDto) -> Respons[AuthServiceReadDto]:
48
-
48
+
49
49
  user_id: str = data.user_id
50
50
  tenant_id: str = data.tenant_id
51
51
 
@@ -59,7 +59,7 @@ class AuthService:
59
59
  status_code=400,
60
60
  error="INVALID_USER_ID"
61
61
  )
62
-
62
+
63
63
  if not tenant_id or not isinstance(tenant_id, str):
64
64
  return Respons[AuthServiceReadDto](
65
65
  detail="Invalid tenant_id: must be a non-empty string",
@@ -68,16 +68,16 @@ class AuthService:
68
68
  status_code=400,
69
69
  error="INVALID_TENANT_ID"
70
70
  )
71
-
71
+
72
72
  try:
73
73
 
74
74
  is_tenant_verified = DatabaseManager.execute_query(
75
- f"SELECT is_verified FROM {db_settings.MAIN_TENANTS_TABLE} WHERE delete_status = 'NOT_DELETED' AND id = %s",
75
+ f"SELECT is_verified FROM {db_settings.CORE_PLATFORM_TENANTS_TABLE} WHERE delete_status = 'NOT_DELETED' AND id = %s",
76
76
  (tenant_id,),
77
77
  )
78
78
 
79
79
  if not is_tenant_verified or len(is_tenant_verified) == 0:
80
- logger.warning("Login failed - tenant not found: %s", tenant_id)
80
+ logger.warning("Authorization failed - tenant not found: %s", tenant_id)
81
81
  return Respons[AuthServiceReadDto](
82
82
  detail=f"Tenant '{tenant_id}' not found or has been deleted",
83
83
  data=[],
@@ -85,9 +85,9 @@ class AuthService:
85
85
  status_code=404,
86
86
  error="TENANT_NOT_FOUND"
87
87
  )
88
-
88
+
89
89
  if not is_tenant_verified[0]['is_verified']:
90
- logger.warning("Login failed - tenant not verified for user: %s, tenant: %s", user_id, tenant_id)
90
+ logger.warning("Authorization failed - tenant not verified for user: %s, tenant: %s", user_id, tenant_id)
91
91
  return Respons[AuthServiceReadDto](
92
92
  detail=f"Tenant '{tenant_id}' is not verified. Please contact your administrator.",
93
93
  data=[],
@@ -96,14 +96,37 @@ class AuthService:
96
96
  error="TENANT_NOT_VERIFIED"
97
97
  )
98
98
 
99
- login_settings_details = DatabaseManager.execute_query(
100
- f"""SELECT user_id, group_id, is_suspended, can_always_login,
101
- is_multi_factor_enabled, is_login_before, working_days,
102
- login_on, logout_on FROM "{tenant_id}".{db_settings.TENANT_LOGIN_SETTINGS_TABLE}
103
- WHERE (delete_status = 'NOT_DELETED' AND is_active = true ) AND user_id = %s""",
104
- (user_id,),
99
+ # 1️⃣ Get all groups the user belongs to
100
+ user_groups = DatabaseManager.execute_query(
101
+ f"""SELECT group_id FROM {db_settings.CORE_PLATFORM_USER_GROUPS_TABLE}
102
+ WHERE tenant_id = %s AND delete_status = 'NOT_DELETED' AND is_active = true AND user_id = %s AND (is_system = false OR is_system IS NULL)""",
103
+ (tenant_id, user_id,),
105
104
  )
106
105
 
106
+ # 2️⃣ Prepare list of group_ids
107
+ group_ids = [g["group_id"] for g in user_groups] if user_groups else []
108
+
109
+ # 3️⃣ Get login settings - check user-level first, then group-level
110
+ if group_ids:
111
+ login_settings_details = DatabaseManager.execute_query(
112
+ f"""SELECT user_id, group_id, is_suspended, can_always_login,
113
+ is_multi_factor_enabled, is_login_before, working_days,
114
+ login_on, logout_on FROM {db_settings.CORE_PLATFORM_LOGIN_SETTINGS_TABLE}
115
+ WHERE tenant_id = %s AND (delete_status = 'NOT_DELETED' AND is_active = true )
116
+ AND (user_id = %s OR group_id = ANY(%s))
117
+ ORDER BY user_id NULLS LAST
118
+ LIMIT 1""",
119
+ (tenant_id, user_id, group_ids),
120
+ )
121
+ else:
122
+ login_settings_details = DatabaseManager.execute_query(
123
+ f"""SELECT user_id, group_id, is_suspended, can_always_login,
124
+ is_multi_factor_enabled, is_login_before, working_days,
125
+ login_on, logout_on FROM {db_settings.CORE_PLATFORM_LOGIN_SETTINGS_TABLE}
126
+ WHERE tenant_id = %s AND (delete_status = 'NOT_DELETED' AND is_active = true ) AND user_id = %s""",
127
+ (tenant_id, user_id,),
128
+ )
129
+
107
130
  if not login_settings_details or len(login_settings_details) == 0:
108
131
  logger.warning("Authorization failed - user not found: %s in tenant: %s", user_id, tenant_id)
109
132
  return Respons[AuthServiceReadDto](
@@ -124,86 +147,194 @@ class AuthService:
124
147
  error="USER_SUSPENDED"
125
148
  )
126
149
 
150
+ # ✅ UPDATED: Mutually exclusive login restrictions logic
127
151
  if not login_settings_details[0]['can_always_login']:
128
- current_day = datetime.now().strftime("%A").upper()
129
-
130
- if current_day not in login_settings_details[0]['working_days']:
131
- logger.warning("Authorization failed - outside working days for user: %s checking custom login period", user_id)
132
-
133
- # Get current datetime (full date and time) with timezone
134
- current_datetime = datetime.now(timezone.utc).replace(microsecond=0, second=0)
135
-
136
- # Get from database (should already be datetime objects)
137
- login_on = login_settings_details[0]['login_on']
138
- logout_on = login_settings_details[0]['logout_on']
152
+ # Get from database (should already be datetime objects)
153
+ login_on = login_settings_details[0]['login_on']
154
+ logout_on = login_settings_details[0]['logout_on']
155
+ working_days = login_settings_details[0]['working_days']
156
+
157
+ # Only ONE restriction type can be active at a time:
158
+ # 1. working_days restriction (if login_on/logout_on are NULL)
159
+ # 2. time period restriction (if login_on/logout_on are set)
160
+
161
+ if login_on and logout_on:
139
162
 
140
- # Set defaults if None (with timezone awareness)
141
- if not login_on:
142
- login_on = datetime.min.replace(tzinfo=timezone.utc)
143
- if not logout_on:
144
- logout_on = datetime.max.replace(tzinfo=timezone.utc)
163
+ # Time period restriction is active
164
+ logger.info(f"Checking time period restriction for user: {user_id}")
165
+
166
+ # Get current datetime (full date and time) with timezone
167
+ current_datetime = datetime.now(timezone.utc).replace(
168
+ microsecond=0, second=0
169
+ )
145
170
 
146
171
  # Compare full datetime objects (both date and time)
147
172
  if not (login_on <= current_datetime <= logout_on):
148
- logger.warning("Authorization failed - outside allowed period for user: %s", user_id)
173
+ logger.warning(
174
+ f"Authorization failed - outside allowed period for user: {user_id}"
175
+ )
149
176
  return Respons[AuthServiceReadDto](
150
- detail="Login is not allowed at this time. Please check your access schedule.",
177
+ detail="Access is not allowed at this time. Please check your access schedule.",
151
178
  data=[],
152
179
  success=False,
153
180
  status_code=403,
154
181
  error="LOGIN_TIME_RESTRICTED"
155
182
  )
156
-
157
- # 1️⃣ Get all groups the user belongs to
158
- user_groups = DatabaseManager.execute_query(
159
- f"""SELECT group_id FROM "{tenant_id}".{db_settings.USER_GROUPS_TABLE}
160
- WHERE delete_status = 'NOT_DELETED' AND is_active = true AND user_id = %s""",(user_id,),
161
- )
183
+ elif working_days:
184
+ # Working days restriction is active
185
+ logger.info(f"Checking working days restriction for user: {user_id}")
186
+ current_day = datetime.now().strftime("%A").upper()
162
187
 
163
- # 2️⃣ Prepare list of group_ids
164
- group_ids = [g["group_id"] for g in user_groups] if user_groups else []
188
+ if current_day not in working_days:
189
+ logger.warning(
190
+ f"Authorization failed - not a working day for user: {user_id}"
191
+ )
192
+ return Respons[AuthServiceReadDto](
193
+ detail="Access is not allowed on this day. Please contact your administrator.",
194
+ data=[],
195
+ success=False,
196
+ status_code=403,
197
+ error="LOGIN_DAY_RESTRICTED"
198
+ )
165
199
 
166
- # 3️⃣ Build query dynamically to include groups (if any) + user
200
+ # 4️⃣ Build query dynamically to include groups (if any) + user
201
+ # ⚠️ CHANGED: Simplified to new schema - only select user_id, group_id, role_id, resource_type
167
202
  if group_ids:
168
203
  get_user_roles = DatabaseManager.execute_query(
169
204
  f"""
170
- SELECT DISTINCT ON (org_id, group_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id)
171
- org_id, group_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id
172
- FROM "{tenant_id}".{db_settings.ASSIGN_ROLES_TABLE}
173
- WHERE delete_status = 'NOT_DELETED'
205
+ SELECT DISTINCT ON (group_id, user_id, role_id)
206
+ group_id, user_id, role_id, resource_type
207
+ FROM {db_settings.CORE_PLATFORM_ASSIGN_ROLES_TABLE}
208
+ WHERE tenant_id = %s AND delete_status = 'NOT_DELETED'
174
209
  AND is_active = true
210
+ AND (is_system = false OR is_system IS NULL)
175
211
  AND (user_id = %s OR group_id = ANY(%s))
176
- ORDER BY org_id, group_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id;
212
+ ORDER BY group_id, user_id, role_id;
177
213
  """,
178
- (user_id, group_ids),
214
+ (tenant_id, user_id, group_ids),
179
215
  )
180
216
  else:
181
217
  # No groups, just check roles for user
182
218
  get_user_roles = DatabaseManager.execute_query(
183
219
  f"""
184
- SELECT DISTINCT ON (org_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id)
185
- org_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id
186
- FROM "{tenant_id}".{db_settings.ASSIGN_ROLES_TABLE}
187
- WHERE delete_status = 'NOT_DELETED'
220
+ SELECT DISTINCT ON (user_id, role_id)
221
+ user_id, role_id, resource_type
222
+ FROM {db_settings.CORE_PLATFORM_ASSIGN_ROLES_TABLE}
223
+ WHERE tenant_id = %s AND delete_status = 'NOT_DELETED'
188
224
  AND is_active = true
225
+ AND (is_system = false OR is_system IS NULL)
189
226
  AND user_id = %s
190
- ORDER BY org_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id;
227
+ ORDER BY user_id, role_id;
191
228
  """,
192
- (user_id,),
229
+ (tenant_id, user_id,),
193
230
  )
194
231
 
232
+ # ✅ NEW: Get system-level roles from cp_assign_roles with is_system=true
233
+ # NOTE: system_groups, system_user_groups, and system_assign_roles are now consolidated
234
+ # into cp_groups, cp_user_groups, and cp_assign_roles with is_system flag
235
+ # Use LEFT JOIN starting from cp_assign_roles to find BOTH direct user assignments AND group-based assignments
236
+ logger.info(f"Fetching system-level roles for user: {user_id}")
237
+
238
+ system_roles = DatabaseManager.execute_query(
239
+ f"""
240
+ SELECT DISTINCT COALESCE(sar.group_id::TEXT, NULL) as group_id, sar.user_id, sar.role_id, sar.resource_type
241
+ FROM {db_settings.CORE_PLATFORM_ASSIGN_ROLES_TABLE} sar
242
+ LEFT JOIN {db_settings.CORE_PLATFORM_USER_GROUPS_TABLE} sug
243
+ ON sar.group_id = sug.group_id AND sar.tenant_id = sug.tenant_id
244
+ WHERE sar.tenant_id = 'system-tenant-id'
245
+ AND sar.is_system = true
246
+ AND sar.delete_status = 'NOT_DELETED'
247
+ AND sar.is_active = true
248
+ AND (sar.user_id = %s OR (sug.user_id = %s AND sug.tenant_id = 'system-tenant-id' AND sug.is_system = true AND sug.is_active = true AND sug.delete_status = 'NOT_DELETED'))
249
+ """,
250
+ (user_id, user_id)
251
+ )
252
+
253
+ if system_roles:
254
+ logger.info(f"Found {len(system_roles)} system-level role(s) for user: {user_id}")
255
+ else:
256
+ logger.info(f"No system-level roles found for user: {user_id}")
257
+
258
+ # ✅ NEW: Merge tenant-level and system-level roles
259
+ all_roles = get_user_roles + system_roles
260
+ logger.info(f"Total roles (tenant + system) for user {user_id}: {len(all_roles)}")
261
+
195
262
  # GET permissions and Append to Role
196
263
  get_user_roles_with_tenant_and_permissions = []
197
- for role in get_user_roles:
198
- permissions = DatabaseManager.execute_query(
199
- f"""SELECT permission_id FROM {db_settings.ROLE_PERMISSIONS_TABLE} WHERE role_id = %s""",
200
- params=(role["role_id"],),)
264
+
265
+ # Track system role IDs by querying cp_roles table for is_system flag (more reliable)
266
+ system_role_ids = set()
267
+ if all_roles:
268
+ role_ids = [r.get("role_id") for r in all_roles if r.get("role_id")]
269
+ if role_ids:
270
+ try:
271
+ # Check which roles are system roles by querying the roles table
272
+ system_roles_check = DatabaseManager.execute_query(
273
+ f"""SELECT id FROM {db_settings.CORE_PLATFORM_ROLES_TABLE}
274
+ WHERE id = ANY(%s) AND is_system = true AND delete_status = 'NOT_DELETED'""",
275
+ params=(role_ids,),
276
+ )
277
+ if system_roles_check:
278
+ for role_record in system_roles_check:
279
+ role_id = role_record.get("id") if isinstance(role_record, dict) else (role_record[0] if isinstance(role_record, (list, tuple)) and len(role_record) > 0 else None)
280
+ if role_id:
281
+ system_role_ids.add(role_id)
282
+
283
+ logger.info(f"Identified {len(system_role_ids)} system roles for user {user_id}")
284
+ except Exception as e:
285
+ logger.warning(f"Error checking system roles: {str(e)}")
286
+ # Fallback: use system_roles query results
287
+ system_role_ids = {r.get("role_id") for r in system_roles if r.get("role_id")} if system_roles else set()
288
+
289
+ for role in all_roles:
290
+ role_id = role.get("role_id")
291
+ if not role_id:
292
+ logger.warning(f"Skipping role with missing role_id: {role}")
293
+ continue
294
+
295
+ # Determine which tenant_id to use for querying permissions
296
+ # For system roles, use 'system-tenant-id'; for tenant roles, use the user's tenant_id
297
+ is_system_role = role_id in system_role_ids
298
+
299
+ # Try the primary tenant_id first based on whether it's a system role
300
+ if is_system_role:
301
+ primary_tenant_id = 'system-tenant-id'
302
+ fallback_tenant_id = tenant_id
303
+ else:
304
+ primary_tenant_id = tenant_id
305
+ fallback_tenant_id = 'system-tenant-id'
306
+
307
+ # Query permissions for this role with primary tenant_id
308
+ permissions = []
309
+ try:
310
+ permissions = DatabaseManager.execute_query(
311
+ f"""SELECT permission_id FROM {db_settings.CORE_PLATFORM_ROLE_PERMISSIONS_TABLE}
312
+ WHERE role_id = %s AND tenant_id = %s AND delete_status = 'NOT_DELETED'""",
313
+ params=(role_id, primary_tenant_id),
314
+ )
315
+
316
+ # If no permissions found with primary tenant_id, try fallback (handles edge cases)
317
+ if not permissions or len(permissions) == 0:
318
+ logger.debug(f"No permissions found for role {role_id} with tenant {primary_tenant_id}, trying fallback {fallback_tenant_id}")
319
+ fallback_permissions = DatabaseManager.execute_query(
320
+ f"""SELECT permission_id FROM {db_settings.CORE_PLATFORM_ROLE_PERMISSIONS_TABLE}
321
+ WHERE role_id = %s AND tenant_id = %s AND delete_status = 'NOT_DELETED'""",
322
+ params=(role_id, fallback_tenant_id),
323
+ )
324
+ if fallback_permissions and len(fallback_permissions) > 0:
325
+ permissions = fallback_permissions
326
+ logger.info(f"Found permissions for role {role_id} in fallback tenant {fallback_tenant_id}")
327
+ except Exception as e:
328
+ logger.error(f"Error querying permissions for role {role_id}: {str(e)}", exc_info=True)
329
+ permissions = []
201
330
 
202
331
  role_dict = {**role, "tenant_id": tenant_id, "permissions": [p['permission_id'] for p in permissions]}
203
332
  get_user_roles_with_tenant_and_permissions.append(role_dict)
204
333
 
205
334
  roles_dto = Helper.map_to_dto(get_user_roles_with_tenant_and_permissions, AuthServiceReadDto)
206
335
 
336
+ logger.info(f"Authorization successful for user: {user_id} with {len(roles_dto)} total role entries")
337
+
207
338
  return Respons[AuthServiceReadDto](
208
339
  detail="Authorized",
209
340
  data=roles_dto,
@@ -216,7 +347,7 @@ class AuthService:
216
347
  raise http_ex
217
348
 
218
349
  except Exception as e:
219
- logger.error("Authorization check failed for user: %s", str(e))
350
+ logger.error("Authorization check failed for user: %s - Error: %s", user_id, str(e), exc_info=True)
220
351
  return Respons[AuthServiceReadDto](
221
352
  detail=None,
222
353
  data=[],
@@ -224,31 +355,27 @@ class AuthService:
224
355
  status_code=500,
225
356
  error="Authorization check failed due to an internal error"
226
357
  )
227
-
358
+
228
359
  @staticmethod
229
- def check_permission(users_data: list, action=None, org_id=None, bus_id=None, app_id=None,
230
- resource_id=None, shared_resource_id=None) -> bool:
360
+ def check_permission(users_data: list, action=None, resource_type=None) -> bool:
231
361
  """
232
- Check if user has a given permission (action) for a specific target.
233
-
234
- Hierarchy: organization > business > app > location > resource/shared_resource
235
- If a field in role is None, it applies to all under that level.
362
+ Check if user has a given permission (action).
363
+
364
+ Args:
365
+ users_data: List of user authorization data containing roles and permissions
366
+ action: The permission/action to check for
367
+ resource_type: Optional resource type filter (e.g., 'rt-user', 'rt-group')
368
+
369
+ Returns:
370
+ bool: True if user has the permission, False otherwise
236
371
  """
237
372
  for user_data in users_data:
238
- # Check hierarchy: None means "all"
239
- if user_data.org_id not in (None, org_id):
240
- continue
241
- if user_data.bus_id not in (None, bus_id):
242
- continue
243
- if user_data.app_id not in (None, app_id):
244
- continue
245
- if user_data.resource_id not in (None, resource_id):
246
- continue
247
- if user_data.shared_resource_id not in (None, shared_resource_id):
373
+ # Check resource_type if specified
374
+ if resource_type and user_data.resource_type and user_data.resource_type != resource_type:
248
375
  continue
249
376
 
250
377
  # Check if the permission exists
251
- if action in user_data.permissions:
378
+ if action and action in user_data.permissions:
252
379
  return True
253
380
 
254
381
  return False
@@ -273,18 +400,34 @@ class AuthService:
273
400
  def authorize_user_from_token(token: str) -> Respons[AuthServiceReadDto]:
274
401
  """
275
402
  Convenience method to authorize a user directly from a JWT token.
276
-
403
+
277
404
  Args:
278
405
  token: JWT token string
279
-
406
+
280
407
  Returns:
281
408
  Respons[AuthServiceReadDto]: Authorization result with user roles and permissions
282
-
409
+
283
410
  Raises:
284
411
  HTTPException: If token is invalid
285
412
  """
286
- user_info = AuthService.decode_token(token)
287
- return AuthService.authorize(user_info["user_id"], user_info["tenant_id"])
413
+ credentials_exception = HTTPException(
414
+ status_code=401,
415
+ detail="Could not validate credentials",
416
+ headers={"WWW-Authenticate": "Bearer"},
417
+ )
418
+ try:
419
+ payload = jwt.decode(token, db_settings.SECRET_KEY, algorithms=[db_settings.ALGORITHM])
420
+ user_id = payload.get("user_id")
421
+ tenant_id = payload.get("tenant_id")
422
+
423
+ if user_id is None or tenant_id is None:
424
+ raise credentials_exception
425
+
426
+ data = AuthServiceWriteDto(user_id=user_id, tenant_id=tenant_id)
427
+ return AuthService.authorize(data=data)
428
+
429
+ except jwt.InvalidTokenError as exc:
430
+ raise credentials_exception from exc
288
431
 
289
432
  @staticmethod
290
433
  def get_user_permissions(user_roles: list) -> list:
@@ -4,7 +4,7 @@ from pydantic import BaseModel
4
4
 
5
5
  class AuthControllerWriteDto(BaseModel):
6
6
  user_id: Optional[str] = None
7
- tenant: Optional[str] = None
7
+ tenant_id: Optional[str] = None
8
8
 
9
9
  class AuthServiceWriteDto(AuthControllerWriteDto):
10
10
  pass