square-authentication 10.0.0__py3-none-any.whl → 10.0.2__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.
@@ -1,64 +1,15 @@
1
- import copy
2
- import io
3
- import mimetypes
4
- import random
5
- import re
6
- import uuid
7
- from datetime import datetime, timedelta, timezone
8
1
  from typing import Annotated, List
9
2
 
10
- import bcrypt
11
- import jwt
12
3
  from fastapi import APIRouter, Header, HTTPException, status
13
4
  from fastapi.params import Query
14
5
  from fastapi.responses import JSONResponse
15
- from google.auth.transport import requests as google_requests
16
- from google.oauth2 import id_token
17
- from requests import HTTPError
18
- from square_commons import get_api_output_in_standard_format, send_email_using_mailgun
19
- from square_commons.api_utils import make_request
20
- from square_database_helper.pydantic_models import FilterConditionsV0, FiltersV0
21
- from square_database_structure.square import global_string_database_name
22
- from square_database_structure.square.authentication import global_string_schema_name
6
+ from square_commons import get_api_output_in_standard_format
23
7
  from square_database_structure.square.authentication.enums import (
24
8
  RecoveryMethodEnum,
25
- AuthProviderEnum,
26
- VerificationCodeTypeEnum,
27
9
  )
28
- from square_database_structure.square.authentication.tables import (
29
- User,
30
- UserApp,
31
- UserCredential,
32
- UserSession,
33
- UserProfile,
34
- UserRecoveryMethod,
35
- UserAuthProvider,
36
- UserVerificationCode,
37
- )
38
- from square_database_structure.square.email import (
39
- global_string_schema_name as email_schema_name,
40
- )
41
- from square_database_structure.square.email.enums import EmailTypeEnum, EmailStatusEnum
42
- from square_database_structure.square.email.tables import EmailLog
43
- from square_database_structure.square.public import (
44
- global_string_schema_name as global_string_public_schema_name,
45
- )
46
- from square_database_structure.square.public.tables import App
47
10
 
48
11
  from square_authentication.configuration import (
49
- config_int_access_token_valid_minutes,
50
- config_int_refresh_token_valid_minutes,
51
- config_str_secret_key_for_access_token,
52
- config_str_secret_key_for_refresh_token,
53
12
  global_object_square_logger,
54
- global_object_square_database_helper,
55
- MAIL_GUN_API_KEY,
56
- GOOGLE_AUTH_PLATFORM_CLIENT_ID,
57
- NUMBER_OF_RECOVERY_CODES,
58
- NUMBER_OF_DIGITS_IN_EMAIL_PASSWORD_RESET_CODE,
59
- EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS,
60
- global_object_square_file_store_helper,
61
- RESEND_COOL_DOWN_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS,
62
13
  )
63
14
  from square_authentication.messages import messages
