square-authentication 10.0.1__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,134 +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_user = global_object_square_database_helper.get_rows_v0(
686
- database_name=global_string_database_name,
687
- schema_name=global_string_schema_name,
688
- table_name=User.__tablename__,
689
- filters=FiltersV0(
690
- root={
691
- User.user_id.name: FilterConditionsV0(eq=user_id),
692
- }
693
- ),
694
- )["data"]["main"]
695
- local_list_app = global_object_square_database_helper.get_rows_v0(
696
- database_name=global_string_database_name,
697
- schema_name=global_string_public_schema_name,
698
- table_name=App.__tablename__,
699
- apply_filters=False,
700
- filters=FiltersV0(root={}),
701
- )["data"]["main"]
702
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
703
- database_name=global_string_database_name,
704
- schema_name=global_string_schema_name,
705
- table_name=UserApp.__tablename__,
706
- filters=FiltersV0(
707
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
708
- ),
709
- )["data"]["main"]
710
- local_list_response_user_profile = (
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=UserProfile.__tablename__,
715
- filters=FiltersV0(
716
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
717
- ),
718
- )["data"]["main"]
719
- )
720
- local_list_response_user_sessions = (
721
- global_object_square_database_helper.get_rows_v0(
722
- database_name=global_string_database_name,
723
- schema_name=global_string_schema_name,
724
- table_name=UserSession.__tablename__,
725
- filters=FiltersV0(
726
- root={
727
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
728
- UserSession.user_session_expiry_time.name: FilterConditionsV0(
729
- gte=datetime.now(timezone.utc).isoformat()
730
- ),
731
- }
732
- ),
733
- )["data"]["main"]
734
- )
735
- user_profile = copy.deepcopy(local_list_response_user_profile[0])
736
- del user_profile[UserProfile.user_id.name]
737
- """
738
- return value
739
- """
740
- return_this = {
741
- "user_id": user_id,
742
- "username": local_list_user[0][User.user_username.name],
743
- "profile": user_profile,
744
- "apps": [
745
- y[App.app_name.name]
746
- for y in local_list_app
747
- if y[App.app_id.name]
748
- in [x[UserApp.app_id.name] for x in local_list_response_user_app]
749
- ],
750
- "sessions": [
751
- {
752
- "app_name": [
753
- y[App.app_name.name]
754
- for y in local_list_app
755
- if y[App.app_id.name] == x[UserApp.app_id.name]
756
- ][0],
757
- "active_sessions": len(
758
- [
759
- y
760
- for y in local_list_response_user_sessions
761
- if y[UserSession.app_id.name] == x[UserApp.app_id.name]
762
- ]
763
- ),
764
- }
765
- for x in local_list_response_user_app
766
- ],
767
- }
768
- output_content = get_api_output_in_standard_format(
769
- message=messages["GENERIC_READ_SUCCESSFUL"],
770
- data={"main": return_this},
771
- )
772
- return JSONResponse(
773
- status_code=status.HTTP_200_OK,
774
- content=output_content,
775
- )
776
- except HTTPException as http_exception:
777
- global_object_square_logger.logger.error(http_exception, exc_info=True)
778
- return JSONResponse(
779
- status_code=http_exception.status_code, content=http_exception.detail
780
- )
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)
781
108
  except Exception as e:
782
- """
783
- rollback logic
784
- """
785
109
  global_object_square_logger.logger.error(e, exc_info=True)
786
110
  output_content = get_api_output_in_standard_format(
787
- message=messages["GENERIC_500"],
788
- log=str(e),
111
+ message=messages["GENERIC_500"], log=str(e)
789
112
  )
790
113
  return JSONResponse(
791
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
792
- content=output_content,
114
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
793
115
  )
794
116
 
795
117
 
@@ -801,156 +123,21 @@ async def update_user_app_ids_v0(
801
123
  app_ids_to_remove: List[int],
802
124
  ):
803
125
  try:
804
-
805
- """
806
- validation
807
- """
808
- # validate access token
809
- try:
810
- local_dict_access_token_payload = get_jwt_payload(
811
- access_token, config_str_secret_key_for_access_token
812
- )
813
- except Exception as error:
814
- output_content = get_api_output_in_standard_format(
815
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
816
- )
817
- raise HTTPException(
818
- status_code=status.HTTP_400_BAD_REQUEST,
819
- detail=output_content,
820
- )
821
- user_id = local_dict_access_token_payload["user_id"]
822
-
823
- app_ids_to_add = list(set(app_ids_to_add))
824
- app_ids_to_remove = list(set(app_ids_to_remove))
825
-
826
- # check if app_ids_to_add and app_ids_to_remove don't have common ids.
827
- local_list_common_app_ids = set(app_ids_to_add) & set(app_ids_to_remove)
828
- if len(local_list_common_app_ids) > 0:
829
- output_content = get_api_output_in_standard_format(
830
- message=messages["GENERIC_400"],
831
- log=f"invalid app_ids: {list(local_list_common_app_ids)}, present in both add list and remove list.",
832
- )
833
- raise HTTPException(
834
- status_code=status.HTTP_400_BAD_REQUEST,
835
- detail=output_content,
836
- )
837
-
838
- # check if all app_ids are valid
839
- local_list_all_app_ids = [*app_ids_to_add, *app_ids_to_remove]
840
- local_list_response_app = global_object_square_database_helper.get_rows_v0(
841
- database_name=global_string_database_name,
842
- schema_name=global_string_public_schema_name,
843
- table_name=App.__tablename__,
844
- apply_filters=False,
845
- filters=FiltersV0(root={}),
846
- )["data"]["main"]
847
- local_list_invalid_ids = [
848
- x
849
- for x in local_list_all_app_ids
850
- if x not in [y[App.app_id.name] for y in local_list_response_app]
851
- ]
852
- if len(local_list_invalid_ids) > 0:
853
- output_content = get_api_output_in_standard_format(
854
- message=messages["GENERIC_400"],
855
- log=f"invalid app_ids: {local_list_invalid_ids}.",
856
- )
857
- raise HTTPException(
858
- status_code=status.HTTP_400_BAD_REQUEST,
859
- detail=output_content,
860
- )
861
- """
862
- main process
863
- """
864
- # logic for adding new app_ids
865
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
866
- database_name=global_string_database_name,
867
- schema_name=global_string_schema_name,
868
- table_name=UserApp.__tablename__,
869
- filters=FiltersV0(
870
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
871
- ),
872
- )["data"]["main"]
873
- local_list_new_app_ids = [
874
- {
875
- UserApp.user_id.name: user_id,
876
- UserApp.app_id.name: x,
877
- }
878
- for x in app_ids_to_add
879
- if x not in [y[UserApp.app_id.name] for y in local_list_response_user_app]
880
- ]
881
- if len(local_list_new_app_ids) > 0:
882
- global_object_square_database_helper.insert_rows_v0(
883
- database_name=global_string_database_name,
884
- schema_name=global_string_schema_name,
885
- table_name=UserApp.__tablename__,
886
- data=local_list_new_app_ids,
887
- )
888
-
889
- # logic for removing app_ids
890
- for app_id in app_ids_to_remove:
891
- global_object_square_database_helper.delete_rows_v0(
892
- database_name=global_string_database_name,
893
- schema_name=global_string_schema_name,
894
- table_name=UserApp.__tablename__,
895
- filters=FiltersV0(
896
- root={
897
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
898
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
899
- }
900
- ),
901
- )
902
- # logout user from removed apps
903
- global_object_square_database_helper.delete_rows_v0(
904
- database_name=global_string_database_name,
905
- schema_name=global_string_schema_name,
906
- table_name=UserSession.__tablename__,
907
- filters=FiltersV0(
908
- root={
909
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
910
- UserSession.app_id.name: FilterConditionsV0(eq=app_id),
911
- }
912
- ),
913
- )
914
-
915
- """
916
- return value
917
- """
918
- # get latest app ids
919
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
920
- database_name=global_string_database_name,
921
- schema_name=global_string_schema_name,
922
- table_name=UserApp.__tablename__,
923
- filters=FiltersV0(
924
- root={UserApp.user_id.name: FilterConditionsV0(eq=user_id)}
925
- ),
926
- )["data"]["main"]
927
- output_content = get_api_output_in_standard_format(
928
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
929
- data={
930
- "main": [x[UserApp.app_id.name] for x in local_list_response_user_app]
931
- },
932
- )
933
- return JSONResponse(
934
- status_code=status.HTTP_200_OK,
935
- content=output_content,
936
- )
937
- except HTTPException as http_exception:
938
- global_object_square_logger.logger.error(http_exception, exc_info=True)
939
- return JSONResponse(
940
- status_code=http_exception.status_code, content=http_exception.detail
941
- )
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)
942
134
  except Exception as e:
943
- """
944
- rollback logic
945
- """
946
135
  global_object_square_logger.logger.error(e, exc_info=True)
947
136
  output_content = get_api_output_in_standard_format(
948
- message=messages["GENERIC_500"],
949
- log=str(e),
137
+ message=messages["GENERIC_500"], log=str(e)
950
138
  )
951
139
  return JSONResponse(
952
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
953
- content=output_content,
140
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
954
141
  )
955
142
 
956
143
 
@@ -963,221 +150,19 @@ async def login_username_v0(body: LoginUsernameV0):
963
150
  assign_app_id_if_missing = body.assign_app_id_if_missing
964
151
  username = username.lower()
965
152
  try:
966
- """
967
- validation
968
- """
969
- # validation for username
970
- # check if user with username exists
971
- local_list_response_user = global_object_square_database_helper.get_rows_v0(
972
- database_name=global_string_database_name,
973
- schema_name=global_string_schema_name,
974
- table_name=User.__tablename__,
975
- filters=FiltersV0(
976
- root={User.user_username.name: FilterConditionsV0(eq=username)}
977
- ),
978
- )["data"]["main"]
979
- if len(local_list_response_user) != 1:
980
- output_content = get_api_output_in_standard_format(
981
- message=messages["INCORRECT_USERNAME"],
982
- log=f"incorrect username {username}",
983
- )
984
- raise HTTPException(
985
- status_code=status.HTTP_400_BAD_REQUEST,
986
- detail=output_content,
987
- )
988
- # check if user has auth provider as SELF
989
- local_list_user_auth_provider_response = (
990
- global_object_square_database_helper.get_rows_v0(
991
- database_name=global_string_database_name,
992
- schema_name=global_string_schema_name,
993
- table_name=UserAuthProvider.__tablename__,
994
- filters=FiltersV0(
995
- root={
996
- UserAuthProvider.user_id.name: FilterConditionsV0(
997
- eq=local_list_response_user[0][User.user_id.name]
998
- ),
999
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
1000
- eq=AuthProviderEnum.SELF.value
1001
- ),
1002
- }
1003
- ),
1004
- )["data"]["main"]
1005
- )
1006
- if len(local_list_user_auth_provider_response) != 1:
1007
- output_content = get_api_output_in_standard_format(
1008
- message=messages["INCORRECT_AUTH_PROVIDER"],
1009
- log=f"{username} not linked with {AuthProviderEnum.SELF.value} auth provider.",
1010
- )
1011
- raise HTTPException(
1012
- status_code=status.HTTP_400_BAD_REQUEST,
1013
- detail=output_content,
1014
- )
1015
- # check if user has credentials (might not be set in case of errors in registration.)
1016
- local_list_authentication_user_response = (
1017
- global_object_square_database_helper.get_rows_v0(
1018
- database_name=global_string_database_name,
1019
- schema_name=global_string_schema_name,
1020
- table_name=UserCredential.__tablename__,
1021
- filters=FiltersV0(
1022
- root={
1023
- UserCredential.user_id.name: FilterConditionsV0(
1024
- eq=local_list_response_user[0][User.user_id.name]
1025
- )
1026
- }
1027
- ),
1028
- )["data"]["main"]
1029
- )
1030
- if len(local_list_authentication_user_response) != 1:
1031
- output_content = get_api_output_in_standard_format(
1032
- message=messages["MALFORMED_USER"],
1033
- log=f"username: {username} does not have credentials set.",
1034
- )
1035
- raise HTTPException(
1036
- status_code=status.HTTP_400_BAD_REQUEST,
1037
- detail=output_content,
1038
- )
1039
- # validate if app_id is assigned to user
1040
- # this will also validate if app_id is valid
1041
- local_dict_user = local_list_authentication_user_response[0]
1042
- local_str_user_id = local_dict_user[UserCredential.user_id.name]
1043
- local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
1044
- database_name=global_string_database_name,
1045
- schema_name=global_string_schema_name,
1046
- table_name=UserApp.__tablename__,
1047
- filters=FiltersV0(
1048
- root={
1049
- UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
1050
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
1051
- }
1052
- ),
1053
- )["data"]["main"]
1054
- if len(local_list_user_app_response) == 0:
1055
- if assign_app_id_if_missing:
1056
- try:
1057
- global_object_square_database_helper.insert_rows_v0(
1058
- database_name=global_string_database_name,
1059
- schema_name=global_string_schema_name,
1060
- table_name=UserApp.__tablename__,
1061
- data=[
1062
- {
1063
- UserApp.user_id.name: local_str_user_id,
1064
- UserApp.app_id.name: app_id,
1065
- }
1066
- ],
1067
- )
1068
- except HTTPError as he:
1069
- output_content = get_api_output_in_standard_format(
1070
- message=messages["GENERIC_400"],
1071
- log=str(he),
1072
- )
1073
- raise HTTPException(
1074
- status_code=he.response.status_code, detail=output_content
1075
- )
1076
- else:
1077
- output_content = get_api_output_in_standard_format(
1078
- message=messages["GENERIC_400"],
1079
- log=f"user_id {local_str_user_id}({username}) not assigned to app {app_id}.",
1080
- )
1081
- raise HTTPException(
1082
- status_code=status.HTTP_400_BAD_REQUEST,
1083
- detail=output_content,
1084
- )
1085
-
1086
- # validate password
1087
- if not (
1088
- bcrypt.checkpw(
1089
- password.encode("utf-8"),
1090
- local_dict_user[
1091
- UserCredential.user_credential_hashed_password.name
1092
- ].encode("utf-8"),
1093
- )
1094
- ):
1095
- output_content = get_api_output_in_standard_format(
1096
- message=messages["INCORRECT_PASSWORD"],
1097
- log=f"incorrect password for user_id {local_str_user_id}({username}).",
1098
- )
1099
- raise HTTPException(
1100
- status_code=status.HTTP_400_BAD_REQUEST,
1101
- detail=output_content,
1102
- )
1103
- """
1104
- main process
1105
- """
1106
- # return new access token and refresh token
1107
-
1108
- # create access token
1109
- local_dict_access_token_payload = {
1110
- "app_id": app_id,
1111
- "user_id": local_str_user_id,
1112
- "exp": datetime.now(timezone.utc)
1113
- + timedelta(minutes=config_int_access_token_valid_minutes),
1114
- }
1115
- local_str_access_token = jwt.encode(
1116
- local_dict_access_token_payload,
1117
- config_str_secret_key_for_access_token,
1118
- )
1119
-
1120
- # create refresh token
1121
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
1122
- minutes=config_int_refresh_token_valid_minutes
1123
- )
1124
-
1125
- local_dict_refresh_token_payload = {
1126
- "app_id": app_id,
1127
- "user_id": local_str_user_id,
1128
- "exp": local_object_refresh_token_expiry_time,
1129
- }
1130
- local_str_refresh_token = jwt.encode(
1131
- local_dict_refresh_token_payload,
1132
- config_str_secret_key_for_refresh_token,
1133
- )
1134
- # entry in user session table
1135
- global_object_square_database_helper.insert_rows_v0(
1136
- data=[
1137
- {
1138
- UserSession.user_id.name: local_str_user_id,
1139
- UserSession.app_id.name: app_id,
1140
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
1141
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
1142
- "%Y-%m-%d %H:%M:%S.%f+00"
1143
- ),
1144
- }
1145
- ],
1146
- database_name=global_string_database_name,
1147
- schema_name=global_string_schema_name,
1148
- table_name=UserSession.__tablename__,
1149
- )
1150
- """
1151
- return value
1152
- """
1153
- output_content = get_api_output_in_standard_format(
1154
- data={
1155
- "main": {
1156
- "user_id": local_str_user_id,
1157
- "access_token": local_str_access_token,
1158
- "refresh_token": local_str_refresh_token,
1159
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
1160
- }
1161
- },
1162
- message=messages["LOGIN_SUCCESSFUL"],
1163
- )
1164
- return JSONResponse(
1165
- status_code=status.HTTP_200_OK,
1166
- content=output_content,
1167
- )
1168
- except HTTPException as http_exception:
1169
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1170
- return JSONResponse(
1171
- status_code=http_exception.status_code, content=http_exception.detail
1172
- )
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)
1173
162
  except Exception as e:
1174
- """
1175
- rollback logic
1176
- """
1177
163
  global_object_square_logger.logger.error(e, exc_info=True)
1178
164
  output_content = get_api_output_in_standard_format(
1179
- message=messages["GENERIC_500"],
1180
- log=str(e),
165
+ message=messages["GENERIC_500"], log=str(e)
1181
166
  )
1182
167
  return JSONResponse(
1183
168
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1190,85 +175,16 @@ async def generate_access_token_v0(
1190
175
  refresh_token: Annotated[str, Header()],
1191
176
  ):
1192
177
  try:
1193
- """
1194
- validation
1195
- """
1196
- # validate refresh token
1197
- # validating if a session refresh token exists in the database.
1198
- local_list_user_session_response = (
1199
- global_object_square_database_helper.get_rows_v0(
1200
- database_name=global_string_database_name,
1201
- schema_name=global_string_schema_name,
1202
- table_name=UserSession.__tablename__,
1203
- filters=FiltersV0(
1204
- root={
1205
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1206
- eq=refresh_token
1207
- ),
1208
- }
1209
- ),
1210
- )["data"]["main"]
1211
- )
1212
-
1213
- if len(local_list_user_session_response) != 1:
1214
- output_content = get_api_output_in_standard_format(
1215
- message=messages["INCORRECT_REFRESH_TOKEN"],
1216
- log=f"incorrect refresh token: {refresh_token}.",
1217
- )
1218
- raise HTTPException(
1219
- status_code=status.HTTP_400_BAD_REQUEST,
1220
- detail=output_content,
1221
- )
1222
- # validating if the refresh token is valid, active and of the same user.
1223
- try:
1224
- local_dict_refresh_token_payload = get_jwt_payload(
1225
- refresh_token, config_str_secret_key_for_refresh_token
1226
- )
1227
- except Exception as error:
1228
- output_content = get_api_output_in_standard_format(
1229
- message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
1230
- )
1231
- raise HTTPException(
1232
- status_code=status.HTTP_400_BAD_REQUEST,
1233
- detail=output_content,
1234
- )
1235
- """
1236
- main process
1237
- """
1238
- # create and send access token
1239
- local_dict_access_token_payload = {
1240
- "app_id": local_dict_refresh_token_payload["app_id"],
1241
- "user_id": local_dict_refresh_token_payload["user_id"],
1242
- "exp": datetime.now(timezone.utc)
1243
- + timedelta(minutes=config_int_access_token_valid_minutes),
1244
- }
1245
- local_str_access_token = jwt.encode(
1246
- local_dict_access_token_payload, config_str_secret_key_for_access_token
1247
- )
1248
- """
1249
- return value
1250
- """
1251
- output_content = get_api_output_in_standard_format(
1252
- data={"main": {"access_token": local_str_access_token}},
1253
- message=messages["GENERIC_CREATION_SUCCESSFUL"],
1254
- )
1255
- return JSONResponse(
1256
- status_code=status.HTTP_200_OK,
1257
- content=output_content,
1258
- )
1259
- except HTTPException as http_exception:
1260
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1261
- return JSONResponse(
1262
- status_code=http_exception.status_code, content=http_exception.detail
178
+ return util_generate_access_token_v0(
179
+ refresh_token=refresh_token,
1263
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)
1264
184
  except Exception as e:
1265
- """
1266
- rollback logic
1267
- """
1268
185
  global_object_square_logger.logger.error(e, exc_info=True)
1269
186
  output_content = get_api_output_in_standard_format(
1270
- message=messages["GENERIC_500"],
1271
- log=str(e),
187
+ message=messages["GENERIC_500"], log=str(e)
1272
188
  )
1273
189
  return JSONResponse(
1274
190
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1281,86 +197,16 @@ async def logout_v0(
1281
197
  refresh_token: Annotated[str, Header()],
1282
198
  ):
1283
199
  try:
1284
- """
1285
- validation
1286
- """
1287
- # validate refresh token
1288
- # validating if a session refresh token exists in the database.
1289
- local_list_user_session_response = (
1290
- global_object_square_database_helper.get_rows_v0(
1291
- database_name=global_string_database_name,
1292
- schema_name=global_string_schema_name,
1293
- table_name=UserSession.__tablename__,
1294
- filters=FiltersV0(
1295
- root={
1296
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1297
- eq=refresh_token
1298
- ),
1299
- }
1300
- ),
1301
- )["data"]["main"]
1302
- )
1303
-
1304
- if len(local_list_user_session_response) != 1:
1305
- output_content = get_api_output_in_standard_format(
1306
- message=messages["INCORRECT_REFRESH_TOKEN"],
1307
- log=f"incorrect refresh token: {refresh_token}.",
1308
- )
1309
- raise HTTPException(
1310
- status_code=status.HTTP_400_BAD_REQUEST,
1311
- detail=output_content,
1312
- )
1313
- # validating if the refresh token is valid, active and of the same user.
1314
- try:
1315
- _ = get_jwt_payload(refresh_token, config_str_secret_key_for_refresh_token)
1316
- except Exception as error:
1317
- output_content = get_api_output_in_standard_format(
1318
- message=messages["INCORRECT_REFRESH_TOKEN"],
1319
- log=str(error),
1320
- )
1321
- raise HTTPException(
1322
- status_code=status.HTTP_400_BAD_REQUEST,
1323
- detail=output_content,
1324
- )
1325
- # ======================================================================================
1326
- # NOTE: if refresh token has expired no need to delete it during this call
1327
- # ======================================================================================
1328
- """
1329
- main process
1330
- """
1331
- # delete session for user
1332
- global_object_square_database_helper.delete_rows_v0(
1333
- database_name=global_string_database_name,
1334
- schema_name=global_string_schema_name,
1335
- table_name=UserSession.__tablename__,
1336
- filters=FiltersV0(
1337
- root={
1338
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1339
- eq=refresh_token
1340
- ),
1341
- }
1342
- ),
1343
- )
1344
- """
1345
- return value
1346
- """
1347
- output_content = get_api_output_in_standard_format(
1348
- message=messages["LOGOUT_SUCCESSFUL"],
1349
- )
1350
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1351
- except HTTPException as http_exception:
1352
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1353
- return JSONResponse(
1354
- status_code=http_exception.status_code, content=http_exception.detail
200
+ return util_logout_v0(
201
+ refresh_token=refresh_token,
1355
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)
1356
206
  except Exception as e:
1357
- """
1358
- rollback logic
1359
- """
1360
207
  global_object_square_logger.logger.error(e, exc_info=True)
1361
208
  output_content = get_api_output_in_standard_format(
1362
- message=messages["GENERIC_500"],
1363
- log=str(e),
209
+ message=messages["GENERIC_500"], log=str(e)
1364
210
  )
1365
211
  return JSONResponse(
1366
212
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1375,85 +221,14 @@ async def logout_apps_v0(
1375
221
  ):
1376
222
  app_ids = body.app_ids
1377
223
  try:
1378
- """
1379
- validation
1380
- """
1381
- try:
1382
- local_dict_access_token_payload = get_jwt_payload(
1383
- access_token, config_str_secret_key_for_access_token
1384
- )
1385
- except Exception as error:
1386
- output_content = get_api_output_in_standard_format(
1387
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1388
- )
1389
- raise HTTPException(
1390
- status_code=status.HTTP_400_BAD_REQUEST,
1391
- detail=output_content,
1392
- )
1393
- user_id = local_dict_access_token_payload["user_id"]
1394
- # validate app_ids
1395
- app_ids = list(set(app_ids))
1396
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
1397
- database_name=global_string_database_name,
1398
- schema_name=global_string_schema_name,
1399
- table_name=UserApp.__tablename__,
1400
- filters=FiltersV0(
1401
- root={
1402
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
1403
- }
1404
- ),
1405
- columns=[UserApp.app_id.name],
1406
- )["data"]["main"]
1407
- local_list_user_app_ids = [
1408
- x[UserApp.app_id.name] for x in local_list_response_user_app
1409
- ]
1410
- local_list_invalid_app_ids = [
1411
- x for x in app_ids if x not in local_list_user_app_ids
1412
- ]
1413
- if len(local_list_invalid_app_ids) > 0:
1414
- output_content = get_api_output_in_standard_format(
1415
- message=messages["GENERIC_400"],
1416
- log=f"invalid app_ids: {local_list_invalid_app_ids}.",
1417
- )
1418
- raise HTTPException(
1419
- status_code=status.HTTP_400_BAD_REQUEST,
1420
- detail=output_content,
1421
- )
1422
- """
1423
- main process
1424
- """
1425
- # delete session for user
1426
- global_object_square_database_helper.delete_rows_v0(
1427
- database_name=global_string_database_name,
1428
- schema_name=global_string_schema_name,
1429
- table_name=UserSession.__tablename__,
1430
- filters=FiltersV0(
1431
- root={
1432
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1433
- UserSession.app_id.name: FilterConditionsV0(in_=app_ids),
1434
- }
1435
- ),
1436
- )
1437
- """
1438
- return value
1439
- """
1440
- output_content = get_api_output_in_standard_format(
1441
- message=messages["LOGOUT_SUCCESSFUL"],
1442
- )
1443
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1444
- except HTTPException as http_exception:
1445
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1446
- return JSONResponse(
1447
- status_code=http_exception.status_code, content=http_exception.detail
1448
- )
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)
1449
228
  except Exception as e:
1450
- """
1451
- rollback logic
1452
- """
1453
229
  global_object_square_logger.logger.error(e, exc_info=True)
1454
230
  output_content = get_api_output_in_standard_format(
1455
- message=messages["GENERIC_500"],
1456
- log=str(e),
231
+ message=messages["GENERIC_500"], log=str(e)
1457
232
  )
1458
233
  return JSONResponse(
1459
234
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1465,59 +240,15 @@ async def logout_apps_v0(
1465
240
  async def logout_all_v0(
1466
241
  access_token: Annotated[str, Header()],
1467
242
  ):
1468
-
1469
243
  try:
1470
- """
1471
- validation
1472
- """
1473
- try:
1474
- local_dict_access_token_payload = get_jwt_payload(
1475
- access_token, config_str_secret_key_for_access_token
1476
- )
1477
- except Exception as error:
1478
- output_content = get_api_output_in_standard_format(
1479
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1480
- )
1481
- raise HTTPException(
1482
- status_code=status.HTTP_400_BAD_REQUEST,
1483
- detail=output_content,
1484
- )
1485
- user_id = local_dict_access_token_payload["user_id"]
1486
-
1487
- """
1488
- main process
1489
- """
1490
- # delete session for user
1491
- global_object_square_database_helper.delete_rows_v0(
1492
- database_name=global_string_database_name,
1493
- schema_name=global_string_schema_name,
1494
- table_name=UserSession.__tablename__,
1495
- filters=FiltersV0(
1496
- root={
1497
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1498
- }
1499
- ),
1500
- )
1501
- """
1502
- return value
1503
- """
1504
- output_content = get_api_output_in_standard_format(
1505
- message=messages["LOGOUT_SUCCESSFUL"],
1506
- )
1507
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1508
- except HTTPException as http_exception:
1509
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1510
- return JSONResponse(
1511
- status_code=http_exception.status_code, content=http_exception.detail
1512
- )
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)
1513
248
  except Exception as e:
1514
- """
1515
- rollback logic
1516
- """
1517
249
  global_object_square_logger.logger.error(e, exc_info=True)
1518
250
  output_content = get_api_output_in_standard_format(
1519
- message=messages["GENERIC_500"],
1520
- log=str(e),
251
+ message=messages["GENERIC_500"], log=str(e)
1521
252
  )
1522
253
  return JSONResponse(
1523
254
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1531,121 +262,17 @@ async def update_username_v0(
1531
262
  access_token: Annotated[str, Header()],
1532
263
  ):
1533
264
  try:
1534
- """
1535
- validation
1536
- """
1537
- # validate access token
1538
- try:
1539
- local_dict_access_token_payload = get_jwt_payload(
1540
- access_token, config_str_secret_key_for_access_token
1541
- )
1542
- except Exception as error:
1543
- output_content = get_api_output_in_standard_format(
1544
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1545
- )
1546
- raise HTTPException(
1547
- status_code=status.HTTP_400_BAD_REQUEST,
1548
- detail=output_content,
1549
- )
1550
- user_id = local_dict_access_token_payload["user_id"]
1551
-
1552
- # validation for username
1553
- new_username = new_username.lower()
1554
- username_pattern = re.compile(r"^[a-z0-9._-]{2,20}$")
1555
- if not username_pattern.match(new_username):
1556
- output_content = get_api_output_in_standard_format(
1557
- message=messages["USERNAME_INVALID"],
1558
- log=f"username '{new_username}' is invalid. it must start and end with a letter, "
1559
- f"contain only lowercase letters, numbers, underscores, or hyphens, "
1560
- f"and not have consecutive separators.",
1561
- )
1562
- raise HTTPException(
1563
- status_code=status.HTTP_400_BAD_REQUEST,
1564
- detail=output_content,
1565
- )
1566
-
1567
- # validate user_id
1568
- local_list_user_response = global_object_square_database_helper.get_rows_v0(
1569
- database_name=global_string_database_name,
1570
- schema_name=global_string_schema_name,
1571
- table_name=User.__tablename__,
1572
- filters=FiltersV0(
1573
- root={
1574
- User.user_id.name: FilterConditionsV0(eq=user_id),
1575
- }
1576
- ),
1577
- )["data"]["main"]
1578
-
1579
- if len(local_list_user_response) != 1:
1580
- output_content = get_api_output_in_standard_format(
1581
- message=messages["INCORRECT_USER_ID"],
1582
- log=f"incorrect user_id: {user_id}.",
1583
- )
1584
- raise HTTPException(
1585
- status_code=status.HTTP_400_BAD_REQUEST,
1586
- detail=output_content,
1587
- )
1588
-
1589
- # validate new username
1590
- local_list_user_credentials_response = (
1591
- global_object_square_database_helper.get_rows_v0(
1592
- database_name=global_string_database_name,
1593
- schema_name=global_string_schema_name,
1594
- table_name=User.__tablename__,
1595
- filters=FiltersV0(
1596
- root={
1597
- User.user_username.name: FilterConditionsV0(eq=new_username),
1598
- }
1599
- ),
1600
- )["data"]["main"]
1601
- )
1602
- if len(local_list_user_credentials_response) != 0:
1603
- output_content = get_api_output_in_standard_format(
1604
- message=messages["USERNAME_ALREADY_EXISTS"],
1605
- log=f"{new_username} is taken.",
1606
- )
1607
- raise HTTPException(
1608
- status_code=status.HTTP_400_BAD_REQUEST,
1609
- detail=output_content,
1610
- )
1611
- """
1612
- main process
1613
- """
1614
- # edit the username
1615
- global_object_square_database_helper.edit_rows_v0(
1616
- database_name=global_string_database_name,
1617
- schema_name=global_string_schema_name,
1618
- table_name=User.__tablename__,
1619
- filters=FiltersV0(
1620
- root={
1621
- User.user_id.name: FilterConditionsV0(eq=user_id),
1622
- }
1623
- ),
1624
- data={
1625
- User.user_username.name: new_username,
1626
- },
1627
- )
1628
- """
1629
- return value
1630
- """
1631
- output_content = get_api_output_in_standard_format(
1632
- data={"main": {"user_id": user_id, "username": new_username}},
1633
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
1634
- )
1635
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1636
- except HTTPException as http_exception:
1637
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1638
- return JSONResponse(
1639
- 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
1640
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)
1641
272
  except Exception as e:
1642
- """
1643
- rollback logic
1644
- """
1645
273
  global_object_square_logger.logger.error(e, exc_info=True)
1646
274
  output_content = get_api_output_in_standard_format(
1647
- message=messages["GENERIC_500"],
1648
- log=str(e),
275
+ message=messages["GENERIC_500"], log=str(e)
1649
276
  )
1650
277
  return JSONResponse(
1651
278
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1660,121 +287,17 @@ async def delete_user_v0(
1660
287
  ):
1661
288
  password = body.password
1662
289
  try:
1663
- """
1664
- validation
1665
- """
1666
- # validate access token
1667
- try:
1668
- local_dict_access_token_payload = get_jwt_payload(
1669
- access_token, config_str_secret_key_for_access_token
1670
- )
1671
- except Exception as error:
1672
- output_content = get_api_output_in_standard_format(
1673
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1674
- )
1675
- raise HTTPException(
1676
- status_code=status.HTTP_400_BAD_REQUEST,
1677
- detail=output_content,
1678
- )
1679
- user_id = local_dict_access_token_payload["user_id"]
1680
-
1681
- # validate user_id
1682
- local_list_authentication_user_response = (
1683
- global_object_square_database_helper.get_rows_v0(
1684
- database_name=global_string_database_name,
1685
- schema_name=global_string_schema_name,
1686
- table_name=UserCredential.__tablename__,
1687
- filters=FiltersV0(
1688
- root={UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
1689
- ),
1690
- )["data"]["main"]
1691
- )
1692
- if len(local_list_authentication_user_response) != 1:
1693
- output_content = get_api_output_in_standard_format(
1694
- message=messages["INCORRECT_USER_ID"],
1695
- log=f"incorrect user_id: {user_id}.",
1696
- )
1697
- raise HTTPException(
1698
- status_code=status.HTTP_400_BAD_REQUEST,
1699
- detail=output_content,
1700
- )
1701
-
1702
- # validate password
1703
- local_dict_user = local_list_authentication_user_response[0]
1704
- if not (
1705
- bcrypt.checkpw(
1706
- password.encode("utf-8"),
1707
- local_dict_user[
1708
- UserCredential.user_credential_hashed_password.name
1709
- ].encode("utf-8"),
1710
- )
1711
- ):
1712
- output_content = get_api_output_in_standard_format(
1713
- message=messages["INCORRECT_PASSWORD"],
1714
- log=f"incorrect password for user_id {user_id}.",
1715
- )
1716
- raise HTTPException(
1717
- status_code=status.HTTP_400_BAD_REQUEST,
1718
- detail=output_content,
1719
- )
1720
- """
1721
- main process
1722
- """
1723
- # fetch user profile photo storage token
1724
- user_profile_storage_token = global_object_square_database_helper.get_rows_v0(
1725
- database_name=global_string_database_name,
1726
- schema_name=global_string_schema_name,
1727
- table_name=UserProfile.__tablename__,
1728
- filters=FiltersV0(
1729
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
1730
- ),
1731
- columns=[UserProfile.user_profile_photo_storage_token.name],
1732
- )["data"]["main"][0][UserProfile.user_profile_photo_storage_token.name]
1733
-
1734
- # delete the user.
1735
- global_object_square_database_helper.delete_rows_v0(
1736
- database_name=global_string_database_name,
1737
- schema_name=global_string_schema_name,
1738
- table_name=User.__tablename__,
1739
- filters=FiltersV0(
1740
- root={
1741
- User.user_id.name: FilterConditionsV0(eq=user_id),
1742
- }
1743
- ),
1744
- )
1745
- # delete profile photo if exists
1746
- if user_profile_storage_token:
1747
- try:
1748
- global_object_square_file_store_helper.delete_file_v0(
1749
- list_file_storage_token=[user_profile_storage_token]
1750
- )
1751
- except HTTPError as he:
1752
- global_object_square_logger.warning(
1753
- f"Failed to delete user profile photo with storage token {user_profile_storage_token}. "
1754
- f"Error: {he.response.text}",
1755
- exc_info=True,
1756
- )
1757
- """
1758
- return value
1759
- """
1760
- output_content = get_api_output_in_standard_format(
1761
- message=messages["GENERIC_DELETE_SUCCESSFUL"],
1762
- log=f"user_id: {user_id} deleted successfully.",
1763
- )
1764
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1765
- except HTTPException as http_exception:
1766
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1767
- return JSONResponse(
1768
- status_code=http_exception.status_code, content=http_exception.detail
290
+ return util_delete_user_v0(
291
+ password=password,
292
+ access_token=access_token,
1769
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)
1770
297
  except Exception as e:
1771
- """
1772
- rollback logic
1773
- """
1774
298
  global_object_square_logger.logger.error(e, exc_info=True)
1775
299
  output_content = get_api_output_in_standard_format(
1776
- message=messages["GENERIC_500"],
1777
- log=str(e),
300
+ message=messages["GENERIC_500"], log=str(e)
1778
301
  )
1779
302
  return JSONResponse(
1780
303
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -1792,203 +315,20 @@ async def update_password_v0(
1792
315
  logout_other_sessions = body.logout_other_sessions
1793
316
  preserve_session_refresh_token = body.preserve_session_refresh_token
1794
317
  try:
1795
- """
1796
- validation
1797
- """
1798
- # validate access token
1799
- try:
1800
- local_dict_access_token_payload = get_jwt_payload(
1801
- access_token, config_str_secret_key_for_access_token
1802
- )
1803
- except Exception as error:
1804
- output_content = get_api_output_in_standard_format(
1805
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
1806
- )
1807
- raise HTTPException(
1808
- status_code=status.HTTP_400_BAD_REQUEST,
1809
- detail=output_content,
1810
- )
1811
- user_id = local_dict_access_token_payload["user_id"]
1812
-
1813
- # validate user_id
1814
- local_list_authentication_user_response = (
1815
- global_object_square_database_helper.get_rows_v0(
1816
- database_name=global_string_database_name,
1817
- schema_name=global_string_schema_name,
1818
- table_name=UserCredential.__tablename__,
1819
- filters=FiltersV0(
1820
- root={UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
1821
- ),
1822
- )["data"]["main"]
1823
- )
1824
- if len(local_list_authentication_user_response) != 1:
1825
- output_content = get_api_output_in_standard_format(
1826
- message=messages["INCORRECT_USER_ID"],
1827
- log=f"incorrect user_id: {user_id}.",
1828
- )
1829
- raise HTTPException(
1830
- status_code=status.HTTP_400_BAD_REQUEST,
1831
- detail=output_content,
1832
- )
1833
- # check if user has SELF auth provider
1834
- local_list_response_user_auth_provider = (
1835
- global_object_square_database_helper.get_rows_v0(
1836
- database_name=global_string_database_name,
1837
- schema_name=global_string_schema_name,
1838
- table_name=UserAuthProvider.__tablename__,
1839
- filters=FiltersV0(
1840
- root={
1841
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
1842
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
1843
- eq=AuthProviderEnum.SELF.value
1844
- ),
1845
- }
1846
- ),
1847
- )["data"]["main"]
1848
- )
1849
- if len(local_list_response_user_auth_provider) != 1:
1850
- output_content = get_api_output_in_standard_format(
1851
- message=messages["INCORRECT_AUTH_PROVIDER"],
1852
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
1853
- )
1854
- raise HTTPException(
1855
- status_code=status.HTTP_400_BAD_REQUEST,
1856
- detail=output_content,
1857
- )
1858
- # check if user has credentials (might not be set in case of errors in registration.)
1859
- local_list_response_user = global_object_square_database_helper.get_rows_v0(
1860
- database_name=global_string_database_name,
1861
- schema_name=global_string_schema_name,
1862
- table_name=User.__tablename__,
1863
- filters=FiltersV0(root={User.user_id.name: FilterConditionsV0(eq=user_id)}),
1864
- )["data"]["main"]
1865
- if len(local_list_response_user) != 1:
1866
- output_content = get_api_output_in_standard_format(
1867
- message=messages["MALFORMED_USER"],
1868
- log=f"user_id: {user_id} does not have credentials.",
1869
- )
1870
- raise HTTPException(
1871
- status_code=status.HTTP_400_BAD_REQUEST,
1872
- detail=output_content,
1873
- )
1874
- # validate password
1875
- local_dict_user = local_list_authentication_user_response[0]
1876
- if not (
1877
- bcrypt.checkpw(
1878
- old_password.encode("utf-8"),
1879
- local_dict_user[
1880
- UserCredential.user_credential_hashed_password.name
1881
- ].encode("utf-8"),
1882
- )
1883
- ):
1884
- output_content = get_api_output_in_standard_format(
1885
- message=messages["INCORRECT_PASSWORD"],
1886
- log=f"incorrect password for user_id {user_id}.",
1887
- )
1888
- raise HTTPException(
1889
- status_code=status.HTTP_400_BAD_REQUEST,
1890
- detail=output_content,
1891
- )
1892
- # check if provided refresh token is valid
1893
- if preserve_session_refresh_token:
1894
- local_dict_token_payload = get_jwt_payload(
1895
- preserve_session_refresh_token, config_str_secret_key_for_refresh_token
1896
- )
1897
- local_list_response_user_session = global_object_square_database_helper.get_rows_v0(
1898
- database_name=global_string_database_name,
1899
- schema_name=global_string_schema_name,
1900
- table_name=UserSession.__tablename__,
1901
- filters=FiltersV0(
1902
- root={
1903
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1904
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1905
- eq=preserve_session_refresh_token
1906
- ),
1907
- }
1908
- ),
1909
- )[
1910
- "data"
1911
- ][
1912
- "main"
1913
- ]
1914
- if len(local_list_response_user_session) != 1:
1915
- output_content = get_api_output_in_standard_format(
1916
- message=messages["INCORRECT_REFRESH_TOKEN"],
1917
- log=f"incorrect refresh token: {preserve_session_refresh_token}.",
1918
- )
1919
- raise HTTPException(
1920
- status_code=status.HTTP_400_BAD_REQUEST,
1921
- detail=output_content,
1922
- )
1923
- """
1924
- main process
1925
- """
1926
- # update the password
1927
- local_str_hashed_password = bcrypt.hashpw(
1928
- new_password.encode("utf-8"), bcrypt.gensalt()
1929
- ).decode("utf-8")
1930
- global_object_square_database_helper.edit_rows_v0(
1931
- database_name=global_string_database_name,
1932
- schema_name=global_string_schema_name,
1933
- table_name=UserCredential.__tablename__,
1934
- filters=FiltersV0(
1935
- root={
1936
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
1937
- }
1938
- ),
1939
- data={
1940
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
1941
- },
1942
- )
1943
- if logout_other_sessions:
1944
- if preserve_session_refresh_token:
1945
- # delete all sessions for user except the one with the given refresh token
1946
- global_object_square_database_helper.delete_rows_v0(
1947
- database_name=global_string_database_name,
1948
- schema_name=global_string_schema_name,
1949
- table_name=UserSession.__tablename__,
1950
- filters=FiltersV0(
1951
- root={
1952
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1953
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
1954
- ne=preserve_session_refresh_token
1955
- ),
1956
- }
1957
- ),
1958
- )
1959
- else:
1960
- # delete all sessions for user
1961
- global_object_square_database_helper.delete_rows_v0(
1962
- database_name=global_string_database_name,
1963
- schema_name=global_string_schema_name,
1964
- table_name=UserSession.__tablename__,
1965
- filters=FiltersV0(
1966
- root={
1967
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
1968
- }
1969
- ),
1970
- )
1971
- """
1972
- return value
1973
- """
1974
- output_content = get_api_output_in_standard_format(
1975
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
1976
- log=f"password for user_id: {user_id} updated successfully.",
1977
- )
1978
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1979
- except HTTPException as http_exception:
1980
- global_object_square_logger.logger.error(http_exception, exc_info=True)
1981
- return JSONResponse(
1982
- status_code=http_exception.status_code, content=http_exception.detail
1983
- )
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)
1984
328
  except Exception as e:
1985
- """
1986
- rollback logic
1987
- """
1988
329
  global_object_square_logger.logger.error(e, exc_info=True)
1989
330
  output_content = get_api_output_in_standard_format(
1990
- message=messages["GENERIC_500"],
1991
- log=str(e),
331
+ message=messages["GENERIC_500"], log=str(e)
1992
332
  )
1993
333
  return JSONResponse(
1994
334
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2002,102 +342,19 @@ async def validate_and_get_payload_from_token_v0(
2002
342
  token: Annotated[str, Header()],
2003
343
  token_type: TokenType = Query(...),
2004
344
  ):
2005
-
2006
345
  try:
2007
- """
2008
- validation
2009
- """
2010
- # validate token
2011
- try:
2012
- local_dict_token_payload = None
2013
- if token_type == TokenType.access_token:
2014
- local_dict_token_payload = get_jwt_payload(
2015
- token, config_str_secret_key_for_access_token
2016
- )
2017
- elif token_type == TokenType.refresh_token:
2018
- local_dict_token_payload = get_jwt_payload(
2019
- token, config_str_secret_key_for_refresh_token
2020
- )
2021
- local_list_response_user_session = global_object_square_database_helper.get_rows_v0(
2022
- database_name=global_string_database_name,
2023
- schema_name=global_string_schema_name,
2024
- table_name=UserSession.__tablename__,
2025
- filters=FiltersV0(
2026
- root={
2027
- UserSession.user_session_refresh_token.name: FilterConditionsV0(
2028
- eq=token
2029
- ),
2030
- UserSession.user_id.name: FilterConditionsV0(
2031
- eq=local_dict_token_payload["user_id"]
2032
- ),
2033
- }
2034
- ),
2035
- )[
2036
- "data"
2037
- ][
2038
- "main"
2039
- ]
2040
- if len(local_list_response_user_session) != 1:
2041
- output_content = get_api_output_in_standard_format(
2042
- message=messages["INCORRECT_REFRESH_TOKEN"],
2043
- log="refresh token valid but not present in database.",
2044
- )
2045
- raise HTTPException(
2046
- status_code=status.HTTP_400_BAD_REQUEST,
2047
- detail=output_content,
2048
- )
2049
- if local_dict_token_payload["app_id"] != app_id:
2050
- output_content = get_api_output_in_standard_format(
2051
- message=messages["GENERIC_400"],
2052
- log=f"app_id: {app_id} does not match with token app_id: {local_dict_token_payload['app_id']}.",
2053
- )
2054
- raise HTTPException(
2055
- status_code=status.HTTP_400_BAD_REQUEST,
2056
- detail=output_content,
2057
- )
2058
- except HTTPException as http_exception:
2059
- raise
2060
- except Exception as error:
2061
- output_content = None
2062
- if token_type == TokenType.access_token:
2063
- output_content = get_api_output_in_standard_format(
2064
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2065
- )
2066
- elif token_type == TokenType.refresh_token:
2067
- output_content = get_api_output_in_standard_format(
2068
- message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
2069
- )
2070
-
2071
- raise HTTPException(
2072
- status_code=status.HTTP_400_BAD_REQUEST,
2073
- detail=output_content,
2074
- )
2075
-
2076
- """
2077
- main process
2078
- """
2079
- # pass
2080
- """
2081
- return value
2082
- """
2083
- output_content = get_api_output_in_standard_format(
2084
- message=messages["GENERIC_READ_SUCCESSFUL"],
2085
- data={"main": local_dict_token_payload},
2086
- )
2087
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2088
- except HTTPException as http_exception:
2089
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2090
- return JSONResponse(
2091
- status_code=http_exception.status_code, content=http_exception.detail
2092
- )
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)
2093
354
  except Exception as e:
2094
- """
2095
- rollback logic
2096
- """
2097
355
  global_object_square_logger.logger.error(e, exc_info=True)
2098
356
  output_content = get_api_output_in_standard_format(
2099
- message=messages["GENERIC_500"],
2100
- log=str(e),
357
+ message=messages["GENERIC_500"], log=str(e)
2101
358
  )
2102
359
  return JSONResponse(
2103
360
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2111,221 +368,22 @@ async def update_user_recovery_methods_v0(
2111
368
  recovery_methods_to_add: List[RecoveryMethodEnum] = None,
2112
369
  recovery_methods_to_remove: List[RecoveryMethodEnum] = None,
2113
370
  ):
2114
- if recovery_methods_to_add is None:
2115
- recovery_methods_to_add = []
2116
- if recovery_methods_to_remove is None:
2117
- recovery_methods_to_remove = []
2118
371
  try:
2119
-
2120
- """
2121
- validation
2122
- """
2123
- # validate access token
2124
- try:
2125
- local_dict_access_token_payload = get_jwt_payload(
2126
- access_token, config_str_secret_key_for_access_token
2127
- )
2128
- except Exception as error:
2129
- output_content = get_api_output_in_standard_format(
2130
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2131
- )
2132
- raise HTTPException(
2133
- status_code=status.HTTP_400_BAD_REQUEST,
2134
- detail=output_content,
2135
- )
2136
- user_id = local_dict_access_token_payload["user_id"]
2137
-
2138
- recovery_methods_to_add = list(set(x.value for x in recovery_methods_to_add))
2139
- recovery_methods_to_remove = list(
2140
- set(x.value for x in recovery_methods_to_remove)
2141
- )
2142
-
2143
- # check if recovery_methods_to_add and recovery_methods_to_remove don't have common ids.
2144
- local_list_common_recovery_methods = set(recovery_methods_to_add) & set(
2145
- recovery_methods_to_remove
2146
- )
2147
- if len(local_list_common_recovery_methods) > 0:
2148
- output_content = get_api_output_in_standard_format(
2149
- message=messages["GENERIC_400"],
2150
- log=f"invalid recovery_methods: {list(local_list_common_recovery_methods)}, present in both add list and remove list.",
2151
- )
2152
- raise HTTPException(
2153
- status_code=status.HTTP_400_BAD_REQUEST,
2154
- detail=output_content,
2155
- )
2156
- # check if user's email is verified in user profile.
2157
- # maybe too harsh to reject the request entirely,
2158
- # but for practical purposes this api call should be used for 1 recovery method at a time, so it's not too bad.
2159
- if RecoveryMethodEnum.EMAIL.value in recovery_methods_to_add:
2160
- local_list_response_user_profile = (
2161
- global_object_square_database_helper.get_rows_v0(
2162
- database_name=global_string_database_name,
2163
- schema_name=global_string_schema_name,
2164
- table_name=UserProfile.__tablename__,
2165
- filters=FiltersV0(
2166
- root={
2167
- UserProfile.user_id.name: FilterConditionsV0(eq=user_id),
2168
- }
2169
- ),
2170
- )["data"]["main"]
2171
- )
2172
- if len(local_list_response_user_profile) != 1:
2173
- # maybe this should raise 500 as this error will not occur if code runs correctly.
2174
- output_content = get_api_output_in_standard_format(
2175
- message=messages["GENERIC_400"],
2176
- log=f"user_id: {user_id} does not have a profile.",
2177
- )
2178
- raise HTTPException(
2179
- status_code=status.HTTP_400_BAD_REQUEST,
2180
- detail=output_content,
2181
- )
2182
- local_dict_user_profile = local_list_response_user_profile[0]
2183
- if not local_dict_user_profile[
2184
- UserProfile.user_profile_email_verified.name
2185
- ]:
2186
- output_content = get_api_output_in_standard_format(
2187
- message=messages["EMAIL_NOT_VERIFIED"],
2188
- log=f"user_id: {user_id} does not have email verified.",
2189
- )
2190
- raise HTTPException(
2191
- status_code=status.HTTP_400_BAD_REQUEST,
2192
- detail=output_content,
2193
- )
2194
- """
2195
- main process
2196
- """
2197
- # logic for adding new recovery_methods
2198
- local_list_response_user_recovery_methods = (
2199
- global_object_square_database_helper.get_rows_v0(
2200
- database_name=global_string_database_name,
2201
- schema_name=global_string_schema_name,
2202
- table_name=UserRecoveryMethod.__tablename__,
2203
- filters=FiltersV0(
2204
- root={
2205
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id)
2206
- }
2207
- ),
2208
- )["data"]["main"]
2209
- )
2210
- local_list_new_recovery_methods = [
2211
- {
2212
- UserRecoveryMethod.user_id.name: user_id,
2213
- UserRecoveryMethod.user_recovery_method_name.name: x,
2214
- }
2215
- for x in recovery_methods_to_add
2216
- if x
2217
- not in [
2218
- y[UserRecoveryMethod.user_recovery_method_name.name]
2219
- for y in local_list_response_user_recovery_methods
2220
- ]
2221
- ]
2222
- if len(local_list_new_recovery_methods) > 0:
2223
- global_object_square_database_helper.insert_rows_v0(
2224
- database_name=global_string_database_name,
2225
- schema_name=global_string_schema_name,
2226
- table_name=UserRecoveryMethod.__tablename__,
2227
- data=local_list_new_recovery_methods,
2228
- )
2229
-
2230
- # logic for removing recovery_methods
2231
- remove_old_backup_codes = (
2232
- RecoveryMethodEnum.BACKUP_CODE.value in recovery_methods_to_remove
2233
- )
2234
- old_backup_code_hashes = None
2235
- if remove_old_backup_codes:
2236
- # delete existing backup codes if any
2237
- old_backup_code_hashes = global_object_square_database_helper.get_rows_v0(
2238
- database_name=global_string_database_name,
2239
- schema_name=global_string_schema_name,
2240
- table_name=UserVerificationCode.__tablename__,
2241
- filters=FiltersV0(
2242
- root={
2243
- UserVerificationCode.user_id.name: FilterConditionsV0(
2244
- eq=user_id
2245
- ),
2246
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2247
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2248
- ),
2249
- }
2250
- ),
2251
- columns=[UserVerificationCode.user_verification_code_hash.name],
2252
- )["data"]["main"]
2253
- global_object_square_database_helper.delete_rows_v0(
2254
- database_name=global_string_database_name,
2255
- schema_name=global_string_schema_name,
2256
- table_name=UserRecoveryMethod.__tablename__,
2257
- filters=FiltersV0(
2258
- root={
2259
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2260
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2261
- in_=recovery_methods_to_remove
2262
- ),
2263
- }
2264
- ),
2265
- )
2266
- if remove_old_backup_codes and old_backup_code_hashes:
2267
- global_object_square_database_helper.delete_rows_v0(
2268
- database_name=global_string_database_name,
2269
- schema_name=global_string_schema_name,
2270
- table_name=UserVerificationCode.__tablename__,
2271
- filters=FiltersV0(
2272
- root={
2273
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2274
- in_=[
2275
- x[UserVerificationCode.user_verification_code_hash.name]
2276
- for x in old_backup_code_hashes
2277
- ]
2278
- ),
2279
- }
2280
- ),
2281
- )
2282
-
2283
- """
2284
- return value
2285
- """
2286
- # get latest recovery_methods
2287
- local_list_response_user_recovery_methods = (
2288
- global_object_square_database_helper.get_rows_v0(
2289
- database_name=global_string_database_name,
2290
- schema_name=global_string_schema_name,
2291
- table_name=UserRecoveryMethod.__tablename__,
2292
- filters=FiltersV0(
2293
- root={
2294
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id)
2295
- }
2296
- ),
2297
- )["data"]["main"]
2298
- )
2299
- output_content = get_api_output_in_standard_format(
2300
- message=messages["GENERIC_UPDATE_SUCCESSFUL"],
2301
- data={
2302
- "main": [
2303
- x[UserRecoveryMethod.user_recovery_method_name.name]
2304
- for x in local_list_response_user_recovery_methods
2305
- ]
2306
- },
2307
- )
2308
- return JSONResponse(
2309
- status_code=status.HTTP_200_OK,
2310
- content=output_content,
2311
- )
2312
- except HTTPException as http_exception:
2313
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2314
- return JSONResponse(
2315
- status_code=http_exception.status_code, content=http_exception.detail
2316
- )
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)
2317
380
  except Exception as e:
2318
- """
2319
- rollback logic
2320
- """
2321
381
  global_object_square_logger.logger.error(e, exc_info=True)
2322
382
  output_content = get_api_output_in_standard_format(
2323
- message=messages["GENERIC_500"],
2324
- log=str(e),
383
+ message=messages["GENERIC_500"], log=str(e)
2325
384
  )
2326
385
  return JSONResponse(
2327
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
2328
- content=output_content,
386
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
2329
387
  )
2330
388
 
2331
389
 
@@ -2334,136 +392,17 @@ async def update_user_recovery_methods_v0(
2334
392
  async def generate_account_backup_codes_v0(
2335
393
  access_token: Annotated[str, Header()],
2336
394
  ):
2337
-
2338
395
  try:
2339
- """
2340
- validation
2341
- """
2342
- try:
2343
- local_dict_access_token_payload = get_jwt_payload(
2344
- access_token, config_str_secret_key_for_access_token
2345
- )
2346
- except Exception as error:
2347
- output_content = get_api_output_in_standard_format(
2348
- message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
2349
- )
2350
- raise HTTPException(
2351
- status_code=status.HTTP_400_BAD_REQUEST,
2352
- detail=output_content,
2353
- )
2354
- user_id = local_dict_access_token_payload["user_id"]
2355
- # check if user has recovery method enabled
2356
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2357
- database_name=global_string_database_name,
2358
- schema_name=global_string_schema_name,
2359
- table_name=UserRecoveryMethod.__tablename__,
2360
- filters=FiltersV0(
2361
- root={
2362
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2363
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2364
- eq=RecoveryMethodEnum.BACKUP_CODE.value
2365
- ),
2366
- }
2367
- ),
2368
- )[
2369
- "data"
2370
- ][
2371
- "main"
2372
- ]
2373
- if len(local_list_response_user_recovery_methods) != 1:
2374
- output_content = get_api_output_in_standard_format(
2375
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2376
- log=f"user_id: {user_id} does not have backup codes recovery method enabled.",
2377
- )
2378
- raise HTTPException(
2379
- status_code=status.HTTP_400_BAD_REQUEST,
2380
- detail=output_content,
2381
- )
2382
- """
2383
- main process
2384
- """
2385
- # delete existing backup codes if any
2386
- old_backup_code_hashes = global_object_square_database_helper.get_rows_v0(
2387
- database_name=global_string_database_name,
2388
- schema_name=global_string_schema_name,
2389
- table_name=UserVerificationCode.__tablename__,
2390
- filters=FiltersV0(
2391
- root={
2392
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2393
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2394
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2395
- ),
2396
- }
2397
- ),
2398
- columns=[UserVerificationCode.user_verification_code_hash.name],
2399
- )["data"]["main"]
2400
-
2401
- # generate backup codes
2402
- backup_codes = []
2403
- db_data = []
2404
-
2405
- for i in range(NUMBER_OF_RECOVERY_CODES):
2406
- backup_code = str(uuid.uuid4())
2407
- backup_codes.append(backup_code)
2408
- # hash the backup code
2409
- local_str_hashed_backup_code = bcrypt.hashpw(
2410
- backup_code.encode("utf-8"), bcrypt.gensalt()
2411
- ).decode("utf-8")
2412
-
2413
- db_data.append(
2414
- {
2415
- UserVerificationCode.user_id.name: user_id,
2416
- UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value,
2417
- UserVerificationCode.user_verification_code_hash.name: local_str_hashed_backup_code,
2418
- }
2419
- )
2420
- global_object_square_database_helper.insert_rows_v0(
2421
- database_name=global_string_database_name,
2422
- schema_name=global_string_schema_name,
2423
- table_name=UserVerificationCode.__tablename__,
2424
- data=db_data,
2425
- )
2426
- global_object_square_database_helper.delete_rows_v0(
2427
- database_name=global_string_database_name,
2428
- schema_name=global_string_schema_name,
2429
- table_name=UserVerificationCode.__tablename__,
2430
- filters=FiltersV0(
2431
- root={
2432
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2433
- in_=[
2434
- x[UserVerificationCode.user_verification_code_hash.name]
2435
- for x in old_backup_code_hashes
2436
- ]
2437
- ),
2438
- }
2439
- ),
2440
- )
2441
- """
2442
- return value
2443
- """
2444
- output_content = get_api_output_in_standard_format(
2445
- message=messages["GENERIC_CREATION_SUCCESSFUL"],
2446
- data={
2447
- "main": {
2448
- "user_id": user_id,
2449
- "backup_codes": backup_codes,
2450
- }
2451
- },
2452
- )
2453
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2454
- except HTTPException as http_exception:
2455
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2456
- return JSONResponse(
2457
- status_code=http_exception.status_code, content=http_exception.detail
396
+ return util_generate_account_backup_codes_v0(
397
+ access_token=access_token,
2458
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)
2459
402
  except Exception as e:
2460
- """
2461
- rollback logic
2462
- """
2463
403
  global_object_square_logger.logger.error(e, exc_info=True)
2464
404
  output_content = get_api_output_in_standard_format(
2465
- message=messages["GENERIC_500"],
2466
- log=str(e),
405
+ message=messages["GENERIC_500"], log=str(e)
2467
406
  )
2468
407
  return JSONResponse(
2469
408
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2481,272 +420,20 @@ async def reset_password_and_login_using_backup_code_v0(
2481
420
  app_id = body.app_id
2482
421
  logout_other_sessions = body.logout_other_sessions
2483
422
  try:
2484
- """
2485
- validation
2486
- """
2487
- # validate username
2488
- local_list_authentication_user_response = (
2489
- global_object_square_database_helper.get_rows_v0(
2490
- database_name=global_string_database_name,
2491
- schema_name=global_string_schema_name,
2492
- table_name=User.__tablename__,
2493
- filters=FiltersV0(
2494
- root={User.user_username.name: FilterConditionsV0(eq=username)}
2495
- ),
2496
- )["data"]["main"]
2497
- )
2498
- if len(local_list_authentication_user_response) != 1:
2499
- output_content = get_api_output_in_standard_format(
2500
- message=messages["INCORRECT_USERNAME"],
2501
- log=f"incorrect username: {username}.",
2502
- )
2503
- raise HTTPException(
2504
- status_code=status.HTTP_400_BAD_REQUEST,
2505
- detail=output_content,
2506
- )
2507
- user_id = local_list_authentication_user_response[0][User.user_id.name]
2508
- # check if user has SELF auth provider
2509
- local_list_response_user_auth_provider = (
2510
- global_object_square_database_helper.get_rows_v0(
2511
- database_name=global_string_database_name,
2512
- schema_name=global_string_schema_name,
2513
- table_name=UserAuthProvider.__tablename__,
2514
- filters=FiltersV0(
2515
- root={
2516
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
2517
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
2518
- eq=AuthProviderEnum.SELF.value
2519
- ),
2520
- }
2521
- ),
2522
- )["data"]["main"]
2523
- )
2524
- if len(local_list_response_user_auth_provider) != 1:
2525
- output_content = get_api_output_in_standard_format(
2526
- message=messages["INCORRECT_AUTH_PROVIDER"],
2527
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
2528
- )
2529
- raise HTTPException(
2530
- status_code=status.HTTP_400_BAD_REQUEST,
2531
- detail=output_content,
2532
- )
2533
- # check if user has recovery method enabled
2534
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2535
- database_name=global_string_database_name,
2536
- schema_name=global_string_schema_name,
2537
- table_name=UserRecoveryMethod.__tablename__,
2538
- filters=FiltersV0(
2539
- root={
2540
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2541
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2542
- eq=RecoveryMethodEnum.BACKUP_CODE.value
2543
- ),
2544
- }
2545
- ),
2546
- )[
2547
- "data"
2548
- ][
2549
- "main"
2550
- ]
2551
- if len(local_list_response_user_recovery_methods) != 1:
2552
- output_content = get_api_output_in_standard_format(
2553
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2554
- log=f"user_id: {user_id} does not have backup codes recovery method enabled.",
2555
- )
2556
- raise HTTPException(
2557
- status_code=status.HTTP_400_BAD_REQUEST,
2558
- detail=output_content,
2559
- )
2560
- # validate if user is assigned to the app.
2561
- # not checking [skipping] if the app exists, as it is not required for this endpoint.
2562
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
2563
- database_name=global_string_database_name,
2564
- schema_name=global_string_schema_name,
2565
- table_name=UserApp.__tablename__,
2566
- filters=FiltersV0(
2567
- root={
2568
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
2569
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
2570
- }
2571
- ),
2572
- )["data"]["main"]
2573
- if len(local_list_response_user_app) == 0:
2574
- output_content = get_api_output_in_standard_format(
2575
- message=messages["GENERIC_400"],
2576
- log=f"user_id: {user_id} is not assigned to app_id: {app_id}.",
2577
- )
2578
- raise HTTPException(
2579
- status_code=status.HTTP_400_BAD_REQUEST,
2580
- detail=output_content,
2581
- )
2582
- """
2583
- main process
2584
- """
2585
- # validate backup code
2586
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
2587
- database_name=global_string_database_name,
2588
- schema_name=global_string_schema_name,
2589
- table_name=UserVerificationCode.__tablename__,
2590
- filters=FiltersV0(
2591
- root={
2592
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2593
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2594
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2595
- ),
2596
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
2597
- is_null=True
2598
- ),
2599
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
2600
- is_null=True
2601
- ),
2602
- }
2603
- ),
2604
- columns=[UserVerificationCode.user_verification_code_hash.name],
2605
- )[
2606
- "data"
2607
- ][
2608
- "main"
2609
- ]
2610
- # find the backup code in the list
2611
- local_list_response_user_verification_code = [
2612
- x
2613
- for x in local_list_response_user_verification_code
2614
- if bcrypt.checkpw(
2615
- backup_code.encode("utf-8"),
2616
- x[UserVerificationCode.user_verification_code_hash.name].encode(
2617
- "utf-8"
2618
- ),
2619
- )
2620
- ]
2621
- if len(local_list_response_user_verification_code) != 1:
2622
- output_content = get_api_output_in_standard_format(
2623
- message=messages["INCORRECT_BACKUP_CODE"],
2624
- log=f"incorrect backup code: {backup_code} for user_id: {user_id}.",
2625
- )
2626
- raise HTTPException(
2627
- status_code=status.HTTP_400_BAD_REQUEST,
2628
- detail=output_content,
2629
- )
2630
- # hash the new password
2631
- local_str_hashed_password = bcrypt.hashpw(
2632
- new_password.encode("utf-8"), bcrypt.gensalt()
2633
- ).decode("utf-8")
2634
- # update the password
2635
- global_object_square_database_helper.edit_rows_v0(
2636
- database_name=global_string_database_name,
2637
- schema_name=global_string_schema_name,
2638
- table_name=UserCredential.__tablename__,
2639
- filters=FiltersV0(
2640
- root={
2641
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
2642
- }
2643
- ),
2644
- data={
2645
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
2646
- },
2647
- )
2648
- # mark the backup code as used
2649
- global_object_square_database_helper.edit_rows_v0(
2650
- database_name=global_string_database_name,
2651
- schema_name=global_string_schema_name,
2652
- table_name=UserVerificationCode.__tablename__,
2653
- filters=FiltersV0(
2654
- root={
2655
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2656
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2657
- eq=VerificationCodeTypeEnum.BACKUP_CODE_RECOVERY.value
2658
- ),
2659
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
2660
- eq=local_list_response_user_verification_code[0][
2661
- UserVerificationCode.user_verification_code_hash.name
2662
- ]
2663
- ),
2664
- }
2665
- ),
2666
- data={
2667
- UserVerificationCode.user_verification_code_used_at.name: datetime.now(
2668
- timezone.utc
2669
- ).strftime("%Y-%m-%d %H:%M:%S.%f+00"),
2670
- },
2671
- )
2672
- if logout_other_sessions:
2673
- # delete all sessions for user
2674
- global_object_square_database_helper.delete_rows_v0(
2675
- database_name=global_string_database_name,
2676
- schema_name=global_string_schema_name,
2677
- table_name=UserSession.__tablename__,
2678
- filters=FiltersV0(
2679
- root={
2680
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
2681
- }
2682
- ),
2683
- )
2684
- # generate access token and refresh token
2685
- local_dict_access_token_payload = {
2686
- "app_id": app_id,
2687
- "user_id": user_id,
2688
- "exp": datetime.now(timezone.utc)
2689
- + timedelta(minutes=config_int_access_token_valid_minutes),
2690
- }
2691
- local_str_access_token = jwt.encode(
2692
- local_dict_access_token_payload, config_str_secret_key_for_access_token
2693
- )
2694
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
2695
- minutes=config_int_refresh_token_valid_minutes
2696
- )
2697
- local_dict_refresh_token_payload = {
2698
- "app_id": app_id,
2699
- "user_id": user_id,
2700
- "exp": local_object_refresh_token_expiry_time,
2701
- }
2702
- local_str_refresh_token = jwt.encode(
2703
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
2704
- )
2705
- # insert the refresh token in the database
2706
- global_object_square_database_helper.insert_rows_v0(
2707
- database_name=global_string_database_name,
2708
- schema_name=global_string_schema_name,
2709
- table_name=UserSession.__tablename__,
2710
- data=[
2711
- {
2712
- UserSession.user_id.name: user_id,
2713
- UserSession.app_id.name: app_id,
2714
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
2715
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
2716
- "%Y-%m-%d %H:%M:%S.%f+00"
2717
- ),
2718
- }
2719
- ],
2720
- )
2721
- """
2722
- return value
2723
- """
2724
- output_content = get_api_output_in_standard_format(
2725
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
2726
- data={
2727
- "main": {
2728
- "user_id": user_id,
2729
- "access_token": local_str_access_token,
2730
- "refresh_token": local_str_refresh_token,
2731
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
2732
- }
2733
- },
2734
- )
2735
-
2736
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2737
- except HTTPException as http_exception:
2738
- global_object_square_logger.logger.error(http_exception, exc_info=True)
2739
- return JSONResponse(
2740
- status_code=http_exception.status_code, content=http_exception.detail
2741
- )
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)
2742
433
  except Exception as e:
2743
- """
2744
- rollback logic
2745
- """
2746
434
  global_object_square_logger.logger.error(e, exc_info=True)
2747
435
  output_content = get_api_output_in_standard_format(
2748
- message=messages["GENERIC_500"],
2749
- log=str(e),
436
+ message=messages["GENERIC_500"], log=str(e)
2750
437
  )
2751
438
  return JSONResponse(
2752
439
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -2760,261 +447,16 @@ async def send_reset_password_email_v0(
2760
447
  ):
2761
448
  username = body.username
2762
449
  try:
2763
- """
2764
- validation
2765
- """
2766
- # validate username
2767
- local_list_authentication_user_response = (
2768
- global_object_square_database_helper.get_rows_v0(
2769
- database_name=global_string_database_name,
2770
- schema_name=global_string_schema_name,
2771
- table_name=User.__tablename__,
2772
- filters=FiltersV0(
2773
- root={User.user_username.name: FilterConditionsV0(eq=username)}
2774
- ),
2775
- )["data"]["main"]
2776
- )
2777
- if len(local_list_authentication_user_response) != 1:
2778
- output_content = get_api_output_in_standard_format(
2779
- message=messages["INCORRECT_USERNAME"],
2780
- log=f"incorrect username: {username}.",
2781
- )
2782
- raise HTTPException(
2783
- status_code=status.HTTP_400_BAD_REQUEST,
2784
- detail=output_content,
2785
- )
2786
- user_id = local_list_authentication_user_response[0][User.user_id.name]
2787
- # check if user has SELF auth provider
2788
- local_list_response_user_auth_provider = (
2789
- global_object_square_database_helper.get_rows_v0(
2790
- database_name=global_string_database_name,
2791
- schema_name=global_string_schema_name,
2792
- table_name=UserAuthProvider.__tablename__,
2793
- filters=FiltersV0(
2794
- root={
2795
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
2796
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
2797
- eq=AuthProviderEnum.SELF.value
2798
- ),
2799
- }
2800
- ),
2801
- )["data"]["main"]
2802
- )
2803
- if len(local_list_response_user_auth_provider) != 1:
2804
- output_content = get_api_output_in_standard_format(
2805
- message=messages["INCORRECT_AUTH_PROVIDER"],
2806
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
2807
- )
2808
- raise HTTPException(
2809
- status_code=status.HTTP_400_BAD_REQUEST,
2810
- detail=output_content,
2811
- )
2812
- # check if user has recovery method enabled
2813
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
2814
- database_name=global_string_database_name,
2815
- schema_name=global_string_schema_name,
2816
- table_name=UserRecoveryMethod.__tablename__,
2817
- filters=FiltersV0(
2818
- root={
2819
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
2820
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
2821
- eq=RecoveryMethodEnum.EMAIL.value
2822
- ),
2823
- }
2824
- ),
2825
- )[
2826
- "data"
2827
- ][
2828
- "main"
2829
- ]
2830
- if len(local_list_response_user_recovery_methods) != 1:
2831
- output_content = get_api_output_in_standard_format(
2832
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
2833
- log=f"user_id: {user_id} does not have email recovery method enabled.",
2834
- )
2835
- raise HTTPException(
2836
- status_code=status.HTTP_400_BAD_REQUEST,
2837
- detail=output_content,
2838
- )
2839
- # validate if user has email in profile
2840
- user_profile_response = global_object_square_database_helper.get_rows_v0(
2841
- database_name=global_string_database_name,
2842
- schema_name=global_string_schema_name,
2843
- table_name=UserProfile.__tablename__,
2844
- filters=FiltersV0(
2845
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
2846
- ),
2847
- apply_filters=True,
2848
- )
2849
- user_profile_data = user_profile_response["data"]["main"][0]
2850
- if not user_profile_data.get(UserProfile.user_profile_email.name):
2851
- output_content = get_api_output_in_standard_format(
2852
- message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
2853
- log="email is required to send verification email.",
2854
- )
2855
- raise HTTPException(
2856
- status_code=status.HTTP_400_BAD_REQUEST,
2857
- detail=output_content,
2858
- )
2859
- # check if email is not verified
2860
- if not user_profile_data.get(UserProfile.user_profile_email_verified.name):
2861
- output_content = get_api_output_in_standard_format(
2862
- message=messages["EMAIL_NOT_VERIFIED"],
2863
- log="email is not verified.",
2864
- )
2865
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
2866
- # check if reset password code already exists
2867
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
2868
- database_name=global_string_database_name,
2869
- schema_name=global_string_schema_name,
2870
- table_name=UserVerificationCode.__tablename__,
2871
- filters=FiltersV0(
2872
- root={
2873
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
2874
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
2875
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
2876
- ),
2877
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
2878
- is_null=True
2879
- ),
2880
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
2881
- gte=datetime.now(timezone.utc).strftime(
2882
- "%Y-%m-%d %H:%M:%S.%f+00"
2883
- )
2884
- ),
2885
- }
2886
- ),
2887
- order_by=[
2888
- "-" + UserVerificationCode.user_verification_code_created_at.name
2889
- ],
2890
- limit=1,
2891
- apply_filters=True,
2892
- )[
2893
- "data"
2894
- ][
2895
- "main"
2896
- ]
2897
- if len(local_list_response_user_verification_code) > 0:
2898
- existing_verification_code_data = (
2899
- local_list_response_user_verification_code[0]
2900
- )
2901
- if (
2902
- datetime.now(timezone.utc)
2903
- - datetime.fromisoformat(
2904
- existing_verification_code_data[
2905
- UserVerificationCode.user_verification_code_created_at.name
2906
- ]
2907
- )
2908
- ).total_seconds() < RESEND_COOL_DOWN_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS:
2909
- output_content = get_api_output_in_standard_format(
2910
- message=messages["GENERIC_400"],
2911
- log="verification code already exists and was sent within the cooldown period.",
2912
- )
2913
- raise HTTPException(
2914
- status_code=status.HTTP_400_BAD_REQUEST,
2915
- detail=output_content,
2916
- )
2917
- """
2918
- main process
2919
- """
2920
- verification_code = random.randint(
2921
- 10 ** (NUMBER_OF_DIGITS_IN_EMAIL_PASSWORD_RESET_CODE - 1),
2922
- 10**NUMBER_OF_DIGITS_IN_EMAIL_PASSWORD_RESET_CODE - 1,
2923
- )
2924
- # hash the verification code
2925
- hashed_verification_code = bcrypt.hashpw(
2926
- str(verification_code).encode("utf-8"), bcrypt.gensalt()
2927
- ).decode("utf-8")
2928
- expires_at = datetime.now(timezone.utc) + timedelta(
2929
- seconds=EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS
2930
- )
2931
- # add verification code to UserVerification code table
2932
- global_object_square_database_helper.insert_rows_v0(
2933
- database_name=global_string_database_name,
2934
- schema_name=global_string_schema_name,
2935
- table_name=UserVerificationCode.__tablename__,
2936
- data=[
2937
- {
2938
- UserVerificationCode.user_id.name: user_id,
2939
- UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.EMAIL_RECOVERY.value,
2940
- UserVerificationCode.user_verification_code_hash.name: hashed_verification_code,
2941
- UserVerificationCode.user_verification_code_expires_at.name: expires_at.strftime(
2942
- "%Y-%m-%d %H:%M:%S.%f+00"
2943
- ),
2944
- }
2945
- ],
2946
- )
2947
- # send verification email
2948
- if (
2949
- user_profile_data[UserProfile.user_profile_first_name.name]
2950
- and user_profile_data[UserProfile.user_profile_last_name.name]
2951
- ):
2952
- user_to_name = f"{user_profile_data[UserProfile.user_profile_first_name.name]} {user_profile_data[UserProfile.user_profile_last_name.name]}"
2953
- elif user_profile_data[UserProfile.user_profile_first_name.name]:
2954
- user_to_name = user_profile_data[UserProfile.user_profile_first_name.name]
2955
- elif user_profile_data[UserProfile.user_profile_last_name.name]:
2956
- user_to_name = user_profile_data[UserProfile.user_profile_last_name.name]
2957
- else:
2958
- user_to_name = ""
2959
-
2960
- mailgun_response = send_email_using_mailgun(
2961
- from_email="auth@thepmsquare.com",
2962
- from_name="square_authentication",
2963
- to_email=user_profile_data[UserProfile.user_profile_email.name],
2964
- to_name=user_to_name,
2965
- subject="Password Reset Verification Code",
2966
- 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.",
2967
- api_key=MAIL_GUN_API_KEY,
2968
- domain_name="thepmsquare.com",
2969
- )
2970
- # add log for email sending
2971
- global_object_square_database_helper.insert_rows_v0(
2972
- database_name=global_string_database_name,
2973
- schema_name=email_schema_name,
2974
- table_name=EmailLog.__tablename__,
2975
- data=[
2976
- {
2977
- EmailLog.user_id.name: user_id,
2978
- EmailLog.recipient_email.name: user_profile_data[
2979
- UserProfile.user_profile_email.name
2980
- ],
2981
- EmailLog.email_type.name: EmailTypeEnum.VERIFY_EMAIL.value,
2982
- EmailLog.status.name: EmailStatusEnum.SENT.value,
2983
- EmailLog.third_party_message_id.name: mailgun_response.get("id"),
2984
- }
2985
- ],
2986
- )
2987
- """
2988
- return value
2989
- """
2990
- cooldown_reset_at = datetime.now(timezone.utc) + timedelta(
2991
- seconds=EXPIRY_TIME_FOR_EMAIL_PASSWORD_RESET_CODE_IN_SECONDS,
2992
- )
2993
-
2994
- output_content = get_api_output_in_standard_format(
2995
- data={
2996
- "expires_at": expires_at.isoformat(),
2997
- "cooldown_reset_at": cooldown_reset_at.isoformat(),
2998
- },
2999
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
3000
- )
3001
- return JSONResponse(
3002
- status_code=status.HTTP_200_OK,
3003
- content=output_content,
3004
- )
3005
- except HTTPException as http_exception:
3006
- global_object_square_logger.logger.error(http_exception, exc_info=True)
3007
- return JSONResponse(
3008
- status_code=http_exception.status_code, content=http_exception.detail
450
+ return util_send_reset_password_email_v0(
451
+ username=username,
3009
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)
3010
456
  except Exception as e:
3011
- """
3012
- rollback logic
3013
- """
3014
457
  global_object_square_logger.logger.error(e, exc_info=True)
3015
458
  output_content = get_api_output_in_standard_format(
3016
- message=messages["GENERIC_500"],
3017
- log=str(e),
459
+ message=messages["GENERIC_500"], log=str(e)
3018
460
  )
3019
461
  return JSONResponse(
3020
462
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
@@ -3032,309 +474,20 @@ async def reset_password_and_login_using_reset_email_code_v0(
3032
474
  app_id = body.app_id
3033
475
  logout_other_sessions = body.logout_other_sessions
3034
476
  try:
3035
- """
3036
- validation
3037
- """
3038
- # validate username
3039
- local_list_authentication_user_response = (
3040
- global_object_square_database_helper.get_rows_v0(
3041
- database_name=global_string_database_name,
3042
- schema_name=global_string_schema_name,
3043
- table_name=User.__tablename__,
3044
- filters=FiltersV0(
3045
- root={User.user_username.name: FilterConditionsV0(eq=username)}
3046
- ),
3047
- )["data"]["main"]
3048
- )
3049
- if len(local_list_authentication_user_response) != 1:
3050
- output_content = get_api_output_in_standard_format(
3051
- message=messages["INCORRECT_USERNAME"],
3052
- log=f"incorrect username: {username}.",
3053
- )
3054
- raise HTTPException(
3055
- status_code=status.HTTP_400_BAD_REQUEST,
3056
- detail=output_content,
3057
- )
3058
- user_id = local_list_authentication_user_response[0][User.user_id.name]
3059
- # check if user has SELF auth provider
3060
- local_list_response_user_auth_provider = (
3061
- global_object_square_database_helper.get_rows_v0(
3062
- database_name=global_string_database_name,
3063
- schema_name=global_string_schema_name,
3064
- table_name=UserAuthProvider.__tablename__,
3065
- filters=FiltersV0(
3066
- root={
3067
- UserAuthProvider.user_id.name: FilterConditionsV0(eq=user_id),
3068
- UserAuthProvider.auth_provider.name: FilterConditionsV0(
3069
- eq=AuthProviderEnum.SELF.value
3070
- ),
3071
- }
3072
- ),
3073
- )["data"]["main"]
3074
- )
3075
- if len(local_list_response_user_auth_provider) != 1:
3076
- output_content = get_api_output_in_standard_format(
3077
- message=messages["INCORRECT_AUTH_PROVIDER"],
3078
- log=f"user_id: {user_id} does not have {AuthProviderEnum.SELF.value} auth provider.",
3079
- )
3080
- raise HTTPException(
3081
- status_code=status.HTTP_400_BAD_REQUEST,
3082
- detail=output_content,
3083
- )
3084
- # check if user has recovery method enabled
3085
- local_list_response_user_recovery_methods = global_object_square_database_helper.get_rows_v0(
3086
- database_name=global_string_database_name,
3087
- schema_name=global_string_schema_name,
3088
- table_name=UserRecoveryMethod.__tablename__,
3089
- filters=FiltersV0(
3090
- root={
3091
- UserRecoveryMethod.user_id.name: FilterConditionsV0(eq=user_id),
3092
- UserRecoveryMethod.user_recovery_method_name.name: FilterConditionsV0(
3093
- eq=RecoveryMethodEnum.EMAIL.value
3094
- ),
3095
- }
3096
- ),
3097
- )[
3098
- "data"
3099
- ][
3100
- "main"
3101
- ]
3102
- if len(local_list_response_user_recovery_methods) != 1:
3103
- output_content = get_api_output_in_standard_format(
3104
- message=messages["RECOVERY_METHOD_NOT_ENABLED"],
3105
- log=f"user_id: {user_id} does not have email recovery method enabled.",
3106
- )
3107
- raise HTTPException(
3108
- status_code=status.HTTP_400_BAD_REQUEST,
3109
- detail=output_content,
3110
- )
3111
- # check if user has email in profile
3112
- user_profile_response = global_object_square_database_helper.get_rows_v0(
3113
- database_name=global_string_database_name,
3114
- schema_name=global_string_schema_name,
3115
- table_name=UserProfile.__tablename__,
3116
- filters=FiltersV0(
3117
- root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
3118
- ),
3119
- apply_filters=True,
3120
- )
3121
- user_profile_data = user_profile_response["data"]["main"][0]
3122
- if not user_profile_data.get(UserProfile.user_profile_email.name):
3123
- output_content = get_api_output_in_standard_format(
3124
- message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
3125
- log="user seems to have email recovery method enabled, but does not have email in profile.",
3126
- )
3127
- raise HTTPException(
3128
- status_code=status.HTTP_400_BAD_REQUEST,
3129
- detail=output_content,
3130
- )
3131
- # check if email is verified.
3132
- if not user_profile_data.get(UserProfile.user_profile_email_verified.name):
3133
- output_content = get_api_output_in_standard_format(
3134
- message=messages["EMAIL_NOT_VERIFIED"],
3135
- log="email is not verified.",
3136
- )
3137
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
3138
- # validate if user is assigned to the app.
3139
- # not checking [skipping] if the app exists, as it is not required for this endpoint.
3140
- local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
3141
- database_name=global_string_database_name,
3142
- schema_name=global_string_schema_name,
3143
- table_name=UserApp.__tablename__,
3144
- filters=FiltersV0(
3145
- root={
3146
- UserApp.user_id.name: FilterConditionsV0(eq=user_id),
3147
- UserApp.app_id.name: FilterConditionsV0(eq=app_id),
3148
- }
3149
- ),
3150
- )["data"]["main"]
3151
- if len(local_list_response_user_app) == 0:
3152
- output_content = get_api_output_in_standard_format(
3153
- message=messages["GENERIC_400"],
3154
- log=f"user_id: {user_id} is not assigned to app_id: {app_id}.",
3155
- )
3156
- raise HTTPException(
3157
- status_code=status.HTTP_400_BAD_REQUEST,
3158
- detail=output_content,
3159
- )
3160
- """
3161
- main process
3162
- """
3163
- # validate email reset code
3164
- local_list_response_user_verification_code = global_object_square_database_helper.get_rows_v0(
3165
- database_name=global_string_database_name,
3166
- schema_name=global_string_schema_name,
3167
- table_name=UserVerificationCode.__tablename__,
3168
- filters=FiltersV0(
3169
- root={
3170
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
3171
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
3172
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
3173
- ),
3174
- UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
3175
- gte=datetime.now(timezone.utc).strftime(
3176
- "%Y-%m-%d %H:%M:%S.%f+00"
3177
- )
3178
- ),
3179
- UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
3180
- is_null=True
3181
- ),
3182
- }
3183
- ),
3184
- columns=[UserVerificationCode.user_verification_code_hash.name],
3185
- order_by=[
3186
- "-" + UserVerificationCode.user_verification_code_created_at.name
3187
- ],
3188
- limit=1,
3189
- )[
3190
- "data"
3191
- ][
3192
- "main"
3193
- ]
3194
- if len(local_list_response_user_verification_code) != 1:
3195
- output_content = get_api_output_in_standard_format(
3196
- message=messages["INCORRECT_VERIFICATION_CODE"],
3197
- log=f"incorrect reset_email_code: {reset_email_code} for user_id: {user_id}.",
3198
- )
3199
- raise HTTPException(
3200
- status_code=status.HTTP_400_BAD_REQUEST,
3201
- detail=output_content,
3202
- )
3203
- latest_hashed_verification_code = local_list_response_user_verification_code[0][
3204
- UserVerificationCode.user_verification_code_hash.name
3205
- ]
3206
-
3207
- if not bcrypt.checkpw(
3208
- reset_email_code.encode("utf-8"),
3209
- latest_hashed_verification_code.encode("utf-8"),
3210
- ):
3211
- output_content = get_api_output_in_standard_format(
3212
- message=messages["INCORRECT_VERIFICATION_CODE"],
3213
- log=f"incorrect reset_email_code: {reset_email_code} for user_id: {user_id}.",
3214
- )
3215
- raise HTTPException(
3216
- status_code=status.HTTP_400_BAD_REQUEST,
3217
- detail=output_content,
3218
- )
3219
-
3220
- # hash the new password
3221
- local_str_hashed_password = bcrypt.hashpw(
3222
- new_password.encode("utf-8"), bcrypt.gensalt()
3223
- ).decode("utf-8")
3224
- # update the password
3225
- global_object_square_database_helper.edit_rows_v0(
3226
- database_name=global_string_database_name,
3227
- schema_name=global_string_schema_name,
3228
- table_name=UserCredential.__tablename__,
3229
- filters=FiltersV0(
3230
- root={
3231
- UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
3232
- }
3233
- ),
3234
- data={
3235
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
3236
- },
3237
- )
3238
- # mark the email code as used
3239
- global_object_square_database_helper.edit_rows_v0(
3240
- database_name=global_string_database_name,
3241
- schema_name=global_string_schema_name,
3242
- table_name=UserVerificationCode.__tablename__,
3243
- filters=FiltersV0(
3244
- root={
3245
- UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
3246
- UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
3247
- eq=VerificationCodeTypeEnum.EMAIL_RECOVERY.value
3248
- ),
3249
- UserVerificationCode.user_verification_code_hash.name: FilterConditionsV0(
3250
- eq=latest_hashed_verification_code
3251
- ),
3252
- }
3253
- ),
3254
- data={
3255
- UserVerificationCode.user_verification_code_used_at.name: datetime.now(
3256
- timezone.utc
3257
- ).strftime("%Y-%m-%d %H:%M:%S.%f+00"),
3258
- },
3259
- )
3260
- if logout_other_sessions:
3261
- # delete all sessions for user
3262
- global_object_square_database_helper.delete_rows_v0(
3263
- database_name=global_string_database_name,
3264
- schema_name=global_string_schema_name,
3265
- table_name=UserSession.__tablename__,
3266
- filters=FiltersV0(
3267
- root={
3268
- UserSession.user_id.name: FilterConditionsV0(eq=user_id),
3269
- }
3270
- ),
3271
- )
3272
- # generate access token and refresh token
3273
- local_dict_access_token_payload = {
3274
- "app_id": app_id,
3275
- "user_id": user_id,
3276
- "exp": datetime.now(timezone.utc)
3277
- + timedelta(minutes=config_int_access_token_valid_minutes),
3278
- }
3279
- local_str_access_token = jwt.encode(
3280
- local_dict_access_token_payload, config_str_secret_key_for_access_token
3281
- )
3282
- local_object_refresh_token_expiry_time = datetime.now(timezone.utc) + timedelta(
3283
- minutes=config_int_refresh_token_valid_minutes
3284
- )
3285
- local_dict_refresh_token_payload = {
3286
- "app_id": app_id,
3287
- "user_id": user_id,
3288
- "exp": local_object_refresh_token_expiry_time,
3289
- }
3290
- local_str_refresh_token = jwt.encode(
3291
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
3292
- )
3293
- # insert the refresh token in the database
3294
- global_object_square_database_helper.insert_rows_v0(
3295
- database_name=global_string_database_name,
3296
- schema_name=global_string_schema_name,
3297
- table_name=UserSession.__tablename__,
3298
- data=[
3299
- {
3300
- UserSession.user_id.name: user_id,
3301
- UserSession.app_id.name: app_id,
3302
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
3303
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
3304
- "%Y-%m-%d %H:%M:%S.%f+00"
3305
- ),
3306
- }
3307
- ],
3308
- )
3309
- """
3310
- return value
3311
- """
3312
- output_content = get_api_output_in_standard_format(
3313
- message=messages["GENERIC_ACTION_SUCCESSFUL"],
3314
- data={
3315
- "main": {
3316
- "user_id": user_id,
3317
- "access_token": local_str_access_token,
3318
- "refresh_token": local_str_refresh_token,
3319
- "refresh_token_expiry_time": local_object_refresh_token_expiry_time.isoformat(),
3320
- }
3321
- },
3322
- )
3323
-
3324
- return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
3325
- except HTTPException as http_exception:
3326
- global_object_square_logger.logger.error(http_exception, exc_info=True)
3327
- return JSONResponse(
3328
- status_code=http_exception.status_code, content=http_exception.detail
3329
- )
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)
3330
487
  except Exception as e:
3331
- """
3332
- rollback logic
3333
- """
3334
488
  global_object_square_logger.logger.error(e, exc_info=True)
3335
489
  output_content = get_api_output_in_standard_format(
3336
- message=messages["GENERIC_500"],
3337
- log=str(e),
490
+ message=messages["GENERIC_500"], log=str(e)
3338
491
  )
3339
492
  return JSONResponse(
3340
493
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content