64
15
  from square_authentication.pydantic_models.core import (
@@ -73,8 +24,26 @@ from square_authentication.pydantic_models.core import (
73
24
  ResetPasswordAndLoginUsingResetEmailCodeV0,
74
25
  RegisterLoginGoogleV0,
75
26
  )
76
- from square_authentication.utils.core import generate_default_username_for_google_users
77
- from square_authentication.utils.token import get_jwt_payload
27
+ from square_authentication.utils.routes.core import (
28
+ util_register_username_v0,
29
+ util_register_login_google_v0,
30
+ util_get_user_details_v0,
31
+ util_update_user_app_ids_v0,
32
+ util_login_username_v0,
33
+ util_generate_access_token_v0,
34
+ util_logout_v0,
35
+ util_logout_apps_v0,
36
+ util_logout_all_v0,
37
+ util_update_username_v0,
38
+ util_delete_user_v0,
39
+ util_update_password_v0,
40
+ util_validate_and_get_payload_from_token_v0,
41
+ util_update_user_recovery_methods_v0,
42
+ util_generate_account_backup_codes_v0,
43
+ util_reset_password_and_login_using_backup_code_v0,
44
+ util_send_reset_password_email_v0,
45
+ util_reset_password_and_login_using_reset_email_code_v0,
46
+ )
78
47
 
79
48
  router = APIRouter(
80
49
  tags=["core"],
@@ -86,210 +55,19 @@ router = APIRouter(
86
55
  async def register_username_v0(
87
56
  body: RegisterUsernameV0,
88
57
  ):
89
- username = body.username
90
- password = body.password
91
- app_id = body.app_id
92
-
93
- local_str_user_id = None
94
- local_str_access_token = None
95
- local_str_refresh_token = None
96
- local_object_refresh_token_expiry_time = None
97
- username = username.lower()
98
58
  try:
99
- """
100
- validation
101
- """
102
- # validation for username
103
- username_pattern = re.compile(r"^[a-z0-9._-]{2,20}$")
104
- if not username_pattern.match(username):
105
- output_content = get_api_output_in_standard_format(
106
- message=messages["USERNAME_INVALID"],
107
- log=f"username '{username}' is invalid. it must start and end with a letter, "
108
- f"contain only lowercase letters, numbers, underscores, or hyphens, "
109
- f"and not have consecutive separators.",
110
- )
111
- raise HTTPException(
112
- status_code=status.HTTP_400_BAD_REQUEST,
113
- detail=output_content,
114
- )
115
- local_list_response_user_creds = (
116
- global_object_square_database_helper.get_rows_v0(
117
- database_name=global_string_database_name,
118
- schema_name=global_string_schema_name,
119
- table_name=User.__tablename__,
120
- filters=FiltersV0(
121
- root={User.user_username.name: FilterConditionsV0(eq=username)}
122
- ),
123
- )["data"]["main"]
124
- )
125
- if len(local_list_response_user_creds) > 0:
126
- output_content = get_api_output_in_standard_format(
127
- message=messages["USERNAME_ALREADY_EXISTS"],
128
- log=f"an account with the username {username} already exists.",
129
- )
130
- raise HTTPException(
131
- status_code=status.HTTP_409_CONFLICT,
132
- detail=output_content,
133
- )
134
-
135
- """
136
- main process
137
- """
138
- # entry in user table
139
- local_list_response_user = global_object_square_database_helper.insert_rows_v0(
140
- data=[
141
- {
142
- User.user_username.name: username,
143
- }
144
- ],
145
- database_name=global_string_database_name,
146
- schema_name=global_string_schema_name,
147
- table_name=User.__tablename__,
148
- )["data"]["main"]
149
- local_str_user_id = local_list_response_user[0][User.user_id.name]
150
-
151
- # entry in user auth provider table
152
- global_object_square_database_helper.insert_rows_v0(
153
- data=[
154
- {
155
- UserAuthProvider.user_id.name: local_str_user_id,
156
- UserAuthProvider.auth_provider.name: AuthProviderEnum.SELF.value,
157
- }
158
- ],
159
- database_name=global_string_database_name,
160
- schema_name=global_string_schema_name,
161
- table_name=UserAuthProvider.__tablename__,
162
- )
163
-
164
- # entry in user profile table
165
- global_object_square_database_helper.insert_rows_v0(
166
- database_name=global_string_database_name,
167
- schema_name=global_string_schema_name,
168
- table_name=UserProfile.__tablename__,
169
- data=[
170
- {
171
- UserProfile.user_id.name: local_str_user_id,
172
- }
173
- ],
174
- )
175
-
176
- # entry in credential table
177
-
178
- # hash password
179
- local_str_hashed_password = bcrypt.hashpw(
180
- password.encode("utf-8"), bcrypt.gensalt()
181
- ).decode("utf-8")
182
-
183
- global_object_square_database_helper.insert_rows_v0(
184
- data=[
185
- {
186
- UserCredential.user_id.name: local_str_user_id,
187
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
188
- }
189
- ],
190
- database_name=global_string_database_name,
191
- schema_name=global_string_schema_name,
192
- table_name=UserCredential.__tablename__,
193
- )
194
- if app_id is not None:
195
- # assign app to user
196
- global_object_square_database_helper.insert_rows_v0(
197
- database_name=global_string_database_name,
198
- schema_name=global_string_schema_name,
199
- table_name=UserApp.__tablename__,
200
- data=[
201
- {
202
- UserApp.user_id.name: local_str_user_id,
203
- UserApp.app_id.name: app_id,
204
- }
205
- ],
206
- )
207
-
208
- # return new access token and refresh token
209
- # create access token
210
- local_dict_access_token_payload = {
211
- "app_id": app_id,
212
- "user_id": local_str_user_id,
213
- "exp": datetime.now(timezone.utc)
214
- + timedelta(minutes=config_int_access_token_valid_minutes),
215
- }
216
- local_str_access_token = jwt.encode(
217
- local_dict_access_token_payload,
218
- config_str_secret_key_for_access_token,
219
- )
220
-
221
- # create refresh token
222
- local_object_refresh_token_expiry_time = datetime.now(
223
- timezone.utc
224
- ) + timedelta(minutes=config_int_refresh_token_valid_minutes)
225
-
226
- local_dict_refresh_token_payload = {
227
- "app_id": app_id,
228
- "user_id": local_str_user_id,
229
- "exp": local_object_refresh_token_expiry_time,
230
- }
231
- local_str_refresh_token = jwt.encode(
232
- local_dict_refresh_token_payload,
233
- config_str_secret_key_for_refresh_token,
234
- )
235
- # entry in user session table
236
- global_object_square_database_helper.insert_rows_v0(
237
- data=[
238
- {
239
- UserSession.user_id.name: local_str_user_id,
240
- UserSession.app_id.name: app_id,
241
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
242
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
243
- "%Y-%m-%d %H:%M:%S.%f+00"
244
- ),
245
- }
246
- ],
247
- database_name=global_string_database_name,
248
- schema_name=global_string_schema_name,
249
- table_name=UserSession.__tablename__,
250
- )
251
- """
252
- return value
253
- """
254
- output_content = get_api_output_in_standard_format(
255
- message=messages["REGISTRATION_SUCCESSFUL"],
256
- data={
257
- "main": {
258
- "user_id": local_str_user_id,
259
- "username": username,
260
- "app_id": app_id,
261
- "access_token": local_str_access_token,
262
- "refresh_token": local_str_refresh_token,
263
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
264
- },
265
- },
266
- )
267
- return JSONResponse(
268
- status_code=status.HTTP_201_CREATED,
269
- content=output_content,
270
- )
271
- except HTTPException as http_exception:
272
- global_object_square_logger.logger.error(http_exception, exc_info=True)
273
- return JSONResponse(
274
- status_code=http_exception.status_code, content=http_exception.detail
275
- )
59
+ return util_register_username_v0(
60
+ username=body.username,
61
+ password=body.password,
62
+ app_id=body.app_id,
63
+ )
64
+ except HTTPException as he:
65
+ global_object_square_logger.logger.error(he, exc_info=True)
66
+ return JSONResponse(status_code=he.status_code, content=he.detail)
276
67
  except Exception as e:
277
68
  global_object_square_logger.logger.error(e, exc_info=True)
278
- """
279
- rollback logic
280
- """
281
- if local_str_user_id:
282
- global_object_square_database_helper.delete_rows_v0(
283
- database_name=global_string_database_name,
284
- schema_name=global_string_schema_name,
285
- table_name=User.__tablename__,
286
- filters=FiltersV0(
287
- root={User.user_id.name: FilterConditionsV0(eq=local_str_user_id)}
288
- ),
289
- )
290
69
  output_content = get_api_output_in_standard_format(
291
- message=messages["GENERIC_500"],
292
- log=str(e),
70
+ message=messages["GENERIC_500"], log=str(e)
293
71
  )
294
72
  return JSONResponse(
295
73
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -298,361 +76,22 @@ async def register_username_v0(
298
76
 
299
77
  @router.post("/register_login_google/v0")
300
78
  async def register_login_google_v0(body: RegisterLoginGoogleV0):
301
- app_id = body.app_id
302
- google_id = body.google_id
303
- assign_app_id_if_missing = body.assign_app_id_if_missing
304
- was_new_user = False
305
79
  try:
306
- """
307
- validation
308
- """
309
- # verify id token
310
- try:
311
- id_info = id_token.verify_oauth2_token(
312
- google_id,
313
- google_requests.Request(),
314
- GOOGLE_AUTH_PLATFORM_CLIENT_ID,
315
- )
316
- except Exception:
317
- output_content = get_api_output_in_standard_format(
318
- message=messages["GENERIC_400"],
319
- log="Google id is invalid.",
320
- )
321
- raise HTTPException(
322
- status_code=status.HTTP_400_BAD_REQUEST,
323
- detail=output_content,
324
- )
325
-
326
- # validate if email is verified
327
- if id_info.get("email_verified") is not True:
328
- output_content = get_api_output_in_standard_format(
329
- message=messages["EMAIL_NOT_VERIFIED"],
330
- log="Google account email is not verified.",
331
- )
332
- raise HTTPException(
333
- status_code=status.HTTP_400_BAD_REQUEST,
334
- detail=output_content,
335
- )
336
- """
337
- processing
338
- """
339
- google_sub = id_info["sub"]
340
- email = id_info.get("email")
341
- given_name = id_info.get("given_name")
342
- family_name = id_info.get("family_name")
343
-
344
- profile_picture = id_info.get("picture")
345
-
346
- # check if user exists
347
- user_rows = global_object_square_database_helper.get_rows_v0(
348
- database_name=global_string_database_name,
349
- schema_name=global_string_schema_name,
350
- table_name=UserAuthProvider.__tablename__,
351
- filters=FiltersV0(
352
- root={
353
- UserAuthProvider.auth_provider_user_id.name: FilterConditionsV0(
354
- eq=google_sub
355
- ),
356
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
357
- eq=AuthProviderEnum.GOOGLE.value
358
- ),
359
- }
360
- ),
361
- )["data"]["main"]
362
-
363
- if user_rows:
364
- # login
365
-
366
- # validate if app_id is assigned to user
367
- # this will also validate if app_id is valid
368
- local_str_user_id = user_rows[0][User.user_id.name]
369
- user_record = global_object_square_database_helper.get_rows_v0(
370
- database_name=global_string_database_name,
371
- schema_name=global_string_schema_name,
372
- table_name=User.__tablename__,
373
- filters=FiltersV0(
374
- root={User.user_id.name: FilterConditionsV0(eq=local_str_user_id)}
375
- ),
376
- )["data"]["main"][0]
377
- username = user_record[User.user_username.name]
378
- local_list_user_app_response = (
379
- global_object_square_database_helper.get_rows_v0(
380
- database_name=global_string_database_name,
381
- schema_name=global_string_schema_name,
382
- table_name=UserApp.__tablename__,
383
- filters=FiltersV0(
384
- root={
385
- UserApp.user_id.name: FilterConditionsV0(
386
- eq=local_str_user_id
387
- ),
388
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
389
- }
390
- ),
391
- )["data"]["main"]
392
- )
393
- if len(local_list_user_app_response) == 0:
394
- if assign_app_id_if_missing:
395
- global_object_square_database_helper.insert_rows_v0(
396
- database_name=global_string_database_name,
397
- schema_name=global_string_schema_name,
398
- table_name=UserApp.__tablename__,
399
- data=[
400
- {
401
- UserApp.user_id.name: local_str_user_id,
402
- UserApp.app_id.name: app_id,
403
- }
404
- ],
405
- )
406
- else:
407
- output_content = get_api_output_in_standard_format(
408
- message=messages["GENERIC_400"],
409
- log=f"user_id {local_str_user_id}({username}) not assigned to app {app_id}.",
410
- )
411
- raise HTTPException(
412
- status_code=status.HTTP_400_BAD_REQUEST,
413
- detail=output_content,
414
- )
415
- else:
416
- # register
417
-
418
- was_new_user = True
419
- # check if account with same email address exists
420
- profile_rows = global_object_square_database_helper.get_rows_v0(
421
- database_name=global_string_database_name,
422
- schema_name=global_string_schema_name,
423
- table_name=UserProfile.__tablename__,
424
- filters=FiltersV0(
425
- root={
426
- UserProfile.user_profile_email.name: FilterConditionsV0(
427
- eq=email
428
- )
429
- }
430
- ),
431
- )["data"]["main"]
432
- if len(profile_rows) > 0:
433
- output_content = get_api_output_in_standard_format(
434
- message=messages["ACCOUNT_WITH_EMAIL_ALREADY_EXISTS"],
435
- log=f"An account with the email {email} already exists.",
436
- )
437
- raise HTTPException(
438
- status_code=status.HTTP_409_CONFLICT,
439
- detail=output_content,
440
- )
441
- # generate a default username
442
- username = generate_default_username_for_google_users(
443
- family_name=family_name, given_name=given_name
444
- )
445
- # create user
446
- user_rows = global_object_square_database_helper.insert_rows_v0(
447
- database_name=global_string_database_name,
448
- schema_name=global_string_schema_name,
449
- table_name=User.__tablename__,
450
- data=[
451
- {
452
- User.user_username.name: username,
453
- }
454
- ],
455
- )["data"]["main"]
456
- local_str_user_id = user_rows[0][User.user_id.name]
457
-
458
- # link to user_auth_provider
459
- global_object_square_database_helper.insert_rows_v0(
460
- database_name=global_string_database_name,
461
- schema_name=global_string_schema_name,
462
- table_name=UserAuthProvider.__tablename__,
463
- data=[
464
- {
465
- UserAuthProvider.user_id.name: local_str_user_id,
466
- UserAuthProvider.auth_provider.name: AuthProviderEnum.GOOGLE.value,
467
- UserAuthProvider.auth_provider_user_id.name: google_sub,
468
- }
469
- ],
470
- )
471
- # getting profile picture
472
- if profile_picture:
473
- try:
474
- profile_picture_response = make_request(
475
- "GET", profile_picture, return_type="response"
476
- )
477
-
478
- # finding content type and filename
479
- headers = profile_picture_response.headers
480
- content_type = headers.get(
481
- "Content-Type", "application/octet-stream"
482
- )
483
- content_disposition = headers.get("Content-Disposition", "")
484
-
485
- if content_disposition:
486
- match = re.search(r'filename="([^"]+)"', content_disposition)
487
- if match:
488
- filename = match.group(1)
489
- else:
490
- filename = None
491
- else:
492
- filename = None
493
- if filename is None:
494
- global_object_square_logger.logger.warning(
495
- f"user_id {local_str_user_id}'s profile picture from Google missing filename; guessing extension from Content-Type: {content_type}."
496
- )
497
- ext = (
498
- mimetypes.guess_extension(
499
- content_type.split(";")[0].strip()
500
- )
501
- or ""
502
- )
503
- filename = f"profile_photo{ext}"
504
- if not ext:
505
- filename += ".bin"
506
-
507
- # upload bytes to square_file_storage
508
- file_upload_response = global_object_square_file_store_helper.upload_file_using_tuple_v0(
509
- file=(
510
- filename,
511
- io.BytesIO(profile_picture_response.content),
512
- content_type,
513
- ),
514
- system_relative_path="global/users/profile_photos",
515
- )
516
- user_profile_photo_storage_token = file_upload_response["data"][
517
- "main"
518
- ]
519
- except HTTPError:
520
- global_object_square_logger.logger.error(
521
- f"Failed to fetch profile picture for user_id {local_str_user_id} from google account.",
522
- exc_info=True,
523
- )
524
- user_profile_photo_storage_token = None
525
- except Exception as e:
526
- global_object_square_logger.logger.error(
527
- f"Error while fetching profile picture for user_id {local_str_user_id} from google account: {str(e)}",
528
- exc_info=True,
529
- )
530
- user_profile_photo_storage_token = None
531
- else:
532
- global_object_square_logger.logger.warning(
533
- f"user_id {local_str_user_id} has no profile picture in google account."
534
- )
535
- user_profile_photo_storage_token = None
536
- # create user profile
537
- global_object_square_database_helper.insert_rows_v0(
538
- database_name=global_string_database_name,
539
- schema_name=global_string_schema_name,
540
- table_name=UserProfile.__tablename__,
541
- data=[
542
- {
543
- UserProfile.user_id.name: local_str_user_id,
544
- UserProfile.user_profile_email.name: email,
545
- UserProfile.user_profile_email_verified.name: datetime.now(
546
- timezone.utc
547
- ).strftime("%Y-%m-%d %H:%M:%S.%f+00"),
548
- UserProfile.user_profile_first_name.name: given_name,
549
- UserProfile.user_profile_last_name.name: family_name,
550
- UserProfile.user_profile_photo_storage_token.name: user_profile_photo_storage_token,
551
- }
552
- ],
553
- )
554
-
555
- # assign app if provided
556
- if app_id is not None:
557
- global_object_square_database_helper.insert_rows_v0(
558
- database_name=global_string_database_name,
559
- schema_name=global_string_schema_name,
560
- table_name=UserApp.__tablename__,
561
- data=[
562
- {
563
- UserApp.user_id.name: local_str_user_id,
564
- UserApp.app_id.name: app_id,
565
- }
566
- ],
567
- )
568
-
569
- # generate tokens
570
- now = datetime.now(timezone.utc)
571
- access_token_payload = {
572
- "app_id": app_id,
573
- "user_id": local_str_user_id,
574
- "exp": now + timedelta(minutes=config_int_access_token_valid_minutes),
575
- }
576
- access_token_str = jwt.encode(
577
- access_token_payload,
578
- config_str_secret_key_for_access_token,
579
- )
580
-
581
- refresh_token_expiry = now + timedelta(
582
- minutes=config_int_refresh_token_valid_minutes
583
- )
584
- refresh_token_payload = {
585
- "app_id": app_id,
586
- "user_id": local_str_user_id,
587
- "exp": refresh_token_expiry,
588
- }
589
- refresh_token_str = jwt.encode(
590
- refresh_token_payload,
591
- config_str_secret_key_for_refresh_token,
592
- )
593
-
594
- # store refresh token
595
- global_object_square_database_helper.insert_rows_v0(
596
- database_name=global_string_database_name,
597
- schema_name=global_string_schema_name,
598
- table_name=UserSession.__tablename__,
599
- data=[
600
- {
601
- UserSession.user_id.name: local_str_user_id,
602
- UserSession.app_id.name: app_id,
603
- UserSession.user_session_refresh_token.name: refresh_token_str,
604
- UserSession.user_session_expiry_time.name: refresh_token_expiry.strftime(
605
- "%Y-%m-%d %H:%M:%S.%f+00"
606
- ),
607
- }
608
- ],
609
- )
610
- """
611
- return value
612
- """
613
- if was_new_user:
614
- message = messages["REGISTRATION_SUCCESSFUL"]
615
- else:
616
- message = messages["LOGIN_SUCCESSFUL"]
617
- output_content = get_api_output_in_standard_format(
618
- message=message,
619
- data={
620
- "main": {
621
- "user_id": local_str_user_id,
622
- "username": username,
623
- "app_id": app_id,
624
- "access_token": access_token_str,
625
- "refresh_token": refresh_token_str,
626
- "refresh_token_expiry_time": refresh_token_expiry.isoformat(),
627
- "was_new_user": was_new_user,
628
- },
629
- },
630
- )
631
-
632
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
633
- except HTTPError as http_error:
634
- global_object_square_logger.logger.error(http_error, exc_info=True)
635
- return JSONResponse(
636
- status_code=http_error.response.status_code,
637
- content=http_error.response.text,
638
- )
639
- except HTTPException as http_exception:
640
- global_object_square_logger.logger.error(http_exception, exc_info=True)
641
- return JSONResponse(
642
- status_code=http_exception.status_code, content=http_exception.detail
643
- )
80
+ return util_register_login_google_v0(
81
+ app_id=body.app_id,
82
+ google_id=body.google_id,
83
+ assign_app_id_if_missing=body.assign_app_id_if_missing,
84
+ )
85
+ except HTTPException as he:
86
+ global_object_square_logger.logger.error(he, exc_info=True)
87
+ return JSONResponse(status_code=he.status_code, content=he.detail)
644
88
  except Exception as e:
645
- """
646
- rollback logic
647
- """
648
89
  global_object_square_logger.logger.error(e, exc_info=True)
649
90
  output_content = get_api_output_in_standard_format(
650
- message=messages["GENERIC_500"],
651
- log=str(e),
91
+ message=messages["GENERIC_500"], log=str(e)
652
92
  )
653
93
  return JSONResponse(
654
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
655
- content=output_content,
94
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
656
95
  )
657
96
 
658
97
 
@@ -662,123 +101,17 @@ async def get_user_details_v0(
662
101
  access_token: Annotated[str, Header()],
663
102
  ):
664
103
  try:
665
- """
666
- validation
667
- """
668
- # validate access token
669
- try:
670
- local_dict_access_token_payload = get_jwt_payload(
671
- access_token, config_str_secret_key_for_access_token
672
- )
673
- except Exception as error:
674
- output_content = get_api_output_in_standard_format(
675
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
676
- )
677
- raise HTTPException(
678
- status_code=status.HTTP_400_BAD_REQUEST,
679
- detail=output_content,
680
- )
681
- user_id = local_dict_access_token_payload["user_id"]
682
- """
683
- main process
684
- """
685
- local_list_app = global_object_square_database_helper.get_rows_v0(
686
- database_name=global_string_database_name,
687
- schema_name=global_string_public_schema_name,
688
- table_name=App.__tablename__,
689
- apply_filters=False,
690
- filters=FiltersV0(root={}),
691
- )["data"]["main"]
692
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
693
- database_name=global_string_database_name,
694
- schema_name=global_string_schema_name,
695
- table_name=UserApp.__tablename__,
696
- filters=FiltersV0(
697
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
698
- ),
699
- )["data"]["main"]
700
- local_list_response_user_profile = (
701
- global_object_square_database_helper.get_rows_v0(
702
- database_name=global_string_database_name,
703
- schema_name=global_string_schema_name,
704
- table_name=UserProfile.__tablename__,
705
- filters=FiltersV0(
706
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
707
- ),
708
- )["data"]["main"]
709
- )
710
- local_list_response_user_sessions = (
711
- global_object_square_database_helper.get_rows_v0(
712
- database_name=global_string_database_name,
713
- schema_name=global_string_schema_name,
714
- table_name=UserSession.__tablename__,
715
- filters=FiltersV0(
716
- root={
717
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
718
- UserSession.user_session_expiry_time.name: FilterConditionsV0(
719
- gte=datetime.now(timezone.utc).isoformat()
720
- ),
721
- }
722
- ),
723
- )["data"]["main"]
724
- )
725
- user_profile = copy.deepcopy(local_list_response_user_profile[0])
726
- del user_profile[UserProfile.user_id.name]
727
- """
728
- return value
729
- """
730
- return_this = {
731
- "user_id": user_id,
732
- "profile": user_profile,
733
- "apps": [
734
- y[App.app_name.name]
735
- for y in local_list_app
736
- if y[App.app_id.name]
737
- in [x[UserApp.app_id.name] for x in local_list_response_user_app]
738
- ],
739
- "sessions": [
740
- {
741
- "app_name": [
742
- y[App.app_name.name]
743
- for y in local_list_app
744
- if y[App.app_id.name] == x[UserApp.app_id.name]
745
- ][0],
746
- "active_sessions": len(
747
- [
748
- y
749
- for y in local_list_response_user_sessions
750
- if y[UserSession.app_id.name] == x[UserApp.app_id.name]
751
- ]
752
- ),
753
- }
754
- for x in local_list_response_user_app
755
- ],
756
- }
757
- output_content = get_api_output_in_standard_format(
758
- message=messages["GENERIC_READ_SUCCESSFUL"],
759
- data={"main": return_this},
760
- )
761
- return JSONResponse(
762
- status_code=status.HTTP_200_OK,
763
- content=output_content,
764
- )
765
- except HTTPException as http_exception:
766
- global_object_square_logger.logger.error(http_exception, exc_info=True)
767
- return JSONResponse(
768
- status_code=http_exception.status_code, content=http_exception.detail
769
- )
104
+ return util_get_user_details_v0(access_token=access_token)
105
+ except HTTPException as he:
106
+ global_object_square_logger.logger.error(he, exc_info=True)
107
+ return JSONResponse(status_code=he.status_code, content=he.detail)
770
108
  except Exception as e:
771
- """
772
- rollback logic
773
- """
774
109
  global_object_square_logger.logger.error(e, exc_info=True)
775
110
  output_content = get_api_output_in_standard_format(
776
- message=messages["GENERIC_500"],
777
- log=str(e),
111
+ message=messages["GENERIC_500"], log=str(e)
778
112
  )
779
113
  return JSONResponse(
780
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
781
- content=output_content,
114
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
782
115
  )
783
116
 
784
117
 
@@ -790,156 +123,21 @@ async def update_user_app_ids_v0(
790
123
  app_ids_to_remove: List[int],
791
124
  ):
792
125
  try:
793
-
794
- """
795
- validation
796
- """
797
- # validate access token
798
- try:
799
- local_dict_access_token_payload = get_jwt_payload(
800
- access_token, config_str_secret_key_for_access_token
801
- )
802
- except Exception as error:
803
- output_content = get_api_output_in_standard_format(
804
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
805
- )
806
- raise HTTPException(
807
- status_code=status.HTTP_400_BAD_REQUEST,
808
- detail=output_content,
809
- )
810
- user_id = local_dict_access_token_payload["user_id"]
811
-
812
- app_ids_to_add = list(set(app_ids_to_add))
813
- app_ids_to_remove = list(set(app_ids_to_remove))
814
-
815
- # check if app_ids_to_add and app_ids_to_remove don't have common ids.
816
- local_list_common_app_ids = set(app_ids_to_add) & set(app_ids_to_remove)
817
- if len(local_list_common_app_ids) > 0:
818
- output_content = get_api_output_in_standard_format(
819
- message=messages["GENERIC_400"],
820
- log=f"invalid app_ids: {list(local_list_common_app_ids)}, present in both add list and remove list.",
821
- )
822
- raise HTTPException(
823
- status_code=status.HTTP_400_BAD_REQUEST,
824
- detail=output_content,
825
- )
826
-
827
- # check if all app_ids are valid
828
- local_list_all_app_ids = [*app_ids_to_add, *app_ids_to_remove]
829
- local_list_response_app = global_object_square_database_helper.get_rows_v0(
830
- database_name=global_string_database_name,
831
- schema_name=global_string_public_schema_name,
832
- table_name=App.__tablename__,
833
- apply_filters=False,
834
- filters=FiltersV0(root={}),
835
- )["data"]["main"]
836
- local_list_invalid_ids = [
837
- x
838
- for x in local_list_all_app_ids
839
- if x not in [y[App.app_id.name] for y in local_list_response_app]
840
- ]
841
- if len(local_list_invalid_ids) > 0:
842
- output_content = get_api_output_in_standard_format(
843
- message=messages["GENERIC_400"],
844
- log=f"invalid app_ids: {local_list_invalid_ids}.",
845
- )
846
- raise HTTPException(
847
- status_code=status.HTTP_400_BAD_REQUEST,
848
- detail=output_content,
849
- )
850
- """
851
- main process
852
- """
853
- # logic for adding new app_ids
854
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
855
- database_name=global_string_database_name,
856
- schema_name=global_string_schema_name,
857
- table_name=UserApp.__tablename__,
858
- filters=FiltersV0(
859
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
860
- ),
861
- )["data"]["main"]
862
- local_list_new_app_ids = [
863
- {
864
- UserApp.user_id.name: user_id,
865
- UserApp.app_id.name: x,
866
- }
867
- for x in app_ids_to_add
868
- if x not in [y[UserApp.app_id.name] for y in local_list_response_user_app]
869
- ]
870
- if len(local_list_new_app_ids) > 0:
871
- global_object_square_database_helper.insert_rows_v0(
872
- database_name=global_string_database_name,
873
- schema_name=global_string_schema_name,
874
- table_name=UserApp.__tablename__,
875
- data=local_list_new_app_ids,
876
- )
877
-
878
- # logic for removing app_ids
879
- for app_id in app_ids_to_remove:
880
- global_object_square_database_helper.delete_rows_v0(
881
- database_name=global_string_database_name,
882
- schema_name=global_string_schema_name,
883
- table_name=UserApp.__tablename__,
884
- filters=FiltersV0(
885
- root={
886
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
887
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
888
- }
889
- ),
890
- )
891
- # logout user from removed apps
892
- global_object_square_database_helper.delete_rows_v0(
893
- database_name=global_string_database_name,
894
- schema_name=global_string_schema_name,
895
- table_name=UserSession.__tablename__,
896
- filters=FiltersV0(
897
- root={
898
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
899
- UserSession.app_id.name: FilterConditionsV0(eq=app_id),
900
- }
901
- ),
902
- )
903
-
904
- """
905
- return value
906
- """
907
- # get latest app ids
908
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
909
- database_name=global_string_database_name,
910
- schema_name=global_string_schema_name,
911
- table_name=UserApp.__tablename__,
912
- filters=FiltersV0(
913
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
914
- ),
915
- )["data"]["main"]
916
- output_content = get_api_output_in_standard_format(
917
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
918
- data={
919
- "main": [x[UserApp.app_id.name] for x in local_list_response_user_app]
920
- },
921
- )
922
- return JSONResponse(
923
- status_code=status.HTTP_200_OK,
924
- content=output_content,
925
- )
926
- except HTTPException as http_exception:
927
- global_object_square_logger.logger.error(http_exception, exc_info=True)
928
- return JSONResponse(
929
- status_code=http_exception.status_code, content=http_exception.detail
930
- )
126
+ return util_update_user_app_ids_v0(
127
+ access_token=access_token,
128
+ app_ids_to_add=app_ids_to_add,
129
+ app_ids_to_remove=app_ids_to_remove,
130
+ )
131
+ except HTTPException as he:
132
+ global_object_square_logger.logger.error(he, exc_info=True)
133
+ return JSONResponse(status_code=he.status_code, content=he.detail)
931
134
  except Exception as e:
932
- """
933
- rollback logic
934
- """
935
135
  global_object_square_logger.logger.error(e, exc_info=True)
936
136
  output_content = get_api_output_in_standard_format(
937
- message=messages["GENERIC_500"],
938
- log=str(e),
137
+ message=messages["GENERIC_500"], log=str(e)
939
138
  )
940
139
  return JSONResponse(
941
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
942
- content=output_content,
140
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
943
141
  )
944
142
 
945
143
 
@@ -952,221 +150,19 @@ async def login_username_v0(body: LoginUsernameV0):
952
150
  assign_app_id_if_missing = body.assign_app_id_if_missing
953
151
  username = username.lower()
954
152
  try:
955
- """
956
- validation
957
- """
958
- # validation for username
959
- # check if user with username exists
960
- local_list_response_user = global_object_square_database_helper.get_rows_v0(
961
- database_name=global_string_database_name,
962
- schema_name=global_string_schema_name,
963
- table_name=User.__tablename__,
964
- filters=FiltersV0(
965
- root={User.user_username.name: FilterConditionsV0(eq=username)}
966
- ),
967
- )["data"]["main"]
968
- if len(local_list_response_user) != 1:
969
- output_content = get_api_output_in_standard_format(
970
- message=messages["INCORRECT_USERNAME"],
971
- log=f"incorrect username {username}",
972
- )
973
- raise HTTPException(
974
- status_code=status.HTTP_400_BAD_REQUEST,
975
- detail=output_content,
976
- )
977
- # check if user has auth provider as SELF
978
- local_list_user_auth_provider_response = (
979
- global_object_square_database_helper.get_rows_v0(
980
- database_name=global_string_database_name,
981
- schema_name=global_string_schema_name,
982
- table_name=UserAuthProvider.__tablename__,
983
- filters=FiltersV0(
984
- root={
985
- UserAuthProvider.user_id.name: FilterConditionsV0(
986
- eq=local_list_response_user[0][User.user_id.name]
987
- ),
988
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
989
- eq=AuthProviderEnum.SELF.value
990
- ),
991
- }
992
- ),
993
- )["data"]["main"]
994
- )
995
- if len(local_list_user_auth_provider_response) != 1:
996
- output_content = get_api_output_in_standard_format(
997
- message=messages["INCORRECT_AUTH_PROVIDER"],
998
- log=f"{username} not linked with {AuthProviderEnum.SELF.value} auth provider.",
999
- )
1000
- raise HTTPException(
1001
- status_code=status.HTTP_400_BAD_REQUEST,
1002
- detail=output_content,
1003
- )
1004
- # check if user has credentials (might not be set in case of errors in registration.)
1005
- local_list_authentication_user_response = (
1006
- global_object_square_database_helper.get_rows_v0(
1007
- database_name=global_string_database_name,
1008
- schema_name=global_string_schema_name,
1009
- table_name=UserCredential.__tablename__,
1010
- filters=FiltersV0(
1011
- root={
1012
- UserCredential.user_id.name: FilterConditionsV0(
1013
- eq=local_list_response_user[0][User.user_id.name]
1014
- )
1015
- }
1016
- ),
1017
- )["data"]["main"]
1018
- )
1019
- if len(local_list_authentication_user_response) != 1:
1020
- output_content = get_api_output_in_standard_format(
1021
- message=messages["MALFORMED_USER"],
1022
- log=f"username: {username} does not have credentials set.",
1023
- )
1024
- raise HTTPException(
1025
- status_code=status.HTTP_400_BAD_REQUEST,
1026
- detail=output_content,
1027
- )
1028
- # validate if app_id is assigned to user
1029
- # this will also validate if app_id is valid
1030
- local_dict_user = local_list_authentication_user_response[0]
1031
- local_str_user_id = local_dict_user[UserCredential.user_id.name]
1032
- local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
1033
- database_name=global_string_database_name,
1034
- schema_name=global_string_schema_name,
1035
- table_name=UserApp.__tablename__,
1036
- filters=FiltersV0(
1037
- root={
1038
- UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
1039
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
1040
- }
1041
- ),
1042
- )["data"]["main"]
1043
- if len(local_list_user_app_response) == 0:
1044
- if assign_app_id_if_missing:
1045
- try:
1046
- global_object_square_database_helper.insert_rows_v0(
1047
- database_name=global_string_database_name,
1048
- schema_name=global_string_schema_name,
1049
- table_name=UserApp.__tablename__,
1050
- data=[
1051
- {
1052
- UserApp.user_id.name: local_str_user_id,
1053
- UserApp.app_id.name: app_id,
1054
- }
1055
- ],
1056
- )
1057
- except HTTPError as he:
1058
- output_content = get_api_output_in_standard_format(
1059
- message=messages["GENERIC_400"],
1060
- log=str(he),
1061
- )
1062
- raise HTTPException(
1063
- status_code=he.response.status_code, detail=output_content
1064
- )
1065
- else:
1066
- output_content = get_api_output_in_standard_format(
1067
- message=messages["GENERIC_400"],
1068
- log=f"user_id {local_str_user_id}({username}) not assigned to app {app_id}.",
1069
- )
1070
- raise HTTPException(
1071
- status_code=status.HTTP_400_BAD_REQUEST,
1072
- detail=output_content,
1073
- )
1074
-
1075
- # validate password
1076
- if not (
1077
- bcrypt.checkpw(
1078
- password.encode("utf-8"),
1079
- local_dict_user[
1080
- UserCredential.user_credential_hashed_password.name
1081
- ].encode("utf-8"),
1082
- )
1083
- ):
1084
- output_content = get_api_output_in_standard_format(
1085
- message=messages["INCORRECT_PASSWORD"],
1086
- log=f"incorrect password for user_id {local_str_user_id}({username}).",
1087
- )
1088
- raise HTTPException(
1089
- status_code=status.HTTP_400_BAD_REQUEST,
1090
- detail=output_content,
1091
- )
1092
- """
1093
- main process
1094
- """
1095
- # return new access token and refresh token
1096
-
1097
- # create access token
1098
- local_dict_access_token_payload = {
1099
- "app_id": app_id,
1100
- "user_id": local_str_user_id,
1101
- "exp": datetime.now(timezone.utc)
1102
- + timedelta(minutes=config_int_access_token_valid_minutes),
1103
- }
1104
- local_str_access_token = jwt.encode(
1105
- local_dict_access_token_payload,
1106
- config_str_secret_key_for_access_token,
1107
- )
1108
-
1109
- # create refresh token
1110
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
1111
- minutes=config_int_refresh_token_valid_minutes
1112
- )
1113
-
1114
- local_dict_refresh_token_payload = {
1115
- "app_id": app_id,
1116
- "user_id": local_str_user_id,
1117
- "exp": local_object_refresh_token_expiry_time,
1118
- }
1119
- local_str_refresh_token = jwt.encode(
1120
- local_dict_refresh_token_payload,
1121
- config_str_secret_key_for_refresh_token,
1122
- )
1123
- # entry in user session table
1124
- global_object_square_database_helper.insert_rows_v0(
1125
- data=[
1126
- {
1127
- UserSession.user_id.name: local_str_user_id,
1128
- UserSession.app_id.name: app_id,
1129
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
1130
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
1131
- "%Y-%m-%d %H:%M:%S.%f+00"
1132
- ),
1133
- }
1134
- ],
1135
- database_name=global_string_database_name,
1136
- schema_name=global_string_schema_name,
1137
- table_name=UserSession.__tablename__,
1138
- )
1139
- """
1140
- return value
1141
- """
1142
- output_content = get_api_output_in_standard_format(
1143
- data={
1144
- "main": {
1145
- "user_id": local_str_user_id,
1146
- "access_token": local_str_access_token,
1147
- "refresh_token": local_str_refresh_token,
1148
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
1149
- }
1150
- },
1151
- message=messages["LOGIN_SUCCESSFUL"],
1152
- )
1153
- return JSONResponse(
1154
- status_code=status.HTTP_200_OK,
1155
- content=output_content,
1156
- )
1157
- except HTTPException as http_exception:
1158
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1159
- return JSONResponse(
1160
- status_code=http_exception.status_code, content=http_exception.detail
1161
- )
153
+ return util_login_username_v0(
154
+ username=username,
155
+ password=password,
156
+ app_id=app_id,
157
+ assign_app_id_if_missing=assign_app_id_if_missing,
158
+ )
159
+ except HTTPException as he:
160
+ global_object_square_logger.logger.error(he, exc_info=True)
161
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1162
162
  except Exception as e:
1163
- """
1164
- rollback logic
1165
- """
1166
163
  global_object_square_logger.logger.error(e, exc_info=True)
1167
164
  output_content = get_api_output_in_standard_format(
1168
- message=messages["GENERIC_500"],
1169
- log=str(e),
165
+ message=messages["GENERIC_500"], log=str(e)
1170
166
  )
1171
167
  return JSONResponse(
1172
168
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1179,85 +175,16 @@ async def generate_access_token_v0(
1179
175
  refresh_token: Annotated[str, Header()],
1180
176
  ):
1181
177
  try:
1182
- """
1183
- validation
1184
- """
1185
- # validate refresh token
1186
- # validating if a session refresh token exists in the database.
1187
- local_list_user_session_response = (
1188
- global_object_square_database_helper.get_rows_v0(
1189
- database_name=global_string_database_name,
1190
- schema_name=global_string_schema_name,
1191
- table_name=UserSession.__tablename__,
1192
- filters=FiltersV0(
1193
- root={
1194
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1195
- eq=refresh_token
1196
- ),
1197
- }
1198
- ),
1199
- )["data"]["main"]
1200
- )
1201
-
1202
- if len(local_list_user_session_response) != 1:
1203
- output_content = get_api_output_in_standard_format(
1204
- message=messages["INCORRECT_REFRESH_TOKEN"],
1205
- log=f"incorrect refresh token: {refresh_token}.",
1206
- )
1207
- raise HTTPException(
1208
- status_code=status.HTTP_400_BAD_REQUEST,
1209
- detail=output_content,
1210
- )
1211
- # validating if the refresh token is valid, active and of the same user.
1212
- try:
1213
- local_dict_refresh_token_payload = get_jwt_payload(
1214
- refresh_token, config_str_secret_key_for_refresh_token
1215
- )
1216
- except Exception as error:
1217
- output_content = get_api_output_in_standard_format(
1218
- message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
1219
- )
1220
- raise HTTPException(
1221
- status_code=status.HTTP_400_BAD_REQUEST,
1222
- detail=output_content,
1223
- )
1224
- """
1225
- main process
1226
- """
1227
- # create and send access token
1228
- local_dict_access_token_payload = {
1229
- "app_id": local_dict_refresh_token_payload["app_id"],
1230
- "user_id": local_dict_refresh_token_payload["user_id"],
1231
- "exp": datetime.now(timezone.utc)
1232
- + timedelta(minutes=config_int_access_token_valid_minutes),
1233
- }
1234
- local_str_access_token = jwt.encode(
1235
- local_dict_access_token_payload, config_str_secret_key_for_access_token
1236
- )
1237
- """
1238
- return value
1239
- """
1240
- output_content = get_api_output_in_standard_format(
1241
- data={"main": {"access_token": local_str_access_token}},
1242
- message=messages["GENERIC_CREATION_SUCCESSFUL"],
1243
- )
1244
- return JSONResponse(
1245
- status_code=status.HTTP_200_OK,
1246
- content=output_content,
1247
- )
1248
- except HTTPException as http_exception:
1249
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1250
- return JSONResponse(
1251
- status_code=http_exception.status_code, content=http_exception.detail
178
+ return util_generate_access_token_v0(
179
+ refresh_token=refresh_token,
1252
180
  )
181
+ except HTTPException as he:
182
+ global_object_square_logger.logger.error(he, exc_info=True)
183
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1253
184
  except Exception as e:
1254
- """
1255
- rollback logic
1256
- """
1257
185
  global_object_square_logger.logger.error(e, exc_info=True)
1258
186
  output_content = get_api_output_in_standard_format(
1259
- message=messages["GENERIC_500"],
1260
- log=str(e),
187
+ message=messages["GENERIC_500"], log=str(e)
1261
188
  )
1262
189
  return JSONResponse(
1263
190
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1270,86 +197,16 @@ async def logout_v0(
1270
197
  refresh_token: Annotated[str, Header()],
1271
198
  ):
1272
199
  try:
1273
- """
1274
- validation
1275
- """
1276
- # validate refresh token
1277
- # validating if a session refresh token exists in the database.
1278
- local_list_user_session_response = (
1279
- global_object_square_database_helper.get_rows_v0(
1280
- database_name=global_string_database_name,
1281
- schema_name=global_string_schema_name,
1282
- table_name=UserSession.__tablename__,
1283
- filters=FiltersV0(
1284
- root={
1285
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1286
- eq=refresh_token
1287
- ),
1288
- }
1289
- ),
1290
- )["data"]["main"]
1291
- )
1292
-
1293
- if len(local_list_user_session_response) != 1:
1294
- output_content = get_api_output_in_standard_format(
1295
- message=messages["INCORRECT_REFRESH_TOKEN"],
1296
- log=f"incorrect refresh token: {refresh_token}.",
1297
- )
1298
- raise HTTPException(
1299
- status_code=status.HTTP_400_BAD_REQUEST,
1300
- detail=output_content,
1301
- )
1302
- # validating if the refresh token is valid, active and of the same user.
1303
- try:
1304
- _ = get_jwt_payload(refresh_token, config_str_secret_key_for_refresh_token)
1305
- except Exception as error:
1306
- output_content = get_api_output_in_standard_format(
1307
- message=messages["INCORRECT_REFRESH_TOKEN"],
1308
- log=str(error),
1309
- )
1310
- raise HTTPException(
1311
- status_code=status.HTTP_400_BAD_REQUEST,
1312
- detail=output_content,
1313
- )
1314
- # ======================================================================================
1315
- # NOTE: if refresh token has expired no need to delete it during this call
1316
- # ======================================================================================
1317
- """
1318
- main process
1319
- """
1320
- # delete session for user
1321
- global_object_square_database_helper.delete_rows_v0(
1322
- database_name=global_string_database_name,
1323
- schema_name=global_string_schema_name,
1324
- table_name=UserSession.__tablename__,
1325
- filters=FiltersV0(
1326
- root={
1327
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1328
- eq=refresh_token
1329
- ),
1330
- }
1331
- ),
1332
- )
1333
- """
1334
- return value
1335
- """
1336
- output_content = get_api_output_in_standard_format(
1337
- message=messages["LOGOUT_SUCCESSFUL"],
1338
- )
1339
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1340
- except HTTPException as http_exception:
1341
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1342
- return JSONResponse(
1343
- status_code=http_exception.status_code, content=http_exception.detail
200
+ return util_logout_v0(
201
+ refresh_token=refresh_token,
1344
202
  )
203
+ except HTTPException as he:
204
+ global_object_square_logger.logger.error(he, exc_info=True)
205
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1345
206
  except Exception as e:
1346
- """
1347
- rollback logic
1348
- """
1349
207
  global_object_square_logger.logger.error(e, exc_info=True)
1350
208
  output_content = get_api_output_in_standard_format(
1351
- message=messages["GENERIC_500"],
1352
- log=str(e),
209
+ message=messages["GENERIC_500"], log=str(e)
1353
210
  )
1354
211
  return JSONResponse(
1355
212
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1364,85 +221,14 @@ async def logout_apps_v0(
1364
221
  ):
1365
222
  app_ids = body.app_ids
1366
223
  try:
1367
- """
1368
- validation
1369
- """
1370
- try:
1371
- local_dict_access_token_payload = get_jwt_payload(
1372
- access_token, config_str_secret_key_for_access_token
1373
- )
1374
- except Exception as error:
1375
- output_content = get_api_output_in_standard_format(
1376
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1377
- )
1378
- raise HTTPException(
1379
- status_code=status.HTTP_400_BAD_REQUEST,
1380
- detail=output_content,
1381
- )
1382
- user_id = local_dict_access_token_payload["user_id"]
1383
- # validate app_ids
1384
- app_ids = list(set(app_ids))
1385
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
1386
- database_name=global_string_database_name,
1387
- schema_name=global_string_schema_name,
1388
- table_name=UserApp.__tablename__,
1389
- filters=FiltersV0(
1390
- root={
1391
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
1392
- }
1393
- ),
1394
- columns=[UserApp.app_id.name],
1395
- )["data"]["main"]
1396
- local_list_user_app_ids = [
1397
- x[UserApp.app_id.name] for x in local_list_response_user_app
1398
- ]
1399
- local_list_invalid_app_ids = [
1400
- x for x in app_ids if x not in local_list_user_app_ids
1401
- ]
1402
- if len(local_list_invalid_app_ids) > 0:
1403
- output_content = get_api_output_in_standard_format(
1404
- message=messages["GENERIC_400"],
1405
- log=f"invalid app_ids: {local_list_invalid_app_ids}.",
1406
- )
1407
- raise HTTPException(
1408
- status_code=status.HTTP_400_BAD_REQUEST,
1409
- detail=output_content,
1410
- )
1411
- """
1412
- main process
1413
- """
1414
- # delete session for user
1415
- global_object_square_database_helper.delete_rows_v0(
1416
- database_name=global_string_database_name,
1417
- schema_name=global_string_schema_name,
1418
- table_name=UserSession.__tablename__,
1419
- filters=FiltersV0(
1420
- root={
1421
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1422
- UserSession.app_id.name: FilterConditionsV0(in_=app_ids),
1423
- }
1424
- ),
1425
- )
1426
- """
1427
- return value
1428
- """
1429
- output_content = get_api_output_in_standard_format(
1430
- message=messages["LOGOUT_SUCCESSFUL"],
1431
- )
1432
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1433
- except HTTPException as http_exception:
1434
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1435
- return JSONResponse(
1436
- status_code=http_exception.status_code, content=http_exception.detail
1437
- )
224
+ return util_logout_apps_v0(access_token=access_token, app_ids=app_ids)
225
+ except HTTPException as he:
226
+ global_object_square_logger.logger.error(he, exc_info=True)
227
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1438
228
  except Exception as e:
1439
- """
1440
- rollback logic
1441
- """
1442
229
  global_object_square_logger.logger.error(e, exc_info=True)
1443
230
  output_content = get_api_output_in_standard_format(
1444
- message=messages["GENERIC_500"],
1445
- log=str(e),
231
+ message=messages["GENERIC_500"], log=str(e)
1446
232
  )
1447
233
  return JSONResponse(
1448
234
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1454,59 +240,15 @@ async def logout_apps_v0(
1454
240
  async def logout_all_v0(
1455
241
  access_token: Annotated[str, Header()],
1456
242
  ):
1457
-
1458
243
  try:
1459
- """
1460
- validation
1461
- """
1462
- try:
1463
- local_dict_access_token_payload = get_jwt_payload(
1464
- access_token, config_str_secret_key_for_access_token
1465
- )
1466
- except Exception as error:
1467
- output_content = get_api_output_in_standard_format(
1468
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1469
- )
1470
- raise HTTPException(
1471
- status_code=status.HTTP_400_BAD_REQUEST,
1472
- detail=output_content,
1473
- )
1474
- user_id = local_dict_access_token_payload["user_id"]
1475
-
1476
- """
1477
- main process
1478
- """
1479
- # delete session for user
1480
- global_object_square_database_helper.delete_rows_v0(
1481
- database_name=global_string_database_name,
1482
- schema_name=global_string_schema_name,
1483
- table_name=UserSession.__tablename__,
1484
- filters=FiltersV0(
1485
- root={
1486
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1487
- }
1488
- ),
1489
- )
1490
- """
1491
- return value
1492
- """
1493
- output_content = get_api_output_in_standard_format(
1494
- message=messages["LOGOUT_SUCCESSFUL"],
1495
- )
1496
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1497
- except HTTPException as http_exception:
1498
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1499
- return JSONResponse(
1500
- status_code=http_exception.status_code, content=http_exception.detail
1501
- )
244
+ return util_logout_all_v0(access_token=access_token)
245
+ except HTTPException as he:
246
+ global_object_square_logger.logger.error(he, exc_info=True)
247
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1502
248
  except Exception as e:
1503
- """
1504
- rollback logic
1505
- """
1506
249
  global_object_square_logger.logger.error(e, exc_info=True)
1507
250
  output_content = get_api_output_in_standard_format(
1508
- message=messages["GENERIC_500"],
1509
- log=str(e),
251
+ message=messages["GENERIC_500"], log=str(e)
1510
252
  )
1511
253
  return JSONResponse(
1512
254
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1520,121 +262,17 @@ async def update_username_v0(
1520
262
  access_token: Annotated[str, Header()],
1521
263
  ):
1522
264
  try:
1523
- """
1524
- validation
1525
- """
1526
- # validate access token
1527
- try:
1528
- local_dict_access_token_payload = get_jwt_payload(
1529
- access_token, config_str_secret_key_for_access_token
1530
- )
1531
- except Exception as error:
1532
- output_content = get_api_output_in_standard_format(
1533
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1534
- )
1535
- raise HTTPException(
1536
- status_code=status.HTTP_400_BAD_REQUEST,
1537
- detail=output_content,
1538
- )
1539
- user_id = local_dict_access_token_payload["user_id"]
1540
-
1541
- # validation for username
1542
- new_username = new_username.lower()
1543
- username_pattern = re.compile(r"^[a-z0-9._-]{2,20}$")
1544
- if not username_pattern.match(new_username):
1545
- output_content = get_api_output_in_standard_format(
1546
- message=messages["USERNAME_INVALID"],
1547
- log=f"username '{new_username}' is invalid. it must start and end with a letter, "
1548
- f"contain only lowercase letters, numbers, underscores, or hyphens, "
1549
- f"and not have consecutive separators.",
1550
- )
1551
- raise HTTPException(
1552
- status_code=status.HTTP_400_BAD_REQUEST,
1553
- detail=output_content,
1554
- )
1555
-
1556
- # validate user_id
1557
- local_list_user_response = global_object_square_database_helper.get_rows_v0(
1558
- database_name=global_string_database_name,
1559
- schema_name=global_string_schema_name,
1560
- table_name=User.__tablename__,
1561
- filters=FiltersV0(
1562
- root={
1563
- User.user_id.name: FilterConditionsV0(eq=user_id),
1564
- }
1565
- ),
1566
- )["data"]["main"]
1567
-
1568
- if len(local_list_user_response) != 1:
1569
- output_content = get_api_output_in_standard_format(
1570
- message=messages["INCORRECT_USER_ID"],
1571
- log=f"incorrect user_id: {user_id}.",
1572
- )
1573
- raise HTTPException(
1574
- status_code=status.HTTP_400_BAD_REQUEST,
1575
- detail=output_content,
1576
- )
1577
-
1578
- # validate new username
1579
- local_list_user_credentials_response = (
1580
- global_object_square_database_helper.get_rows_v0(
1581
- database_name=global_string_database_name,
1582
- schema_name=global_string_schema_name,
1583
- table_name=User.__tablename__,
1584
- filters=FiltersV0(
1585
- root={
1586
- User.user_username.name: FilterConditionsV0(eq=new_username),
1587
- }
1588
- ),
1589
- )["data"]["main"]
1590
- )
1591
- if len(local_list_user_credentials_response) != 0:
1592
- output_content = get_api_output_in_standard_format(
1593
- message=messages["USERNAME_ALREADY_EXISTS"],
1594
- log=f"{new_username} is taken.",
1595
- )
1596
- raise HTTPException(
1597
- status_code=status.HTTP_400_BAD_REQUEST,
1598
- detail=output_content,
1599
- )
1600
- """
1601
- main process
1602
- """
1603
- # edit the username
1604
- global_object_square_database_helper.edit_rows_v0(
1605
- database_name=global_string_database_name,
1606
- schema_name=global_string_schema_name,
1607
- table_name=User.__tablename__,
1608
- filters=FiltersV0(
1609
- root={
1610
- User.user_id.name: FilterConditionsV0(eq=user_id),
1611
- }
1612
- ),
1613
- data={
1614
- User.user_username.name: new_username,
1615
- },
1616
- )
1617
- """
1618
- return value
1619
- """
1620
- output_content = get_api_output_in_standard_format(
1621
- data={"main": {"user_id": user_id, "username": new_username}},
1622
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
1623
- )
1624
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1625
- except HTTPException as http_exception:
1626
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1627
- return JSONResponse(
1628
- status_code=http_exception.status_code, content=http_exception.detail
265
+ return util_update_username_v0(
266
+ new_username=new_username, access_token=access_token
1629
267
  )
268
+
269
+ except HTTPException as he:
270
+ global_object_square_logger.logger.error(he, exc_info=True)
271
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1630
272
  except Exception as e:
1631
- """
1632
- rollback logic
1633
- """
1634
273
  global_object_square_logger.logger.error(e, exc_info=True)
1635
274
  output_content = get_api_output_in_standard_format(
1636
- message=messages["GENERIC_500"],
1637
- log=str(e),
275
+ message=messages["GENERIC_500"], log=str(e)
1638
276
  )
1639
277
  return JSONResponse(
1640
278
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1649,121 +287,17 @@ async def delete_user_v0(
1649
287
  ):
1650
288
  password = body.password
1651
289
  try:
1652
- """
1653
- validation
1654
- """
1655
- # validate access token
1656
- try:
1657
- local_dict_access_token_payload = get_jwt_payload(
1658
- access_token, config_str_secret_key_for_access_token
1659
- )
1660
- except Exception as error:
1661
- output_content = get_api_output_in_standard_format(
1662
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1663
- )
1664
- raise HTTPException(
1665
- status_code=status.HTTP_400_BAD_REQUEST,
1666
- detail=output_content,
1667
- )
1668
- user_id = local_dict_access_token_payload["user_id"]
1669
-
1670
- # validate user_id
1671
- local_list_authentication_user_response = (
1672
- global_object_square_database_helper.get_rows_v0(
1673
- database_name=global_string_database_name,
1674
- schema_name=global_string_schema_name,
1675
- table_name=UserCredential.__tablename__,
1676
- filters=FiltersV0(
1677
- root={UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
1678
- ),
1679
- )["data"]["main"]
1680
- )
1681
- if len(local_list_authentication_user_response) != 1:
1682
- output_content = get_api_output_in_standard_format(
1683
- message=messages["INCORRECT_USER_ID"],
1684
- log=f"incorrect user_id: {user_id}.",
1685
- )
1686
- raise HTTPException(
1687
- status_code=status.HTTP_400_BAD_REQUEST,
1688
- detail=output_content,
1689
- )
1690
-
1691
- # validate password
1692
- local_dict_user = local_list_authentication_user_response[0]
1693
- if not (
1694
- bcrypt.checkpw(
1695
- password.encode("utf-8"),
1696
- local_dict_user[
1697
- UserCredential.user_credential_hashed_password.name
1698
- ].encode("utf-8"),
1699
- )
1700
- ):
1701
- output_content = get_api_output_in_standard_format(
1702
- message=messages["INCORRECT_PASSWORD"],
1703
- log=f"incorrect password for user_id {user_id}.",
1704
- )
1705
- raise HTTPException(
1706
- status_code=status.HTTP_400_BAD_REQUEST,
1707
- detail=output_content,
1708
- )
1709
- """
1710
- main process
1711
- """
1712
- # fetch user profile photo storage token
1713
- user_profile_storage_token = global_object_square_database_helper.get_rows_v0(
1714
- database_name=global_string_database_name,
1715
- schema_name=global_string_schema_name,
1716
- table_name=UserProfile.__tablename__,
1717
- filters=FiltersV0(
1718
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
1719
- ),
1720
- columns=[UserProfile.user_profile_photo_storage_token.name],
1721
- )["data"]["main"][0][UserProfile.user_profile_photo_storage_token.name]
1722
-
1723
- # delete the user.
1724
- global_object_square_database_helper.delete_rows_v0(
1725
- database_name=global_string_database_name,
1726
- schema_name=global_string_schema_name,
1727
- table_name=User.__tablename__,
1728
- filters=FiltersV0(
1729
- root={
1730
- User.user_id.name: FilterConditionsV0(eq=user_id),
1731
- }
1732
- ),
1733
- )
1734
- # delete profile photo if exists
1735
- if user_profile_storage_token:
1736
- try:
1737
- global_object_square_file_store_helper.delete_file_v0(
1738
- list_file_storage_token=[user_profile_storage_token]
1739
- )
1740
- except HTTPError as he:
1741
- global_object_square_logger.warning(
1742
- f"Failed to delete user profile photo with storage token {user_profile_storage_token}. "
1743
- f"Error: {he.response.text}",
1744
- exc_info=True,
1745
- )
1746
- """
1747
- return value
1748
- """
1749
- output_content = get_api_output_in_standard_format(
1750
- message=messages["GENERIC_DELETE_SUCCESSFUL"],
1751
- log=f"user_id: {user_id} deleted successfully.",
1752
- )
1753
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1754
- except HTTPException as http_exception:
1755
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1756
- return JSONResponse(
1757
- status_code=http_exception.status_code, content=http_exception.detail
290
+ return util_delete_user_v0(
291
+ password=password,
292
+ access_token=access_token,
1758
293
  )
294
+ except HTTPException as he:
295
+ global_object_square_logger.logger.error(he, exc_info=True)
296
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1759
297
  except Exception as e:
1760
- """
1761
- rollback logic
1762
- """
1763
298
  global_object_square_logger.logger.error(e, exc_info=True)
1764
299
  output_content = get_api_output_in_standard_format(
1765
- message=messages["GENERIC_500"],
1766
- log=str(e),
300
+ message=messages["GENERIC_500"], log=str(e)
1767
301
  )
1768
302
  return JSONResponse(
1769
303
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1781,203 +315,20 @@ async def update_password_v0(
1781
315
  logout_other_sessions = body.logout_other_sessions
1782
316
  preserve_session_refresh_token = body.preserve_session_refresh_token
1783
317
  try:
1784
- """
1785
- validation
1786
- """
1787
- # validate access token
1788
- try:
1789
- local_dict_access_token_payload = get_jwt_payload(
1790
- access_token, config_str_secret_key_for_access_token
1791
- )
1792
- except Exception as error:
1793
- output_content = get_api_output_in_standard_format(
1794
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1795
- )
1796
- raise HTTPException(
1797
- status_code=status.HTTP_400_BAD_REQUEST,
1798
- detail=output_content,
1799
- )
1800
- user_id = local_dict_access_token_payload["user_id"]
1801
-
1802
- # validate user_id
1803
- local_list_authentication_user_response = (
1804
- global_object_square_database_helper.get_rows_v0(
1805
- database_name=global_string_database_name,
1806
- schema_name=global_string_schema_name,
1807
- table_name=UserCredential.__tablename__,
1808
- filters=FiltersV0(
1809
- root={UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
1810
- ),
1811
- )["data"]["main"]
1812
- )
1813
- if len(local_list_authentication_user_response) != 1:
1814
- output_content = get_api_output_in_standard_format(
1815
- message=messages["INCORRECT_USER_ID"],
1816
- log=f"incorrect user_id: {user_id}.",
1817
- )
1818
- raise HTTPException(
1819
- status_code=status.HTTP_400_BAD_REQUEST,
1820
- detail=output_content,
1821
- )
1822
- # check if user has SELF auth provider
1823
- local_list_response_user_auth_provider = (
1824
- global_object_square_database_helper.get_rows_v0(
1825
- database_name=global_string_database_name,
1826
- schema_name=global_string_schema_name,
1827
- table_name=UserAuthProvider.__tablename__,
1828
- filters=FiltersV0(
1829
- root={
1830
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
1831
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
1832
- eq=AuthProviderEnum.SELF.value
1833
- ),
1834
- }
1835
- ),
1836
- )["data"]["main"]
1837
- )
1838
- if len(local_list_response_user_auth_provider) != 1:
1839
- output_content = get_api_output_in_standard_format(
1840
- message=messages["INCORRECT_AUTH_PROVIDER"],
1841
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
1842
- )
1843
- raise HTTPException(
1844
- status_code=status.HTTP_400_BAD_REQUEST,
1845
- detail=output_content,
1846
- )
1847
- # check if user has credentials (might not be set in case of errors in registration.)
1848
- local_list_response_user = global_object_square_database_helper.get_rows_v0(
1849
- database_name=global_string_database_name,
1850
- schema_name=global_string_schema_name,
1851
- table_name=User.__tablename__,
1852
- filters=FiltersV0(root={User.user_id.name: FilterConditionsV0(eq=user_id)}),
1853
- )["data"]["main"]
1854
- if len(local_list_response_user) != 1:
1855
- output_content = get_api_output_in_standard_format(
1856
- message=messages["MALFORMED_USER"],
1857
- log=f"user_id: {user_id} does not have credentials.",
1858
- )
1859
- raise HTTPException(
1860
- status_code=status.HTTP_400_BAD_REQUEST,
1861
- detail=output_content,
1862
- )
1863
- # validate password
1864
- local_dict_user = local_list_authentication_user_response[0]
1865
- if not (
1866
- bcrypt.checkpw(
1867
- old_password.encode("utf-8"),
1868
- local_dict_user[
1869
- UserCredential.user_credential_hashed_password.name
1870
- ].encode("utf-8"),
1871
- )
1872
- ):
1873
- output_content = get_api_output_in_standard_format(
1874
- message=messages["INCORRECT_PASSWORD"],
1875
- log=f"incorrect password for user_id {user_id}.",
1876
- )
1877
- raise HTTPException(
1878
- status_code=status.HTTP_400_BAD_REQUEST,
1879
- detail=output_content,
1880
- )
1881
- # check if provided refresh token is valid
1882
- if preserve_session_refresh_token:
1883
- local_dict_token_payload = get_jwt_payload(
1884
- preserve_session_refresh_token, config_str_secret_key_for_refresh_token
1885
- )
1886
- local_list_response_user_session = global_object_square_database_helper.get_rows_v0(
1887
- database_name=global_string_database_name,
1888
- schema_name=global_string_schema_name,
1889
- table_name=UserSession.__tablename__,
1890
- filters=FiltersV0(
1891
- root={
1892
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1893
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1894
- eq=preserve_session_refresh_token
1895
- ),
1896
- }
1897
- ),
1898
- )[
1899
- "data"
1900
- ][
1901
- "main"
1902
- ]
1903
- if len(local_list_response_user_session) != 1:
1904
- output_content = get_api_output_in_standard_format(
1905
- message=messages["INCORRECT_REFRESH_TOKEN"],
1906
- log=f"incorrect refresh token: {preserve_session_refresh_token}.",
1907
- )
1908
- raise HTTPException(
1909
- status_code=status.HTTP_400_BAD_REQUEST,
1910
- detail=output_content,
1911
- )
1912
- """
1913
- main process
1914
- """
1915
- # update the password
1916
- local_str_hashed_password = bcrypt.hashpw(
1917
- new_password.encode("utf-8"), bcrypt.gensalt()
1918
- ).decode("utf-8")
1919
- global_object_square_database_helper.edit_rows_v0(
1920
- database_name=global_string_database_name,
1921
- schema_name=global_string_schema_name,
1922
- table_name=UserCredential.__tablename__,
1923
- filters=FiltersV0(
1924
- root={
1925
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
1926
- }
1927
- ),
1928
- data={
1929
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
1930
- },
1931
- )
1932
- if logout_other_sessions:
1933
- if preserve_session_refresh_token:
1934
- # delete all sessions for user except the one with the given refresh token
1935
- global_object_square_database_helper.delete_rows_v0(
1936
- database_name=global_string_database_name,
1937
- schema_name=global_string_schema_name,
1938
- table_name=UserSession.__tablename__,
1939
- filters=FiltersV0(
1940
- root={
1941
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1942
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1943
- ne=preserve_session_refresh_token
1944
- ),
1945
- }
1946
- ),
1947
- )
1948
- else:
1949
- # delete all sessions for user
1950
- global_object_square_database_helper.delete_rows_v0(
1951
- database_name=global_string_database_name,
1952
- schema_name=global_string_schema_name,
1953
- table_name=UserSession.__tablename__,
1954
- filters=FiltersV0(
1955
- root={
1956
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1957
- }
1958
- ),
1959
- )
1960
- """
1961
- return value
1962
- """
1963
- output_content = get_api_output_in_standard_format(
1964
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
1965
- log=f"password for user_id: {user_id} updated successfully.",
1966
- )
1967
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1968
- except HTTPException as http_exception:
1969
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1970
- return JSONResponse(
1971
- status_code=http_exception.status_code, content=http_exception.detail
1972
- )
318
+ return util_update_password_v0(
319
+ old_password=old_password,
320
+ new_password=new_password,
321
+ logout_other_sessions=logout_other_sessions,
322
+ preserve_session_refresh_token=preserve_session_refresh_token,
323
+ access_token=access_token,
324
+ )
325
+ except HTTPException as he:
326
+ global_object_square_logger.logger.error(he, exc_info=True)
327
+ return JSONResponse(status_code=he.status_code, content=he.detail)
1973
328
  except Exception as e:
1974
- """
1975
- rollback logic
1976
- """
1977
329
  global_object_square_logger.logger.error(e, exc_info=True)
1978
330
  output_content = get_api_output_in_standard_format(
1979
- message=messages["GENERIC_500"],
1980
- log=str(e),
331
+ message=messages["GENERIC_500"], log=str(e)
1981
332
  )
1982
333
  return JSONResponse(
1983
334
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1991,102 +342,19 @@ async def validate_and_get_payload_from_token_v0(
1991
342
  token: Annotated[str, Header()],
1992
343
  token_type: TokenType = Query(...),
1993
344
  ):
1994
-
1995
345
  try:
1996
- """
1997
- validation
1998
- """
1999
- # validate token
2000
- try:
2001
- local_dict_token_payload = None
2002
- if token_type == TokenType.access_token:
2003
- local_dict_token_payload = get_jwt_payload(
2004
- token, config_str_secret_key_for_access_token
2005
- )
2006
- elif token_type == TokenType.refresh_token:
2007
- local_dict_token_payload = get_jwt_payload(
2008
- token, config_str_secret_key_for_refresh_token
2009
- )
2010
- local_list_response_user_session = global_object_square_database_helper.get_rows_v0(
2011
- database_name=global_string_database_name,
2012
- schema_name=global_string_schema_name,
2013
- table_name=UserSession.__tablename__,
2014
- filters=FiltersV0(
2015
- root={
2016
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
2017
- eq=token
2018
- ),
2019
- UserSession.user_id.name: FilterConditionsV0(
2020
- eq=local_dict_token_payload["user_id"]
2021
- ),
2022
- }
2023
- ),
2024
- )[
2025
- "data"
2026
- ][
2027
- "main"
2028
- ]
2029
- if len(local_list_response_user_session) != 1:
2030
- output_content = get_api_output_in_standard_format(
2031
- message=messages["INCORRECT_REFRESH_TOKEN"],
2032
- log="refresh token valid but not present in database.",
2033
- )
2034
- raise HTTPException(
2035
- status_code=status.HTTP_400_BAD_REQUEST,
2036
- detail=output_content,
2037
- )
2038
- if local_dict_token_payload["app_id"] != app_id:
2039
- output_content = get_api_output_in_standard_format(
2040
- message=messages["GENERIC_400"],
2041
- log=f"app_id: {app_id} does not match with token app_id: {local_dict_token_payload['app_id']}.",
2042
- )
2043
- raise HTTPException(
2044
- status_code=status.HTTP_400_BAD_REQUEST,
2045
- detail=output_content,
2046
- )
2047
- except HTTPException as http_exception:
2048
- raise
2049
- except Exception as error:
2050
- output_content = None
2051
- if token_type == TokenType.access_token:
2052
- output_content = get_api_output_in_standard_format(
2053
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2054
- )
2055
- elif token_type == TokenType.refresh_token:
2056
- output_content = get_api_output_in_standard_format(
2057
- message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
2058
- )
2059
-
2060
- raise HTTPException(
2061
- status_code=status.HTTP_400_BAD_REQUEST,
2062
- detail=output_content,
2063
- )
2064
-
2065
- """
2066
- main process
2067
- """
2068
- # pass
2069
- """
2070
- return value
2071
- """
2072
- output_content = get_api_output_in_standard_format(
2073
- message=messages["GENERIC_READ_SUCCESSFUL"],
2074
- data={"main": local_dict_token_payload},
2075
- )
2076
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2077
- except HTTPException as http_exception:
2078
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2079
- return JSONResponse(
2080
- status_code=http_exception.status_code, content=http_exception.detail
2081
- )
346
+ return util_validate_and_get_payload_from_token_v0(
347
+ app_id=app_id,
348
+ token=token,
349
+ token_type=token_type,
350
+ )
351
+ except HTTPException as he:
352
+ global_object_square_logger.logger.error(he, exc_info=True)
353
+ return JSONResponse(status_code=he.status_code, content=he.detail)
2082
354
  except Exception as e:
2083
- """
2084
- rollback logic
2085
- """
2086
355
  global_object_square_logger.logger.error(e, exc_info=True)
2087
356
  output_content = get_api_output_in_standard_format(
2088
- message=messages["GENERIC_500"],
2089
- log=str(e),
357
+ message=messages["GENERIC_500"], log=str(e)
2090
358
  )
2091
359
  return JSONResponse(
2092
360
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2100,221 +368,22 @@ async def update_user_recovery_methods_v0(
2100
368
  recovery_methods_to_add: List[RecoveryMethodEnum] = None,
2101
369
  recovery_methods_to_remove: List[RecoveryMethodEnum] = None,
2102
370
  ):
2103
- if recovery_methods_to_add is None:
2104
- recovery_methods_to_add = []
2105
- if recovery_methods_to_remove is None:
2106
- recovery_methods_to_remove = []
2107
371
  try:
2108
-
2109
- """
2110
- validation
2111
- """
2112
- # validate access token
2113
- try:
2114
- local_dict_access_token_payload = get_jwt_payload(
2115
- access_token, config_str_secret_key_for_access_token
2116
- )
2117
- except Exception as error:
2118
- output_content = get_api_output_in_standard_format(
2119
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2120
- )
2121
- raise HTTPException(
2122
- status_code=status.HTTP_400_BAD_REQUEST,
2123
- detail=output_content,
2124
- )
2125
- user_id = local_dict_access_token_payload["user_id"]
2126
-
2127
- recovery_methods_to_add = list(set(x.value for x in recovery_methods_to_add))
2128
- recovery_methods_to_remove = list(
2129
- set(x.value for x in recovery_methods_to_remove)
2130
- )
2131
-
2132
- # check if recovery_methods_to_add and recovery_methods_to_remove don't have common ids.
2133
- local_list_common_recovery_methods = set(recovery_methods_to_add) & set(
2134
- recovery_methods_to_remove
2135
- )
2136
- if len(local_list_common_recovery_methods) > 0:
2137
- output_content = get_api_output_in_standard_format(
2138
- message=messages["GENERIC_400"],
2139
- log=f"invalid recovery_methods: {list(local_list_common_recovery_methods)}, present in both add list and remove list.",
2140
- )
2141
- raise HTTPException(
2142
- status_code=status.HTTP_400_BAD_REQUEST,
2143
- detail=output_content,
2144
- )
2145
- # check if user's email is verified in user profile.
2146
- # maybe too harsh to reject the request entirely,
2147
- # but for practical purposes this api call should be used for 1 recovery method at a time, so it's not too bad.
2148
- if RecoveryMethodEnum.EMAIL.value in recovery_methods_to_add:
2149
- local_list_response_user_profile = (
2150
- global_object_square_database_helper.get_rows_v0(
2151
- database_name=global_string_database_name,
2152
- schema_name=global_string_schema_name,
2153
- table_name=UserProfile.__tablename__,
2154
- filters=FiltersV0(
2155
- root={
2156
- UserProfile.user_id.name: FilterConditionsV0(eq=user_id),
2157
- }
2158
- ),
2159
- )["data"]["main"]
2160
- )
2161
- if len(local_list_response_user_profile) != 1:
2162
- # maybe this should raise 500 as this error will not occur if code runs correctly.
2163
- output_content = get_api_output_in_standard_format(
2164
- message=messages["GENERIC_400"],
2165
- log=f"user_id: {user_id} does not have a profile.",
2166
- )
2167
- raise HTTPException(
2168
- status_code=status.HTTP_400_BAD_REQUEST,
2169
- detail=output_content,
2170
- )
2171
- local_dict_user_profile = local_list_response_user_profile[0]
2172
- if not local_dict_user_profile[
2173
- UserProfile.user_profile_email_verified.name
2174
- ]:
2175
- output_content = get_api_output_in_standard_format(
2176
- message=messages["EMAIL_NOT_VERIFIED"],
2177
- log=f"user_id: {user_id} does not have email verified.",
2178
- )
2179
- raise HTTPException(
2180
- status_code=status.HTTP_400_BAD_REQUEST,
2181
- detail=output_content,
2182
- )
2183
- """
2184
- main process
2185
- """
2186
- # logic for adding new recovery_methods
2187
- local_list_response_user_recovery_methods = (
2188
- global_object_square_database_helper.get_rows_v0(
2189
- database_name=global_string_database_name,
2190
- schema_name=global_string_schema_name,
2191
- table_name=UserRecoveryMethod.__tablename__,
2192
- filters=FiltersV0(
2193
- root={
2194
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id)
2195
- }
2196
- ),
2197
- )["data"]["main"]
2198
- )
2199
- local_list_new_recovery_methods = [
2200
- {
2201
- UserRecoveryMethod.user_id.name: user_id,
2202
- UserRecoveryMethod.user_recovery_method_name.name: x,
2203
- }
2204
- for x in recovery_methods_to_add
2205
- if x
2206
- not in [
2207
- y[UserRecoveryMethod.user_recovery_method_name.name]
2208
- for y in local_list_response_user_recovery_methods
2209
- ]
2210
- ]
2211
- if len(local_list_new_recovery_methods) > 0:
2212
- global_object_square_database_helper.insert_rows_v0(
2213
- database_name=global_string_database_name,
2214
- schema_name=global_string_schema_name,
2215
- table_name=UserRecoveryMethod.__tablename__,
2216
- data=local_list_new_recovery_methods,
2217
- )
2218
-
2219
- # logic for removing recovery_methods
2220
- remove_old_backup_codes = (
2221
- RecoveryMethodEnum.BACKUP_CODE.value in recovery_methods_to_remove
2222
- )
2223
- old_backup_code_hashes = None
2224
- if remove_old_backup_codes:
2225
- # delete existing backup codes if any
2226
- old_backup_code_hashes = global_object_square_database_helper.get_rows_v0(
2227
- database_name=global_string_database_name,
2228
- schema_name=global_string_schema_name,
2229
- table_name=UserVerificationCode.__tablename__,
2230
- filters=FiltersV0(
2231
- root={
2232
- UserVerificationCode.user_id.name: FilterConditionsV0(
2233
- eq=user_id
2234
- ),
2235
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2236
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2237
- ),
2238
- }
2239
- ),
2240
- columns=[UserVerificationCode.user_verification_code_hash.name],
2241
- )["data"]["main"]
2242
- global_object_square_database_helper.delete_rows_v0(
2243
- database_name=global_string_database_name,
2244
- schema_name=global_string_schema_name,
2245
- table_name=UserRecoveryMethod.__tablename__,
2246
- filters=FiltersV0(
2247
- root={
2248
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2249
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2250
- in_=recovery_methods_to_remove
2251
- ),
2252
- }
2253
- ),
2254
- )
2255
- if remove_old_backup_codes and old_backup_code_hashes:
2256
- global_object_square_database_helper.delete_rows_v0(
2257
- database_name=global_string_database_name,
2258
- schema_name=global_string_schema_name,
2259
- table_name=UserVerificationCode.__tablename__,
2260
- filters=FiltersV0(
2261
- root={
2262
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2263
- in_=[
2264
- x[UserVerificationCode.user_verification_code_hash.name]
2265
- for x in old_backup_code_hashes
2266
- ]
2267
- ),
2268
- }
2269
- ),
2270
- )
2271
-
2272
- """
2273
- return value
2274
- """
2275
- # get latest recovery_methods
2276
- local_list_response_user_recovery_methods = (
2277
- global_object_square_database_helper.get_rows_v0(
2278
- database_name=global_string_database_name,
2279
- schema_name=global_string_schema_name,
2280
- table_name=UserRecoveryMethod.__tablename__,
2281
- filters=FiltersV0(
2282
- root={
2283
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id)
2284
- }
2285
- ),
2286
- )["data"]["main"]
2287
- )
2288
- output_content = get_api_output_in_standard_format(
2289
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
2290
- data={
2291
- "main": [
2292
- x[UserRecoveryMethod.user_recovery_method_name.name]
2293
- for x in local_list_response_user_recovery_methods
2294
- ]
2295
- },
2296
- )
2297
- return JSONResponse(
2298
- status_code=status.HTTP_200_OK,
2299
- content=output_content,
2300
- )
2301
- except HTTPException as http_exception:
2302
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2303
- return JSONResponse(
2304
- status_code=http_exception.status_code, content=http_exception.detail
2305
- )
372
+ return util_update_user_recovery_methods_v0(
373
+ access_token=access_token,
374
+ recovery_methods_to_add=recovery_methods_to_add,
375
+ recovery_methods_to_remove=recovery_methods_to_remove,
376
+ )
377
+ except HTTPException as he:
378
+ global_object_square_logger.logger.error(he, exc_info=True)
379
+ return JSONResponse(status_code=he.status_code, content=he.detail)
2306
380
  except Exception as e:
2307
- """
2308
- rollback logic
2309
- """
2310
381
  global_object_square_logger.logger.error(e, exc_info=True)
2311
382
  output_content = get_api_output_in_standard_format(
2312
- message=messages["GENERIC_500"],
2313
- log=str(e),
383
+ message=messages["GENERIC_500"], log=str(e)
2314
384
  )
2315
385
  return JSONResponse(
2316
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
2317
- content=output_content,
386
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
2318
387
  )
2319
388
 
2320
389
 
@@ -2323,136 +392,17 @@ async def update_user_recovery_methods_v0(
2323
392
  async def generate_account_backup_codes_v0(
2324
393
  access_token: Annotated[str, Header()],
2325
394
  ):
2326
-
2327
395
  try:
2328
- """
2329
- validation
2330
- """
2331
- try:
2332
- local_dict_access_token_payload = get_jwt_payload(
2333
- access_token, config_str_secret_key_for_access_token
2334
- )
2335
- except Exception as error:
2336
- output_content = get_api_output_in_standard_format(
2337
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2338
- )
2339
- raise HTTPException(
2340
- status_code=status.HTTP_400_BAD_REQUEST,
2341
- detail=output_content,
2342
- )
2343
- user_id = local_dict_access_token_payload["user_id"]
2344
- # check if user has recovery method enabled
2345
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2346
- database_name=global_string_database_name,
2347
- schema_name=global_string_schema_name,
2348
- table_name=UserRecoveryMethod.__tablename__,
2349
- filters=FiltersV0(
2350
- root={
2351
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2352
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2353
- eq=RecoveryMethodEnum.BACKUP_CODE.value
2354
- ),
2355
- }
2356
- ),
2357
- )[
2358
- "data"
2359
- ][
2360
- "main"
2361
- ]
2362
- if len(local_list_response_user_recovery_methods) != 1:
2363
- output_content = get_api_output_in_standard_format(
2364
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2365
- log=f"user_id: {user_id} does not have backup codes recovery method enabled.",
2366
- )
2367
- raise HTTPException(
2368
- status_code=status.HTTP_400_BAD_REQUEST,
2369
- detail=output_content,
2370
- )
2371
- """
2372
- main process
2373
- """
2374
- # delete existing backup codes if any
2375
- old_backup_code_hashes = global_object_square_database_helper.get_rows_v0(
2376
- database_name=global_string_database_name,
2377
- schema_name=global_string_schema_name,
2378
- table_name=UserVerificationCode.__tablename__,
2379
- filters=FiltersV0(
2380
- root={
2381
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2382
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2383
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2384
- ),
2385
- }
2386
- ),
2387
- columns=[UserVerificationCode.user_verification_code_hash.name],
2388
- )["data"]["main"]
2389
-
2390
- # generate backup codes
2391
- backup_codes = []
2392
- db_data = []
2393
-
2394
- for i in range(NUMBER_OF_RECOVERY_CODES):
2395
- backup_code = str(uuid.uuid4())
2396
- backup_codes.append(backup_code)
2397
- # hash the backup code
2398
- local_str_hashed_backup_code = bcrypt.hashpw(
2399
- backup_code.encode("utf-8"), bcrypt.gensalt()
2400
- ).decode("utf-8")
2401
-
2402
- db_data.append(
2403
- {
2404
- UserVerificationCode.user_id.name: user_id,
2405
- UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value,
2406
- UserVerificationCode.user_verification_code_hash.name: local_str_hashed_backup_code,
2407
- }
2408
- )
2409
- global_object_square_database_helper.insert_rows_v0(
2410
- database_name=global_string_database_name,
2411
- schema_name=global_string_schema_name,
2412
- table_name=UserVerificationCode.__tablename__,
2413
- data=db_data,
2414
- )
2415
- global_object_square_database_helper.delete_rows_v0(
2416
- database_name=global_string_database_name,
2417
- schema_name=global_string_schema_name,
2418
- table_name=UserVerificationCode.__tablename__,
2419
- filters=FiltersV0(
2420
- root={
2421
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2422
- in_=[
2423
- x[UserVerificationCode.user_verification_code_hash.name]
2424
- for x in old_backup_code_hashes
2425
- ]
2426
- ),
2427
- }
2428
- ),
2429
- )
2430
- """
2431
- return value
2432
- """
2433
- output_content = get_api_output_in_standard_format(
2434
- message=messages["GENERIC_CREATION_SUCCESSFUL"],
2435
- data={
2436
- "main": {
2437
- "user_id": user_id,
2438
- "backup_codes": backup_codes,
2439
- }
2440
- },
2441
- )
2442
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2443
- except HTTPException as http_exception:
2444
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2445
- return JSONResponse(
2446
- status_code=http_exception.status_code, content=http_exception.detail
396
+ return util_generate_account_backup_codes_v0(
397
+ access_token=access_token,
2447
398
  )
399
+ except HTTPException as he:
400
+ global_object_square_logger.logger.error(he, exc_info=True)
401
+ return JSONResponse(status_code=he.status_code, content=he.detail)
2448
402
  except Exception as e:
2449
- """
2450
- rollback logic
2451
- """
2452
403
  global_object_square_logger.logger.error(e, exc_info=True)
2453
404
  output_content = get_api_output_in_standard_format(
2454
- message=messages["GENERIC_500"],
2455
- log=str(e),
405
+ message=messages["GENERIC_500"], log=str(e)
2456
406
  )
2457
407
  return JSONResponse(
2458
408
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2470,272 +420,20 @@ async def reset_password_and_login_using_backup_code_v0(
2470
420
  app_id = body.app_id
2471
421
  logout_other_sessions = body.logout_other_sessions
2472
422
  try:
2473
- """
2474
- validation
2475
- """
2476
- # validate username
2477
- local_list_authentication_user_response = (
2478
- global_object_square_database_helper.get_rows_v0(
2479
- database_name=global_string_database_name,
2480
- schema_name=global_string_schema_name,
2481
- table_name=User.__tablename__,
2482
- filters=FiltersV0(
2483
- root={User.user_username.name: FilterConditionsV0(eq=username)}
2484
- ),
2485
- )["data"]["main"]
2486
- )
2487
- if len(local_list_authentication_user_response) != 1:
2488
- output_content = get_api_output_in_standard_format(
2489
- message=messages["INCORRECT_USERNAME"],
2490
- log=f"incorrect username: {username}.",
2491
- )
2492
- raise HTTPException(
2493
- status_code=status.HTTP_400_BAD_REQUEST,
2494
- detail=output_content,
2495
- )
2496
- user_id = local_list_authentication_user_response[0][User.user_id.name]
2497
- # check if user has SELF auth provider
2498
- local_list_response_user_auth_provider = (
2499
- global_object_square_database_helper.get_rows_v0(
2500
- database_name=global_string_database_name,
2501
- schema_name=global_string_schema_name,
2502
- table_name=UserAuthProvider.__tablename__,
2503
- filters=FiltersV0(
2504
- root={
2505
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
2506
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
2507
- eq=AuthProviderEnum.SELF.value
2508
- ),
2509
- }
2510
- ),
2511
- )["data"]["main"]
2512
- )
2513
- if len(local_list_response_user_auth_provider) != 1:
2514
- output_content = get_api_output_in_standard_format(
2515
- message=messages["INCORRECT_AUTH_PROVIDER"],
2516
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
2517
- )
2518
- raise HTTPException(
2519
- status_code=status.HTTP_400_BAD_REQUEST,
2520
- detail=output_content,
2521
- )
2522
- # check if user has recovery method enabled
2523
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2524
- database_name=global_string_database_name,
2525
- schema_name=global_string_schema_name,
2526
- table_name=UserRecoveryMethod.__tablename__,
2527
- filters=FiltersV0(
2528
- root={
2529
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2530
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2531
- eq=RecoveryMethodEnum.BACKUP_CODE.value
2532
- ),
2533
- }
2534
- ),
2535
- )[
2536
- "data"
2537
- ][
2538
- "main"
2539
- ]
2540
- if len(local_list_response_user_recovery_methods) != 1:
2541
- output_content = get_api_output_in_standard_format(
2542
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2543
- log=f"user_id: {user_id} does not have backup codes recovery method enabled.",
2544
- )
2545
- raise HTTPException(
2546
- status_code=status.HTTP_400_BAD_REQUEST,
2547
- detail=output_content,
2548
- )
2549
- # validate if user is assigned to the app.
2550
- # not checking [skipping] if the app exists, as it is not required for this endpoint.
2551
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
2552
- database_name=global_string_database_name,
2553
- schema_name=global_string_schema_name,
2554
- table_name=UserApp.__tablename__,
2555
- filters=FiltersV0(
2556
- root={
2557
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
2558
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
2559
- }
2560
- ),
2561
- )["data"]["main"]
2562
- if len(local_list_response_user_app) == 0:
2563
- output_content = get_api_output_in_standard_format(
2564
- message=messages["GENERIC_400"],
2565
- log=f"user_id: {user_id} is not assigned to app_id: {app_id}.",
2566
- )
2567
- raise HTTPException(
2568
- status_code=status.HTTP_400_BAD_REQUEST,
2569
- detail=output_content,
2570
- )
2571
- """
2572
- main process
2573
- """
2574
- # validate backup code
2575
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
2576
- database_name=global_string_database_name,
2577
- schema_name=global_string_schema_name,
2578
- table_name=UserVerificationCode.__tablename__,
2579
- filters=FiltersV0(
2580
- root={
2581
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2582
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2583
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2584
- ),
2585
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
2586
- is_null=True
2587
- ),
2588
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
2589
- is_null=True
2590
- ),
2591
- }
2592
- ),
2593
- columns=[UserVerificationCode.user_verification_code_hash.name],
2594
- )[
2595
- "data"
2596
- ][
2597
- "main"
2598
- ]
2599
- # find the backup code in the list
2600
- local_list_response_user_verification_code = [
2601
- x
2602
- for x in local_list_response_user_verification_code
2603
- if bcrypt.checkpw(
2604
- backup_code.encode("utf-8"),
2605
- x[UserVerificationCode.user_verification_code_hash.name].encode(
2606
- "utf-8"
2607
- ),
2608
- )
2609
- ]
2610
- if len(local_list_response_user_verification_code) != 1:
2611
- output_content = get_api_output_in_standard_format(
2612
- message=messages["INCORRECT_BACKUP_CODE"],
2613
- log=f"incorrect backup code: {backup_code} for user_id: {user_id}.",
2614
- )
2615
- raise HTTPException(
2616
- status_code=status.HTTP_400_BAD_REQUEST,
2617
- detail=output_content,
2618
- )
2619
- # hash the new password
2620
- local_str_hashed_password = bcrypt.hashpw(
2621
- new_password.encode("utf-8"), bcrypt.gensalt()
2622
- ).decode("utf-8")
2623
- # update the password
2624
- global_object_square_database_helper.edit_rows_v0(
2625
- database_name=global_string_database_name,
2626
- schema_name=global_string_schema_name,
2627
- table_name=UserCredential.__tablename__,
2628
- filters=FiltersV0(
2629
- root={
2630
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
2631
- }
2632
- ),
2633
- data={
2634
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
2635
- },
2636
- )
2637
- # mark the backup code as used
2638
- global_object_square_database_helper.edit_rows_v0(
2639
- database_name=global_string_database_name,
2640
- schema_name=global_string_schema_name,
2641
- table_name=UserVerificationCode.__tablename__,
2642
- filters=FiltersV0(
2643
- root={
2644
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2645
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2646
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2647
- ),
2648
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2649
- eq=local_list_response_user_verification_code[0][
2650
- UserVerificationCode.user_verification_code_hash.name
2651
- ]
2652
- ),
2653
- }
2654
- ),
2655
- data={
2656
- UserVerificationCode.user_verification_code_used_at.name: datetime.now(
2657
- timezone.utc
2658
- ).strftime("%Y-%m-%d %H:%M:%S.%f+00"),
2659
- },
2660
- )
2661
- if logout_other_sessions:
2662
- # delete all sessions for user
2663
- global_object_square_database_helper.delete_rows_v0(
2664
- database_name=global_string_database_name,
2665
- schema_name=global_string_schema_name,
2666
- table_name=UserSession.__tablename__,
2667
- filters=FiltersV0(
2668
- root={
2669
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
2670
- }
2671
- ),
2672
- )
2673
- # generate access token and refresh token
2674
- local_dict_access_token_payload = {
2675
- "app_id": app_id,
2676
- "user_id": user_id,
2677
- "exp": datetime.now(timezone.utc)
2678
- + timedelta(minutes=config_int_access_token_valid_minutes),
2679
- }
2680
- local_str_access_token = jwt.encode(
2681
- local_dict_access_token_payload, config_str_secret_key_for_access_token
2682
- )
2683
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
2684
- minutes=config_int_refresh_token_valid_minutes
2685
- )
2686
- local_dict_refresh_token_payload = {
2687
- "app_id": app_id,
2688
- "user_id": user_id,
2689
- "exp": local_object_refresh_token_expiry_time,
2690
- }
2691
- local_str_refresh_token = jwt.encode(
2692
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
2693
- )
2694
- # insert the refresh token in the database
2695
- global_object_square_database_helper.insert_rows_v0(
2696
- database_name=global_string_database_name,
2697
- schema_name=global_string_schema_name,
2698
- table_name=UserSession.__tablename__,
2699
- data=[
2700
- {
2701
- UserSession.user_id.name: user_id,
2702
- UserSession.app_id.name: app_id,
2703
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
2704
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
2705
- "%Y-%m-%d %H:%M:%S.%f+00"
2706
- ),
2707
- }
2708
- ],
2709
- )
2710
- """
2711
- return value
2712
- """
2713
- output_content = get_api_output_in_standard_format(
2714
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
2715
- data={
2716
- "main": {
2717
- "user_id": user_id,
2718
- "access_token": local_str_access_token,
2719
- "refresh_token": local_str_refresh_token,
2720
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
2721
- }
2722
- },
2723
- )
2724
-
2725
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2726
- except HTTPException as http_exception:
2727
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2728
- return JSONResponse(
2729
- status_code=http_exception.status_code, content=http_exception.detail
2730
- )
423
+ return util_reset_password_and_login_using_backup_code_v0(
424
+ backup_code=backup_code,
425
+ username=username,
426
+ new_password=new_password,
427
+ app_id=app_id,
428
+ logout_other_sessions=logout_other_sessions,
429
+ )
430
+ except HTTPException as he:
431
+ global_object_square_logger.logger.error(he, exc_info=True)
432
+ return JSONResponse(status_code=he.status_code, content=he.detail)
2731
433
  except Exception as e:
2732
- """
2733
- rollback logic
2734
- """
2735
434
  global_object_square_logger.logger.error(e, exc_info=True)
2736
435
  output_content = get_api_output_in_standard_format(
2737
- message=messages["GENERIC_500"],
2738
- log=str(e),
436
+ message=messages["GENERIC_500"], log=str(e)
2739
437
  )
2740
438
  return JSONResponse(
2741
439
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2749,261 +447,16 @@ async def send_reset_password_email_v0(
2749
447
  ):
2750
448
  username = body.username
2751
449
  try:
2752
- """
2753
- validation
2754
- """
2755
- # validate username
2756
- local_list_authentication_user_response = (
2757
- global_object_square_database_helper.get_rows_v0(
2758
- database_name=global_string_database_name,
2759
- schema_name=global_string_schema_name,
2760
- table_name=User.__tablename__,
2761
- filters=FiltersV0(
2762
- root={User.user_username.name: FilterConditionsV0(eq=username)}
2763
- ),
2764
- )["data"]["main"]
2765
- )
2766
- if len(local_list_authentication_user_response) != 1:
2767
- output_content = get_api_output_in_standard_format(
2768
- message=messages["INCORRECT_USERNAME"],
2769
- log=f"incorrect username: {username}.",
2770
- )
2771
- raise HTTPException(
2772
- status_code=status.HTTP_400_BAD_REQUEST,
2773
- detail=output_content,
2774
- )
2775
- user_id = local_list_authentication_user_response[0][User.user_id.name]
2776
- # check if user has SELF auth provider
2777
- local_list_response_user_auth_provider = (
2778
- global_object_square_database_helper.get_rows_v0(
2779
- database_name=global_string_database_name,
2780
- schema_name=global_string_schema_name,
2781
- table_name=UserAuthProvider.__tablename__,
2782
- filters=FiltersV0(
2783
- root={
2784
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
2785
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
2786
- eq=AuthProviderEnum.SELF.value
2787
- ),
2788
- }
2789
- ),
2790
- )["data"]["main"]
2791
- )
2792
- if len(local_list_response_user_auth_provider) != 1:
2793
- output_content = get_api_output_in_standard_format(
2794
- message=messages["INCORRECT_AUTH_PROVIDER"],
2795
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
2796
- )
2797
- raise HTTPException(
2798
- status_code=status.HTTP_400_BAD_REQUEST,
2799
- detail=output_content,
2800
- )
2801
- # check if user has recovery method enabled
2802
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2803
- database_name=global_string_database_name,
2804
- schema_name=global_string_schema_name,
2805
- table_name=UserRecoveryMethod.__tablename__,
2806
- filters=FiltersV0(
2807
- root={
2808
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2809
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2810
- eq=RecoveryMethodEnum.EMAIL.value
2811
- ),
2812
- }
2813
- ),
2814
- )[
2815
- "data"
2816
- ][
2817
- "main"
2818
- ]
2819
- if len(local_list_response_user_recovery_methods) != 1:
2820
- output_content = get_api_output_in_standard_format(
2821
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2822
- log=f"user_id: {user_id} does not have email recovery method enabled.",
2823
- )
2824
- raise HTTPException(
2825
- status_code=status.HTTP_400_BAD_REQUEST,
2826
- detail=output_content,
2827
- )
2828
- # validate if user has email in profile
2829
- user_profile_response = global_object_square_database_helper.get_rows_v0(
2830
- database_name=global_string_database_name,
2831
- schema_name=global_string_schema_name,
2832
- table_name=UserProfile.__tablename__,
2833
- filters=FiltersV0(
2834
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
2835
- ),
2836
- apply_filters=True,
2837
- )
2838
- user_profile_data = user_profile_response["data"]["main"][0]
2839
- if not user_profile_data.get(UserProfile.user_profile_email.name):
2840
- output_content = get_api_output_in_standard_format(
2841
- message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
2842
- log="email is required to send verification email.",
2843
- )
2844
- raise HTTPException(
2845
- status_code=status.HTTP_400_BAD_REQUEST,
2846
- detail=output_content,
2847
- )
2848
- # check if email is not verified
2849
- if not user_profile_data.get(UserProfile.user_profile_email_verified.name):
2850
- output_content = get_api_output_in_standard_format(
2851
- message=messages["EMAIL_NOT_VERIFIED"],
2852
- log="email is not verified.",
2853
- )
2854
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2855
- # check if reset password code already exists
2856
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
2857
- database_name=global_string_database_name,
2858
- schema_name=global_string_schema_name,
2859
- table_name=UserVerificationCode.__tablename__,
2860
- filters=FiltersV0(
2861
- root={
2862
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2863
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2864
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
2865
- ),
2866
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
2867
- is_null=True
2868
- ),
2869
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
2870
- gte=datetime.now(timezone.utc).strftime(
2871
- "%Y-%m-%d %H:%M:%S.%f+00"
2872
- )
2873
- ),
2874
- }
2875
- ),
2876
- order_by=[
2877
- "-" + UserVerificationCode.user_verification_code_created_at.name
2878
- ],
2879
- limit=1,
2880
- apply_filters=True,
2881
- )[
2882
- "data"
2883
- ][
2884
- "main"
2885
- ]
2886
- if len(local_list_response_user_verification_code) > 0:
2887
- existing_verification_code_data = (
2888
- local_list_response_user_verification_code[0]
2889
- )
2890
- if (
2891
- datetime.now(timezone.utc)
2892
- - datetime.fromisoformat(
2893
- existing_verification_code_data[
2894
- UserVerificationCode.user_verification_code_created_at.name
2895
- ]
2896
- )
2897
- ).total_seconds() < RESEND_COOL_DOWN_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS:
2898
- output_content = get_api_output_in_standard_format(
2899
- message=messages["GENERIC_400"],
2900
- log="verification code already exists and was sent within the cooldown period.",
2901
- )
2902
- raise HTTPException(
2903
- status_code=status.HTTP_400_BAD_REQUEST,
2904
- detail=output_content,
2905
- )
2906
- """
2907
- main process
2908
- """
2909
- verification_code = random.randint(
2910
- 10 ** (NUMBER_OF_DIGITS_IN_EMAIL_PASSWORD_RESET_CODE - 1),
2911
- 10**NUMBER_OF_DIGITS_IN_EMAIL_PASSWORD_RESET_CODE - 1,
2912
- )
2913
- # hash the verification code
2914
- hashed_verification_code = bcrypt.hashpw(
2915
- str(verification_code).encode("utf-8"), bcrypt.gensalt()
2916
- ).decode("utf-8")
2917
- expires_at = datetime.now(timezone.utc) + timedelta(
2918
- seconds=EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS
2919
- )
2920
- # add verification code to UserVerification code table
2921
- global_object_square_database_helper.insert_rows_v0(
2922
- database_name=global_string_database_name,
2923
- schema_name=global_string_schema_name,
2924
- table_name=UserVerificationCode.__tablename__,
2925
- data=[
2926
- {
2927
- UserVerificationCode.user_id.name: user_id,
2928
- UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.EMAIL_RECOVERY.value,
2929
- UserVerificationCode.user_verification_code_hash.name: hashed_verification_code,
2930
- UserVerificationCode.user_verification_code_expires_at.name: expires_at.strftime(
2931
- "%Y-%m-%d %H:%M:%S.%f+00"
2932
- ),
2933
- }
2934
- ],
2935
- )
2936
- # send verification email
2937
- if (
2938
- user_profile_data[UserProfile.user_profile_first_name.name]
2939
- and user_profile_data[UserProfile.user_profile_last_name.name]
2940
- ):
2941
- user_to_name = f"{user_profile_data[UserProfile.user_profile_first_name.name]} {user_profile_data[UserProfile.user_profile_last_name.name]}"
2942
- elif user_profile_data[UserProfile.user_profile_first_name.name]:
2943
- user_to_name = user_profile_data[UserProfile.user_profile_first_name.name]
2944
- elif user_profile_data[UserProfile.user_profile_last_name.name]:
2945
- user_to_name = user_profile_data[UserProfile.user_profile_last_name.name]
2946
- else:
2947
- user_to_name = ""
2948
-
2949
- mailgun_response = send_email_using_mailgun(
2950
- from_email="auth@thepmsquare.com",
2951
- from_name="square_authentication",
2952
- to_email=user_profile_data[UserProfile.user_profile_email.name],
2953
- to_name=user_to_name,
2954
- subject="Password Reset Verification Code",
2955
- body=f"Your Password Reset verification code is {verification_code}. It will expire in {EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS/60} minutes.",
2956
- api_key=MAIL_GUN_API_KEY,
2957
- domain_name="thepmsquare.com",
2958
- )
2959
- # add log for email sending
2960
- global_object_square_database_helper.insert_rows_v0(
2961
- database_name=global_string_database_name,
2962
- schema_name=email_schema_name,
2963
- table_name=EmailLog.__tablename__,
2964
- data=[
2965
- {
2966
- EmailLog.user_id.name: user_id,
2967
- EmailLog.recipient_email.name: user_profile_data[
2968
- UserProfile.user_profile_email.name
2969
- ],
2970
- EmailLog.email_type.name: EmailTypeEnum.VERIFY_EMAIL.value,
2971
- EmailLog.status.name: EmailStatusEnum.SENT.value,
2972
- EmailLog.third_party_message_id.name: mailgun_response.get("id"),
2973
- }
2974
- ],
2975
- )
2976
- """
2977
- return value
2978
- """
2979
- cooldown_reset_at = datetime.now(timezone.utc) + timedelta(
2980
- seconds=EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS,
2981
- )
2982
-
2983
- output_content = get_api_output_in_standard_format(
2984
- data={
2985
- "expires_at": expires_at.isoformat(),
2986
- "cooldown_reset_at": cooldown_reset_at.isoformat(),
2987
- },
2988
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
2989
- )
2990
- return JSONResponse(
2991
- status_code=status.HTTP_200_OK,
2992
- content=output_content,
2993
- )
2994
- except HTTPException as http_exception:
2995
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2996
- return JSONResponse(
2997
- status_code=http_exception.status_code, content=http_exception.detail
450
+ return util_send_reset_password_email_v0(
451
+ username=username,
2998
452
  )
453
+ except HTTPException as he:
454
+ global_object_square_logger.logger.error(he, exc_info=True)
455
+ return JSONResponse(status_code=he.status_code, content=he.detail)
2999
456
  except Exception as e:
3000
- """
3001
- rollback logic
3002
- """
3003
457
  global_object_square_logger.logger.error(e, exc_info=True)
3004
458
  output_content = get_api_output_in_standard_format(
3005
- message=messages["GENERIC_500"],
3006
- log=str(e),
459
+ message=messages["GENERIC_500"], log=str(e)
3007
460
  )
3008
461
  return JSONResponse(
3009
462
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -3021,309 +474,20 @@ async def reset_password_and_login_using_reset_email_code_v0(
3021
474
  app_id = body.app_id
3022
475
  logout_other_sessions = body.logout_other_sessions
3023
476
  try:
3024
- """
3025
- validation
3026
- """
3027
- # validate username
3028
- local_list_authentication_user_response = (
3029
- global_object_square_database_helper.get_rows_v0(
3030
- database_name=global_string_database_name,
3031
- schema_name=global_string_schema_name,
3032
- table_name=User.__tablename__,
3033
- filters=FiltersV0(
3034
- root={User.user_username.name: FilterConditionsV0(eq=username)}
3035
- ),
3036
- )["data"]["main"]
3037
- )
3038
- if len(local_list_authentication_user_response) != 1:
3039
- output_content = get_api_output_in_standard_format(
3040
- message=messages["INCORRECT_USERNAME"],
3041
- log=f"incorrect username: {username}.",
3042
- )
3043
- raise HTTPException(
3044
- status_code=status.HTTP_400_BAD_REQUEST,
3045
- detail=output_content,
3046
- )
3047
- user_id = local_list_authentication_user_response[0][User.user_id.name]
3048
- # check if user has SELF auth provider
3049
- local_list_response_user_auth_provider = (
3050
- global_object_square_database_helper.get_rows_v0(
3051
- database_name=global_string_database_name,
3052
- schema_name=global_string_schema_name,
3053
- table_name=UserAuthProvider.__tablename__,
3054
- filters=FiltersV0(
3055
- root={
3056
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
3057
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
3058
- eq=AuthProviderEnum.SELF.value
3059
- ),
3060
- }
3061
- ),
3062
- )["data"]["main"]
3063
- )
3064
- if len(local_list_response_user_auth_provider) != 1:
3065
- output_content = get_api_output_in_standard_format(
3066
- message=messages["INCORRECT_AUTH_PROVIDER"],
3067
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
3068
- )
3069
- raise HTTPException(
3070
- status_code=status.HTTP_400_BAD_REQUEST,
3071
- detail=output_content,
3072
- )
3073
- # check if user has recovery method enabled
3074
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
3075
- database_name=global_string_database_name,
3076
- schema_name=global_string_schema_name,
3077
- table_name=UserRecoveryMethod.__tablename__,
3078
- filters=FiltersV0(
3079
- root={
3080
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
3081
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
3082
- eq=RecoveryMethodEnum.EMAIL.value
3083
- ),
3084
- }
3085
- ),
3086
- )[
3087
- "data"
3088
- ][
3089
- "main"
3090
- ]
3091
- if len(local_list_response_user_recovery_methods) != 1:
3092
- output_content = get_api_output_in_standard_format(
3093
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
3094
- log=f"user_id: {user_id} does not have email recovery method enabled.",
3095
- )
3096
- raise HTTPException(
3097
- status_code=status.HTTP_400_BAD_REQUEST,
3098
- detail=output_content,
3099
- )
3100
- # check if user has email in profile
3101
- user_profile_response = global_object_square_database_helper.get_rows_v0(
3102
- database_name=global_string_database_name,
3103
- schema_name=global_string_schema_name,
3104
- table_name=UserProfile.__tablename__,
3105
- filters=FiltersV0(
3106
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
3107
- ),
3108
- apply_filters=True,
3109
- )
3110
- user_profile_data = user_profile_response["data"]["main"][0]
3111
- if not user_profile_data.get(UserProfile.user_profile_email.name):
3112
- output_content = get_api_output_in_standard_format(
3113
- message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
3114
- log="user seems to have email recovery method enabled, but does not have email in profile.",
3115
- )
3116
- raise HTTPException(
3117
- status_code=status.HTTP_400_BAD_REQUEST,
3118
- detail=output_content,
3119
- )
3120
- # check if email is verified.
3121
- if not user_profile_data.get(UserProfile.user_profile_email_verified.name):
3122
- output_content = get_api_output_in_standard_format(
3123
- message=messages["EMAIL_NOT_VERIFIED"],
3124
- log="email is not verified.",
3125
- )
3126
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
3127
- # validate if user is assigned to the app.
3128
- # not checking [skipping] if the app exists, as it is not required for this endpoint.
3129
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
3130
- database_name=global_string_database_name,
3131
- schema_name=global_string_schema_name,
3132
- table_name=UserApp.__tablename__,
3133
- filters=FiltersV0(
3134
- root={
3135
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
3136
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
3137
- }
3138
- ),
3139
- )["data"]["main"]
3140
- if len(local_list_response_user_app) == 0:
3141
- output_content = get_api_output_in_standard_format(
3142
- message=messages["GENERIC_400"],
3143
- log=f"user_id: {user_id} is not assigned to app_id: {app_id}.",
3144
- )
3145
- raise HTTPException(
3146
- status_code=status.HTTP_400_BAD_REQUEST,
3147
- detail=output_content,
3148
- )
3149
- """
3150
- main process
3151
- """
3152
- # validate email reset code
3153
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
3154
- database_name=global_string_database_name,
3155
- schema_name=global_string_schema_name,
3156
- table_name=UserVerificationCode.__tablename__,
3157
- filters=FiltersV0(
3158
- root={
3159
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
3160
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
3161
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
3162
- ),
3163
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
3164
- gte=datetime.now(timezone.utc).strftime(
3165
- "%Y-%m-%d %H:%M:%S.%f+00"
3166
- )
3167
- ),
3168
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
3169
- is_null=True
3170
- ),
3171
- }
3172
- ),
3173
- columns=[UserVerificationCode.user_verification_code_hash.name],
3174
- order_by=[
3175
- "-" + UserVerificationCode.user_verification_code_created_at.name
3176
- ],
3177
- limit=1,
3178
- )[
3179
- "data"
3180
- ][
3181
- "main"
3182
- ]
3183
- if len(local_list_response_user_verification_code) != 1:
3184
- output_content = get_api_output_in_standard_format(
3185
- message=messages["INCORRECT_VERIFICATION_CODE"],
3186
- log=f"incorrect reset_email_code: {reset_email_code} for user_id: {user_id}.",
3187
- )
3188
- raise HTTPException(
3189
- status_code=status.HTTP_400_BAD_REQUEST,
3190
- detail=output_content,
3191
- )
3192
- latest_hashed_verification_code = local_list_response_user_verification_code[0][
3193
- UserVerificationCode.user_verification_code_hash.name
3194
- ]
3195
-
3196
- if not bcrypt.checkpw(
3197
- reset_email_code.encode("utf-8"),
3198
- latest_hashed_verification_code.encode("utf-8"),
3199
- ):
3200
- output_content = get_api_output_in_standard_format(
3201
- message=messages["INCORRECT_VERIFICATION_CODE"],
3202
- log=f"incorrect reset_email_code: {reset_email_code} for user_id: {user_id}.",
3203
- )
3204
- raise HTTPException(
3205
- status_code=status.HTTP_400_BAD_REQUEST,
3206
- detail=output_content,
3207
- )
3208
-
3209
- # hash the new password
3210
- local_str_hashed_password = bcrypt.hashpw(
3211
- new_password.encode("utf-8"), bcrypt.gensalt()
3212
- ).decode("utf-8")
3213
- # update the password
3214
- global_object_square_database_helper.edit_rows_v0(
3215
- database_name=global_string_database_name,
3216
- schema_name=global_string_schema_name,
3217
- table_name=UserCredential.__tablename__,
3218
- filters=FiltersV0(
3219
- root={
3220
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
3221
- }
3222
- ),
3223
- data={
3224
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
3225
- },
3226
- )
3227
- # mark the email code as used
3228
- global_object_square_database_helper.edit_rows_v0(
3229
- database_name=global_string_database_name,
3230
- schema_name=global_string_schema_name,
3231
- table_name=UserVerificationCode.__tablename__,
3232
- filters=FiltersV0(
3233
- root={
3234
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
3235
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
3236
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
3237
- ),
3238
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
3239
- eq=latest_hashed_verification_code
3240
- ),
3241
- }
3242
- ),
3243
- data={
3244
- UserVerificationCode.user_verification_code_used_at.name: datetime.now(
3245
- timezone.utc
3246
- ).strftime("%Y-%m-%d %H:%M:%S.%f+00"),
3247
- },
3248
- )
3249
- if logout_other_sessions:
3250
- # delete all sessions for user
3251
- global_object_square_database_helper.delete_rows_v0(
3252
- database_name=global_string_database_name,
3253
- schema_name=global_string_schema_name,
3254
- table_name=UserSession.__tablename__,
3255
- filters=FiltersV0(
3256
- root={
3257
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
3258
- }
3259
- ),
3260
- )
3261
- # generate access token and refresh token
3262
- local_dict_access_token_payload = {
3263
- "app_id": app_id,
3264
- "user_id": user_id,
3265
- "exp": datetime.now(timezone.utc)
3266
- + timedelta(minutes=config_int_access_token_valid_minutes),
3267
- }
3268
- local_str_access_token = jwt.encode(
3269
- local_dict_access_token_payload, config_str_secret_key_for_access_token
3270
- )
3271
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
3272
- minutes=config_int_refresh_token_valid_minutes
3273
- )
3274
- local_dict_refresh_token_payload = {
3275
- "app_id": app_id,
3276
- "user_id": user_id,
3277
- "exp": local_object_refresh_token_expiry_time,
3278
- }
3279
- local_str_refresh_token = jwt.encode(
3280
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
3281
- )
3282
- # insert the refresh token in the database
3283
- global_object_square_database_helper.insert_rows_v0(
3284
- database_name=global_string_database_name,
3285
- schema_name=global_string_schema_name,
3286
- table_name=UserSession.__tablename__,
3287
- data=[
3288
- {
3289
- UserSession.user_id.name: user_id,
3290
- UserSession.app_id.name: app_id,
3291
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
3292
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
3293
- "%Y-%m-%d %H:%M:%S.%f+00"
3294
- ),
3295
- }
3296
- ],
3297
- )
3298
- """
3299
- return value
3300
- """
3301
- output_content = get_api_output_in_standard_format(
3302
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
3303
- data={
3304
- "main": {
3305
- "user_id": user_id,
3306
- "access_token": local_str_access_token,
3307
- "refresh_token": local_str_refresh_token,
3308
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
3309
- }
3310
- },
3311
- )
3312
-
3313
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
3314
- except HTTPException as http_exception:
3315
- global_object_square_logger.logger.error(http_exception, exc_info=True)
3316
- return JSONResponse(
3317
- status_code=http_exception.status_code, content=http_exception.detail
3318
- )
477
+ return util_reset_password_and_login_using_reset_email_code_v0(
478
+ reset_email_code=reset_email_code,
479
+ username=username,
480
+ new_password=new_password,
481
+ app_id=app_id,
482
+ logout_other_sessions=logout_other_sessions,
483
+ )
484
+ except HTTPException as he:
485
+ global_object_square_logger.logger.error(he, exc_info=True)
486
+ return JSONResponse(status_code=he.status_code, content=he.detail)
3319
487
  except Exception as e:
3320
- """
3321
- rollback logic
3322
- """
3323
488
  global_object_square_logger.logger.error(e, exc_info=True)
3324
489
  output_content = get_api_output_in_standard_format(
3325
- message=messages["GENERIC_500"],
3326
- log=str(e),
490
+ message=messages["GENERIC_500"], log=str(e)
3327
491
  )
3328
492
  return JSONResponse(
3329
493
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content