square-authentication 1.0.0__py3-none-any.whl → 3.0.0__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,22 +1,28 @@
1
1
  from datetime import datetime, timedelta, timezone
2
- from typing import Annotated, Union
2
+ from typing import Annotated, List
3
3
 
4
4
  import bcrypt
5
5
  import jwt
6
- from fastapi import APIRouter, status, Header
6
+ from fastapi import APIRouter, status, Header, HTTPException
7
7
  from fastapi.responses import JSONResponse
8
- from requests.exceptions import HTTPError
8
+ from square_commons import get_api_output_in_standard_format
9
+ from square_database.pydantic_models.pydantic_models import (
10
+ FiltersV0,
11
+ FilterConditionsV0,
12
+ )
9
13
  from square_database_helper.main import SquareDatabaseHelper
10
- from square_database_structure.square.authentication.enums import UserLogEventEnum
14
+ from square_database_structure.square import global_string_database_name
15
+ from square_database_structure.square.authentication import global_string_schema_name
11
16
  from square_database_structure.square.authentication.tables import (
12
- local_string_database_name,
13
- local_string_schema_name,
14
17
  User,
15
- UserLog,
16
18
  UserCredential,
17
- UserProfile,
18
19
  UserSession,
20
+ UserApp,
21
+ )
22
+ from square_database_structure.square.public import (
23
+ global_string_schema_name as global_string_public_schema_name,
19
24
  )
25
+ from square_database_structure.square.public.tables import App
20
26
 
21
27
  from square_authentication.configuration import (
22
28
  global_object_square_logger,
@@ -28,6 +34,13 @@ from square_authentication.configuration import (
28
34
  config_int_square_database_port,
29
35
  config_str_square_database_protocol,
30
36
  )
37
+ from square_authentication.messages import messages
38
+ from square_authentication.pydantic_models.core import (
39
+ RegisterUsernameV0,
40
+ LoginUsernameV0,
41
+ DeleteUserV0,
42
+ UpdatePasswordV0,
43
+ )
31
44
  from square_authentication.utils.token import get_jwt_payload
32
45
 
33
46
  router = APIRouter(
@@ -41,66 +54,541 @@ global_object_square_database_helper = SquareDatabaseHelper(
41
54
  )
42
55
 
43
56
 
44
- @router.get("/register_username/")
57
+ @router.post("/register_username/v0")
45
58
  @global_object_square_logger.async_auto_logger
46
- async def register_username(username: str, password: str):
59
+ async def register_username_v0(
60
+ body: RegisterUsernameV0,
61
+ ):
62
+ username = body.username
63
+ password = body.password
64
+ app_id = body.app_id
65
+
47
66
  local_str_user_id = None
67
+ local_str_access_token = None
68
+ local_str_refresh_token = None
69
+
70
+ username = username.lower()
48
71
  try:
49
- # ======================================================================================
72
+ """
73
+ validation
74
+ """
75
+
76
+ # validation for username
77
+ local_list_response_user_creds = global_object_square_database_helper.get_rows_v0(
78
+ database_name=global_string_database_name,
79
+ schema_name=global_string_schema_name,
80
+ table_name=UserCredential.__tablename__,
81
+ filters=FiltersV0(
82
+ {
83
+ UserCredential.user_credential_username.name: FilterConditionsV0(
84
+ eq=username
85
+ )
86
+ }
87
+ ),
88
+ )[
89
+ "data"
90
+ ][
91
+ "main"
92
+ ]
93
+ if len(local_list_response_user_creds) > 0:
94
+ output_content = get_api_output_in_standard_format(
95
+ message=messages["USERNAME_ALREADY_EXISTS"],
96
+ log=f"an account with the username {username} already exists.",
97
+ )
98
+ raise HTTPException(
99
+ status_code=status.HTTP_409_CONFLICT,
100
+ detail=output_content,
101
+ )
102
+
103
+ """
104
+ main process
105
+ """
50
106
  # entry in user table
51
- local_list_response_user = global_object_square_database_helper.insert_rows(
107
+ local_list_response_user = global_object_square_database_helper.insert_rows_v0(
52
108
  data=[{}],
53
- database_name=local_string_database_name,
54
- schema_name=local_string_schema_name,
109
+ database_name=global_string_database_name,
110
+ schema_name=global_string_schema_name,
55
111
  table_name=User.__tablename__,
56
- )
112
+ )["data"]["main"]
57
113
  local_str_user_id = local_list_response_user[0][User.user_id.name]
58
- # ======================================================================================
59
114
 
60
- # ======================================================================================
61
- # entry in user log
62
- local_list_response_user_log = global_object_square_database_helper.insert_rows(
115
+ # entry in credential table
116
+
117
+ # hash password
118
+ local_str_hashed_password = bcrypt.hashpw(
119
+ password.encode("utf-8"), bcrypt.gensalt()
120
+ ).decode("utf-8")
121
+
122
+ global_object_square_database_helper.insert_rows_v0(
63
123
  data=[
64
124
  {
65
- UserLog.user_id.name: local_str_user_id,
66
- UserLog.user_log_event.name: UserLogEventEnum.CREATED.value,
125
+ UserCredential.user_id.name: local_str_user_id,
126
+ UserCredential.user_credential_username.name: username,
127
+ UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
67
128
  }
68
129
  ],
69
- database_name=local_string_database_name,
70
- schema_name=local_string_schema_name,
71
- table_name=UserLog.__tablename__,
130
+ database_name=global_string_database_name,
131
+ schema_name=global_string_schema_name,
132
+ table_name=UserCredential.__tablename__,
72
133
  )
73
- # ======================================================================================
134
+ if app_id is not None:
135
+ # assign app to user
136
+ global_object_square_database_helper.insert_rows_v0(
137
+ database_name=global_string_database_name,
138
+ schema_name=global_string_schema_name,
139
+ table_name=UserApp.__tablename__,
140
+ data=[
141
+ {
142
+ UserApp.user_id.name: local_str_user_id,
143
+ UserApp.app_id.name: app_id,
144
+ }
145
+ ],
146
+ )
74
147
 
75
- # ======================================================================================
76
- # entry in user profile
77
- local_list_response_user_profile = (
78
- global_object_square_database_helper.insert_rows(
79
- data=[{UserProfile.user_id.name: local_str_user_id}],
80
- database_name=local_string_database_name,
81
- schema_name=local_string_schema_name,
82
- table_name=UserProfile.__tablename__,
148
+ # return new access token and refresh token
149
+ # create access token
150
+ local_dict_access_token_payload = {
151
+ "app_id": app_id,
152
+ "user_id": local_str_user_id,
153
+ "exp": datetime.now(timezone.utc)
154
+ + timedelta(minutes=config_int_access_token_valid_minutes),
155
+ }
156
+ local_str_access_token = jwt.encode(
157
+ local_dict_access_token_payload,
158
+ config_str_secret_key_for_access_token,
159
+ )
160
+
161
+ # create refresh token
162
+ local_object_refresh_token_expiry_time = datetime.now(
163
+ timezone.utc
164
+ ) + timedelta(minutes=config_int_refresh_token_valid_minutes)
165
+
166
+ local_dict_refresh_token_payload = {
167
+ "app_id": app_id,
168
+ "user_id": local_str_user_id,
169
+ "exp": local_object_refresh_token_expiry_time,
170
+ }
171
+ local_str_refresh_token = jwt.encode(
172
+ local_dict_refresh_token_payload,
173
+ config_str_secret_key_for_refresh_token,
174
+ )
175
+ # entry in user session table
176
+ global_object_square_database_helper.insert_rows_v0(
177
+ data=[
178
+ {
179
+ UserSession.user_id.name: local_str_user_id,
180
+ UserSession.app_id.name: app_id,
181
+ UserSession.user_session_refresh_token.name: local_str_refresh_token,
182
+ UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
183
+ "%Y-%m-%d %H:%M:%S.%f+00"
184
+ ),
185
+ }
186
+ ],
187
+ database_name=global_string_database_name,
188
+ schema_name=global_string_schema_name,
189
+ table_name=UserSession.__tablename__,
190
+ )
191
+ """
192
+ return value
193
+ """
194
+ output_content = get_api_output_in_standard_format(
195
+ message=messages["REGISTRATION_SUCCESSFUL"],
196
+ data={
197
+ "main": {
198
+ "user_id": local_str_user_id,
199
+ "username": username,
200
+ "app_id": app_id,
201
+ "access_token": local_str_access_token,
202
+ "refresh_token": local_str_refresh_token,
203
+ },
204
+ },
205
+ )
206
+ return JSONResponse(
207
+ status_code=status.HTTP_201_CREATED,
208
+ content=output_content,
209
+ )
210
+ except HTTPException as http_exception:
211
+ return JSONResponse(
212
+ status_code=http_exception.status_code, content=http_exception.detail
213
+ )
214
+ except Exception as e:
215
+ global_object_square_logger.logger.error(e, exc_info=True)
216
+ """
217
+ rollback logic
218
+ """
219
+ if local_str_user_id:
220
+ global_object_square_database_helper.delete_rows_v0(
221
+ database_name=global_string_database_name,
222
+ schema_name=global_string_schema_name,
223
+ table_name=User.__tablename__,
224
+ filters=FiltersV0(
225
+ {User.user_id.name: FilterConditionsV0(eq=local_str_user_id)}
226
+ ),
83
227
  )
228
+ output_content = get_api_output_in_standard_format(
229
+ message=messages["GENERIC_500"],
230
+ log=str(e),
231
+ )
232
+ return JSONResponse(
233
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
84
234
  )
85
235
 
86
- # ======================================================================================
87
236
 
88
- # ======================================================================================
89
- # entry in credential table
237
+ @router.get("/get_user_details/v0")
238
+ @global_object_square_logger.async_auto_logger
239
+ async def get_user_details_v0(
240
+ access_token: Annotated[str, Header()],
241
+ ):
242
+ try:
243
+ """
244
+ validation
245
+ """
246
+ # validate access token
247
+ try:
248
+ local_dict_access_token_payload = get_jwt_payload(
249
+ access_token, config_str_secret_key_for_access_token
250
+ )
251
+ except Exception as error:
252
+ output_content = get_api_output_in_standard_format(
253
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
254
+ )
255
+ return JSONResponse(
256
+ status_code=status.HTTP_400_BAD_REQUEST,
257
+ content=output_content,
258
+ )
259
+ user_id = local_dict_access_token_payload["user_id"]
260
+ """
261
+ main process
262
+ """
263
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
264
+ database_name=global_string_database_name,
265
+ schema_name=global_string_schema_name,
266
+ table_name=UserApp.__tablename__,
267
+ filters=FiltersV0({UserApp.user_id.name: FilterConditionsV0(eq=user_id)}),
268
+ )["data"]["main"]
269
+ local_list_response_user_credentials = (
270
+ global_object_square_database_helper.get_rows_v0(
271
+ database_name=global_string_database_name,
272
+ schema_name=global_string_schema_name,
273
+ table_name=UserCredential.__tablename__,
274
+ filters=FiltersV0(
275
+ {UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
276
+ ),
277
+ )["data"]["main"]
278
+ )
279
+ # not putting filter for expiry refresh tokens
280
+ local_list_response_user_sessions = (
281
+ global_object_square_database_helper.get_rows_v0(
282
+ database_name=global_string_database_name,
283
+ schema_name=global_string_schema_name,
284
+ table_name=UserSession.__tablename__,
285
+ filters=FiltersV0(
286
+ {
287
+ UserSession.user_id.name: FilterConditionsV0(eq=user_id),
288
+ }
289
+ ),
290
+ )["data"]["main"]
291
+ )
292
+ """
293
+ return value
294
+ """
295
+ return_this = {
296
+ "user_id": user_id,
297
+ "credentials": {
298
+ "username": local_list_response_user_credentials[0][
299
+ UserCredential.user_credential_username.name
300
+ ],
301
+ },
302
+ "apps": [x[UserApp.app_id.name] for x in local_list_response_user_app],
303
+ "sessions": [
304
+ {
305
+ "app_id": x[UserApp.app_id.name],
306
+ "sessions": len(
307
+ [
308
+ y
309
+ for y in local_list_response_user_sessions
310
+ if y[UserSession.app_id.name] == x[UserApp.app_id.name]
311
+ ]
312
+ ),
313
+ }
314
+ for x in local_list_response_user_app
315
+ ],
316
+ }
317
+ output_content = get_api_output_in_standard_format(
318
+ message=messages["GENERIC_READ_SUCCESSFUL"],
319
+ data={"main": return_this},
320
+ )
321
+ return JSONResponse(
322
+ status_code=status.HTTP_200_OK,
323
+ content=output_content,
324
+ )
325
+ except HTTPException as http_exception:
326
+ return JSONResponse(
327
+ status_code=http_exception.status_code, content=http_exception.detail
328
+ )
329
+ except Exception as e:
330
+ """
331
+ rollback logic
332
+ """
333
+ global_object_square_logger.logger.error(e, exc_info=True)
334
+ output_content = get_api_output_in_standard_format(
335
+ message=messages["GENERIC_500"],
336
+ log=str(e),
337
+ )
338
+ return JSONResponse(
339
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
340
+ content=output_content,
341
+ )
90
342
 
91
- # hash password
92
- local_str_hashed_password = bcrypt.hashpw(
93
- password.encode("utf-8"), bcrypt.gensalt()
94
- ).decode("utf-8")
343
+
344
+ @router.patch("/update_user_app_ids/v0")
345
+ @global_object_square_logger.async_auto_logger
346
+ async def update_user_app_ids_v0(
347
+ access_token: Annotated[str, Header()],
348
+ app_ids_to_add: List[int],
349
+ app_ids_to_remove: List[int],
350
+ ):
351
+ try:
352
+
353
+ """
354
+ validation
355
+ """
356
+ # validate access token
357
+ try:
358
+ local_dict_access_token_payload = get_jwt_payload(
359
+ access_token, config_str_secret_key_for_access_token
360
+ )
361
+ except Exception as error:
362
+ output_content = get_api_output_in_standard_format(
363
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
364
+ )
365
+ return JSONResponse(
366
+ status_code=status.HTTP_400_BAD_REQUEST,
367
+ content=output_content,
368
+ )
369
+ user_id = local_dict_access_token_payload["user_id"]
370
+
371
+ app_ids_to_add = list(set(app_ids_to_add))
372
+ app_ids_to_remove = list(set(app_ids_to_remove))
373
+
374
+ # check if app_ids_to_add and app_ids_to_remove don't have common ids.
375
+ local_list_common_app_ids = set(app_ids_to_add) & set(app_ids_to_remove)
376
+ if len(local_list_common_app_ids) > 0:
377
+ output_content = get_api_output_in_standard_format(
378
+ message=messages["GENERIC_400"],
379
+ log=f"invalid app_ids: {list(local_list_common_app_ids)}, present in both add list and remove list.",
380
+ )
381
+ raise HTTPException(
382
+ status_code=status.HTTP_400_BAD_REQUEST,
383
+ detail=output_content,
384
+ )
385
+
386
+ # check if all app_ids are valid
387
+ local_list_all_app_ids = [*app_ids_to_add, *app_ids_to_remove]
388
+ local_list_response_app = global_object_square_database_helper.get_rows_v0(
389
+ database_name=global_string_database_name,
390
+ schema_name=global_string_public_schema_name,
391
+ table_name=App.__tablename__,
392
+ apply_filters=False,
393
+ filters=FiltersV0({}),
394
+ )["data"]["main"]
395
+ local_list_invalid_ids = [
396
+ x
397
+ for x in local_list_all_app_ids
398
+ if x not in [y[App.app_id.name] for y in local_list_response_app]
399
+ ]
400
+ if len(local_list_invalid_ids) > 0:
401
+ output_content = get_api_output_in_standard_format(
402
+ message=messages["GENERIC_400"],
403
+ log=f"invalid app_ids: {local_list_invalid_ids}.",
404
+ )
405
+ raise HTTPException(
406
+ status_code=status.HTTP_400_BAD_REQUEST,
407
+ detail=output_content,
408
+ )
409
+ """
410
+ main process
411
+ """
412
+ # logic for adding new app_ids
413
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
414
+ database_name=global_string_database_name,
415
+ schema_name=global_string_schema_name,
416
+ table_name=UserApp.__tablename__,
417
+ filters=FiltersV0({UserApp.user_id.name: FilterConditionsV0(eq=user_id)}),
418
+ )["data"]["main"]
419
+ local_list_new_app_ids = [
420
+ {
421
+ UserApp.user_id.name: user_id,
422
+ UserApp.app_id.name: x,
423
+ }
424
+ for x in app_ids_to_add
425
+ if x not in [y[UserApp.app_id.name] for y in local_list_response_user_app]
426
+ ]
427
+ if len(local_list_new_app_ids) > 0:
428
+ global_object_square_database_helper.insert_rows_v0(
429
+ database_name=global_string_database_name,
430
+ schema_name=global_string_schema_name,
431
+ table_name=UserApp.__tablename__,
432
+ data=local_list_new_app_ids,
433
+ )
434
+
435
+ # logic for removing app_ids
436
+ for app_id in app_ids_to_remove:
437
+ global_object_square_database_helper.delete_rows_v0(
438
+ database_name=global_string_database_name,
439
+ schema_name=global_string_schema_name,
440
+ table_name=UserApp.__tablename__,
441
+ filters=FiltersV0(
442
+ {
443
+ UserApp.user_id.name: FilterConditionsV0(eq=user_id),
444
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
445
+ }
446
+ ),
447
+ )
448
+ # logout user from removed apps
449
+ global_object_square_database_helper.delete_rows_v0(
450
+ database_name=global_string_database_name,
451
+ schema_name=global_string_schema_name,
452
+ table_name=UserSession.__tablename__,
453
+ filters=FiltersV0(
454
+ {
455
+ UserSession.user_id.name: FilterConditionsV0(eq=user_id),
456
+ UserSession.app_id.name: FilterConditionsV0(eq=app_id),
457
+ }
458
+ ),
459
+ )
460
+
461
+ """
462
+ return value
463
+ """
464
+ # get latest app ids
465
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
466
+ database_name=global_string_database_name,
467
+ schema_name=global_string_schema_name,
468
+ table_name=UserApp.__tablename__,
469
+ filters=FiltersV0({UserApp.user_id.name: FilterConditionsV0(eq=user_id)}),
470
+ )["data"]["main"]
471
+ output_content = get_api_output_in_standard_format(
472
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
473
+ data={
474
+ "main": [x[UserApp.app_id.name] for x in local_list_response_user_app]
475
+ },
476
+ )
477
+ return JSONResponse(
478
+ status_code=status.HTTP_200_OK,
479
+ content=output_content,
480
+ )
481
+ except HTTPException as http_exception:
482
+ return JSONResponse(
483
+ status_code=http_exception.status_code, content=http_exception.detail
484
+ )
485
+ except Exception as e:
486
+ """
487
+ rollback logic
488
+ """
489
+ global_object_square_logger.logger.error(e, exc_info=True)
490
+ output_content = get_api_output_in_standard_format(
491
+ message=messages["GENERIC_500"],
492
+ log=str(e),
493
+ )
494
+ return JSONResponse(
495
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
496
+ content=output_content,
497
+ )
498
+
499
+
500
+ @router.get("/login_username/v0")
501
+ @global_object_square_logger.async_auto_logger
502
+ async def login_username_v0(body: LoginUsernameV0):
503
+ username = body.username
504
+ password = body.password
505
+ app_id = body.app_id
506
+ username = username.lower()
507
+ try:
508
+ """
509
+ validation
510
+ """
511
+ # validation for username
512
+ local_list_authentication_user_response = global_object_square_database_helper.get_rows_v0(
513
+ database_name=global_string_database_name,
514
+ schema_name=global_string_schema_name,
515
+ table_name=UserCredential.__tablename__,
516
+ filters=FiltersV0(
517
+ {
518
+ UserCredential.user_credential_username.name: FilterConditionsV0(
519
+ eq=username
520
+ )
521
+ }
522
+ ),
523
+ )[
524
+ "data"
525
+ ][
526
+ "main"
527
+ ]
528
+ if len(local_list_authentication_user_response) != 1:
529
+ output_content = get_api_output_in_standard_format(
530
+ message=messages["INCORRECT_USERNAME"],
531
+ log=f"incorrect username {username}",
532
+ )
533
+ return JSONResponse(
534
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
535
+ )
536
+ # validate if app_id is assigned to user
537
+ # this will also validate if app_id is valid
538
+ local_dict_user = local_list_authentication_user_response[0]
539
+ local_str_user_id = local_dict_user[UserCredential.user_id.name]
540
+ local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
541
+ database_name=global_string_database_name,
542
+ schema_name=global_string_schema_name,
543
+ table_name=UserApp.__tablename__,
544
+ filters=FiltersV0(
545
+ {
546
+ UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
547
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
548
+ }
549
+ ),
550
+ )["data"]["main"]
551
+ if len(local_list_user_app_response) != 1:
552
+ output_content = get_api_output_in_standard_format(
553
+ message=messages["GENERIC_400"],
554
+ log=f"user_id {local_str_user_id}({username}) not assigned to app {app_id}.",
555
+ )
556
+ return JSONResponse(
557
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
558
+ )
559
+
560
+ # validate password
561
+ if not (
562
+ bcrypt.checkpw(
563
+ password.encode("utf-8"),
564
+ local_dict_user[
565
+ UserCredential.user_credential_hashed_password.name
566
+ ].encode("utf-8"),
567
+ )
568
+ ):
569
+ output_content = get_api_output_in_standard_format(
570
+ message=messages["INCORRECT_PASSWORD"],
571
+ log=f"incorrect password for user_id {local_str_user_id}({username}).",
572
+ )
573
+ return JSONResponse(
574
+ status_code=status.HTTP_400_BAD_REQUEST,
575
+ content=output_content,
576
+ )
577
+ """
578
+ main process
579
+ """
580
+ # return new access token and refresh token
95
581
 
96
582
  # create access token
97
583
  local_dict_access_token_payload = {
584
+ "app_id": app_id,
98
585
  "user_id": local_str_user_id,
99
586
  "exp": datetime.now(timezone.utc)
100
- + timedelta(minutes=config_int_access_token_valid_minutes),
587
+ + timedelta(minutes=config_int_access_token_valid_minutes),
101
588
  }
102
589
  local_str_access_token = jwt.encode(
103
- local_dict_access_token_payload, config_str_secret_key_for_access_token
590
+ local_dict_access_token_payload,
591
+ config_str_secret_key_for_access_token,
104
592
  )
105
593
 
106
594
  # create refresh token
@@ -109,222 +597,189 @@ async def register_username(username: str, password: str):
109
597
  )
110
598
 
111
599
  local_dict_refresh_token_payload = {
600
+ "app_id": app_id,
112
601
  "user_id": local_str_user_id,
113
602
  "exp": local_object_refresh_token_expiry_time,
114
603
  }
115
604
  local_str_refresh_token = jwt.encode(
116
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
605
+ local_dict_refresh_token_payload,
606
+ config_str_secret_key_for_refresh_token,
117
607
  )
118
- try:
119
- local_list_response_authentication_username = global_object_square_database_helper.insert_rows(
120
- data=[
121
- {
122
- UserCredential.user_id.name: local_str_user_id,
123
- UserCredential.user_credential_username.name: username,
124
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
125
- }
126
- ],
127
- database_name=local_string_database_name,
128
- schema_name=local_string_schema_name,
129
- table_name=UserCredential.__tablename__,
130
- )
131
- except HTTPError as http_error:
132
- if http_error.response.status_code == 400:
133
- return JSONResponse(
134
- status_code=status.HTTP_409_CONFLICT,
135
- content=f"an account with the username {username} already exists.",
136
- )
137
- else:
138
- raise http_error
139
- # ======================================================================================
140
-
141
- # ======================================================================================
142
608
  # entry in user session table
143
- local_list_response_user_session = global_object_square_database_helper.insert_rows(
609
+ global_object_square_database_helper.insert_rows_v0(
144
610
  data=[
145
611
  {
146
612
  UserSession.user_id.name: local_str_user_id,
613
+ UserSession.app_id.name: app_id,
147
614
  UserSession.user_session_refresh_token.name: local_str_refresh_token,
148
615
  UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
149
616
  "%Y-%m-%d %H:%M:%S.%f+00"
150
617
  ),
151
618
  }
152
619
  ],
153
- database_name=local_string_database_name,
154
- schema_name=local_string_schema_name,
620
+ database_name=global_string_database_name,
621
+ schema_name=global_string_schema_name,
155
622
  table_name=UserSession.__tablename__,
156
623
  )
157
- # ======================================================================================
624
+ """
625
+ return value
626
+ """
627
+ output_content = get_api_output_in_standard_format(
628
+ data={
629
+ "main": {
630
+ "user_id": local_str_user_id,
631
+ "access_token": local_str_access_token,
632
+ "refresh_token": local_str_refresh_token,
633
+ }
634
+ },
635
+ message=messages["LOGIN_SUCCESSFUL"],
636
+ )
158
637
  return JSONResponse(
159
638
  status_code=status.HTTP_200_OK,
160
- content={
161
- "user_id": local_str_user_id,
162
- "access_token": local_str_access_token,
163
- "refresh_token": local_str_refresh_token,
164
- },
639
+ content=output_content,
640
+ )
641
+ except HTTPException as http_exception:
642
+ return JSONResponse(
643
+ status_code=http_exception.status_code, content=http_exception.detail
165
644
  )
166
645
  except Exception as e:
646
+ """
647
+ rollback logic
648
+ """
167
649
  global_object_square_logger.logger.error(e, exc_info=True)
168
- if local_str_user_id:
169
- global_object_square_database_helper.delete_rows(
170
- database_name=local_string_database_name,
171
- schema_name=local_string_schema_name,
172
- table_name=User.__tablename__,
173
- filters={User.user_id.name: local_str_user_id},
174
- )
650
+ output_content = get_api_output_in_standard_format(
651
+ message=messages["GENERIC_500"],
652
+ log=str(e),
653
+ )
175
654
  return JSONResponse(
176
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
655
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
177
656
  )
178
657
 
179
658
 
180
- @router.get("/login_username/")
659
+ @router.get("/generate_access_token/v0")
181
660
  @global_object_square_logger.async_auto_logger
182
- async def login_username(username: str, password: str):
661
+ async def generate_access_token_v0(
662
+ refresh_token: Annotated[str, Header()],
663
+ ):
183
664
  try:
184
- # ======================================================================================
185
- # get entry from authentication_username table
186
- local_list_authentication_user_response = (
187
- global_object_square_database_helper.get_rows(
188
- database_name=local_string_database_name,
189
- schema_name=local_string_schema_name,
190
- table_name=UserCredential.__tablename__,
191
- filters={UserCredential.user_credential_username.name: username},
192
- )
665
+ """
666
+ validation
667
+ """
668
+ # validate refresh token
669
+ # validating if a session refresh token exists in the database.
670
+ local_list_user_session_response = (
671
+ global_object_square_database_helper.get_rows_v0(
672
+ database_name=global_string_database_name,
673
+ schema_name=global_string_schema_name,
674
+ table_name=UserSession.__tablename__,
675
+ filters=FiltersV0(
676
+ {
677
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
678
+ eq=refresh_token
679
+ ),
680
+ }
681
+ ),
682
+ )["data"]["main"]
193
683
  )
194
- # ======================================================================================
195
684
 
196
- # ======================================================================================
197
- # validate username
198
- # ======================================================================================
199
- if len(local_list_authentication_user_response) != 1:
685
+ if len(local_list_user_session_response) != 1:
686
+ output_content = get_api_output_in_standard_format(
687
+ message=messages["INCORRECT_REFRESH_TOKEN"],
688
+ log=f"incorrect refresh token: {refresh_token}.",
689
+ )
200
690
  return JSONResponse(
201
- status_code=status.HTTP_400_BAD_REQUEST, content="incorrect username."
691
+ status_code=status.HTTP_400_BAD_REQUEST,
692
+ content=output_content,
202
693
  )
203
- # ======================================================================================
204
- # validate password
205
- # ======================================================================================
206
- else:
207
- if not (
208
- bcrypt.checkpw(
209
- password.encode("utf-8"),
210
- local_list_authentication_user_response[0][
211
- UserCredential.user_credential_hashed_password.name
212
- ].encode("utf-8"),
213
- )
214
- ):
215
- return JSONResponse(
216
- status_code=status.HTTP_400_BAD_REQUEST,
217
- content="incorrect password.",
218
- )
219
-
220
- # ======================================================================================
221
- # return new access token and refresh token
222
- # ======================================================================================
223
- else:
224
- local_str_user_id = local_list_authentication_user_response[0][
225
- UserCredential.user_id.name
226
- ]
227
- # create access token
228
- local_dict_access_token_payload = {
229
- "user_id": local_str_user_id,
230
- "exp": datetime.now(timezone.utc)
231
- + timedelta(minutes=config_int_access_token_valid_minutes),
232
- }
233
- local_str_access_token = jwt.encode(
234
- local_dict_access_token_payload,
235
- config_str_secret_key_for_access_token,
236
- )
237
-
238
- # create refresh token
239
- local_object_refresh_token_expiry_time = datetime.now(
240
- timezone.utc
241
- ) + timedelta(minutes=config_int_refresh_token_valid_minutes)
242
-
243
- local_dict_refresh_token_payload = {
244
- "user_id": local_str_user_id,
245
- "exp": local_object_refresh_token_expiry_time,
246
- }
247
- local_str_refresh_token = jwt.encode(
248
- local_dict_refresh_token_payload,
249
- config_str_secret_key_for_refresh_token,
250
- )
251
- # ======================================================================================
252
- # entry in user session table
253
- local_list_response_user_session = global_object_square_database_helper.insert_rows(
254
- data=[
255
- {
256
- UserSession.user_id.name: local_str_user_id,
257
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
258
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
259
- "%Y-%m-%d %H:%M:%S.%f+00"
260
- ),
261
- }
262
- ],
263
- database_name=local_string_database_name,
264
- schema_name=local_string_schema_name,
265
- table_name=UserSession.__tablename__,
266
- )
267
- # ======================================================================================
268
- return JSONResponse(
269
- status_code=status.HTTP_200_OK,
270
- content={
271
- "user_id": local_str_user_id,
272
- "access_token": local_str_access_token,
273
- "refresh_token": local_str_refresh_token,
274
- },
275
- )
276
- # ======================================================================================
277
-
694
+ # validating if the refresh token is valid, active and of the same user.
695
+ try:
696
+ local_dict_refresh_token_payload = get_jwt_payload(
697
+ refresh_token, config_str_secret_key_for_refresh_token
698
+ )
699
+ except Exception as error:
700
+ output_content = get_api_output_in_standard_format(
701
+ message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
702
+ )
703
+ return JSONResponse(
704
+ status_code=status.HTTP_400_BAD_REQUEST,
705
+ content=output_content,
706
+ )
707
+ """
708
+ main process
709
+ """
710
+ # create and send access token
711
+ local_dict_access_token_payload = {
712
+ "app_id": local_dict_refresh_token_payload["app_id"],
713
+ "user_id": local_dict_refresh_token_payload["user_id"],
714
+ "exp": datetime.now(timezone.utc)
715
+ + timedelta(minutes=config_int_access_token_valid_minutes),
716
+ }
717
+ local_str_access_token = jwt.encode(
718
+ local_dict_access_token_payload, config_str_secret_key_for_access_token
719
+ )
720
+ """
721
+ return value
722
+ """
723
+ output_content = get_api_output_in_standard_format(
724
+ data={"main": {"access_token": local_str_access_token}},
725
+ message=messages["GENERIC_CREATION_SUCCESSFUL"],
726
+ )
727
+ return JSONResponse(
728
+ status_code=status.HTTP_200_OK,
729
+ content=output_content,
730
+ )
731
+ except HTTPException as http_exception:
732
+ return JSONResponse(
733
+ status_code=http_exception.status_code, content=http_exception.detail
734
+ )
278
735
  except Exception as e:
736
+ """
737
+ rollback logic
738
+ """
279
739
  global_object_square_logger.logger.error(e, exc_info=True)
740
+ output_content = get_api_output_in_standard_format(
741
+ message=messages["GENERIC_500"],
742
+ log=str(e),
743
+ )
280
744
  return JSONResponse(
281
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
745
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
282
746
  )
283
747
 
284
748
 
285
- @router.get("/generate_access_token/")
749
+ @router.delete("/logout/v0")
286
750
  @global_object_square_logger.async_auto_logger
287
- async def generate_access_token(
288
- user_id: str, refresh_token: Annotated[Union[str, None], Header()]
751
+ async def logout_v0(
752
+ refresh_token: Annotated[str, Header()],
289
753
  ):
290
754
  try:
291
- # ======================================================================================
292
- # validate user_id
293
- local_list_user_response = global_object_square_database_helper.get_rows(
294
- database_name=local_string_database_name,
295
- schema_name=local_string_schema_name,
296
- table_name=User.__tablename__,
297
- filters={User.user_id.name: user_id},
298
- )
299
-
300
- if len(local_list_user_response) != 1:
301
- return JSONResponse(
302
- status_code=status.HTTP_400_BAD_REQUEST,
303
- content=f"incorrect user_id: {user_id}.",
304
- )
305
- # ======================================================================================
306
-
307
- # ======================================================================================
755
+ """
756
+ validation
757
+ """
308
758
  # validate refresh token
309
-
310
759
  # validating if a session refresh token exists in the database.
311
760
  local_list_user_session_response = (
312
- global_object_square_database_helper.get_rows(
313
- database_name=local_string_database_name,
314
- schema_name=local_string_schema_name,
761
+ global_object_square_database_helper.get_rows_v0(
762
+ database_name=global_string_database_name,
763
+ schema_name=global_string_schema_name,
315
764
  table_name=UserSession.__tablename__,
316
- filters={
317
- UserSession.user_id.name: user_id,
318
- UserSession.user_session_refresh_token.name: refresh_token,
319
- },
320
- )
765
+ filters=FiltersV0(
766
+ {
767
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
768
+ eq=refresh_token
769
+ ),
770
+ }
771
+ ),
772
+ )["data"]["main"]
321
773
  )
322
774
 
323
775
  if len(local_list_user_session_response) != 1:
776
+ output_content = get_api_output_in_standard_format(
777
+ message=messages["INCORRECT_REFRESH_TOKEN"],
778
+ log=f"incorrect refresh token: {refresh_token}.",
779
+ )
324
780
  return JSONResponse(
325
781
  status_code=status.HTTP_400_BAD_REQUEST,
326
- content=f"incorrect refresh token: {refresh_token} for user_id: {user_id}."
327
- f"for user_id: {user_id}.",
782
+ content=output_content,
328
783
  )
329
784
  # validating if the refresh token is valid, active and of the same user.
330
785
  try:
@@ -332,133 +787,384 @@ async def generate_access_token(
332
787
  refresh_token, config_str_secret_key_for_refresh_token
333
788
  )
334
789
  except Exception as error:
335
- return JSONResponse(
336
- status_code=status.HTTP_400_BAD_REQUEST,
337
- content=str(error),
790
+ output_content = get_api_output_in_standard_format(
791
+ message=messages["INCORRECT_REFRESH_TOKEN"],
792
+ log=str(error),
338
793
  )
339
-
340
- if local_dict_refresh_token_payload["user_id"] != user_id:
341
794
  return JSONResponse(
342
795
  status_code=status.HTTP_400_BAD_REQUEST,
343
- content=f"refresh token and user_id mismatch.",
796
+ content=output_content,
344
797
  )
345
-
346
798
  # ======================================================================================
799
+ # NOTE: if refresh token has expired no need to delete it during this call
347
800
  # ======================================================================================
348
- # create and send access token
349
- local_dict_access_token_payload = {
350
- "user_id": user_id,
351
- "exp": datetime.now(timezone.utc)
352
- + timedelta(minutes=config_int_access_token_valid_minutes),
353
- }
354
- local_str_access_token = jwt.encode(
355
- local_dict_access_token_payload, config_str_secret_key_for_access_token
801
+ """
802
+ main process
803
+ """
804
+ # delete session for user
805
+ global_object_square_database_helper.delete_rows_v0(
806
+ database_name=global_string_database_name,
807
+ schema_name=global_string_schema_name,
808
+ table_name=UserSession.__tablename__,
809
+ filters=FiltersV0(
810
+ {
811
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
812
+ eq=refresh_token
813
+ ),
814
+ }
815
+ ),
356
816
  )
357
-
817
+ """
818
+ return value
819
+ """
820
+ output_content = get_api_output_in_standard_format(
821
+ message=messages["LOGOUT_SUCCESSFUL"],
822
+ )
823
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
824
+ except HTTPException as http_exception:
358
825
  return JSONResponse(
359
- status_code=status.HTTP_200_OK,
360
- content={"access_token": local_str_access_token},
826
+ status_code=http_exception.status_code, content=http_exception.detail
361
827
  )
362
- # ======================================================================================
363
-
364
828
  except Exception as e:
829
+ """
830
+ rollback logic
831
+ """
365
832
  global_object_square_logger.logger.error(e, exc_info=True)
833
+ output_content = get_api_output_in_standard_format(
834
+ message=messages["GENERIC_500"],
835
+ log=str(e),
836
+ )
366
837
  return JSONResponse(
367
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
838
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
368
839
  )
369
840
 
370
841
 
371
- @router.delete("/logout/")
842
+ @router.patch("/update_username/v0")
372
843
  @global_object_square_logger.async_auto_logger
373
- async def logout(
374
- user_id: str,
375
- access_token: Annotated[Union[str, None], Header()],
376
- refresh_token: Annotated[Union[str, None], Header()],
844
+ async def update_username_v0(
845
+ new_username: str,
846
+ access_token: Annotated[str, Header()],
377
847
  ):
378
848
  try:
379
- # ======================================================================================
849
+ """
850
+ validation
851
+ """
852
+ # validate access token
853
+ try:
854
+ local_dict_access_token_payload = get_jwt_payload(
855
+ access_token, config_str_secret_key_for_access_token
856
+ )
857
+ except Exception as error:
858
+ output_content = get_api_output_in_standard_format(
859
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
860
+ )
861
+ return JSONResponse(
862
+ status_code=status.HTTP_400_BAD_REQUEST,
863
+ content=output_content,
864
+ )
865
+ user_id = local_dict_access_token_payload["user_id"]
866
+
380
867
  # validate user_id
381
- local_list_user_response = global_object_square_database_helper.get_rows(
382
- database_name=local_string_database_name,
383
- schema_name=local_string_schema_name,
868
+ local_list_user_response = global_object_square_database_helper.get_rows_v0(
869
+ database_name=global_string_database_name,
870
+ schema_name=global_string_schema_name,
384
871
  table_name=User.__tablename__,
385
- filters={User.user_id.name: user_id},
386
- )
872
+ filters=FiltersV0(
873
+ {
874
+ User.user_id.name: FilterConditionsV0(eq=user_id),
875
+ }
876
+ ),
877
+ )["data"]["main"]
387
878
 
388
879
  if len(local_list_user_response) != 1:
880
+ output_content = get_api_output_in_standard_format(
881
+ message=messages["INCORRECT_USER_ID"],
882
+ log=f"incorrect user_id: {user_id}.",
883
+ )
389
884
  return JSONResponse(
390
885
  status_code=status.HTTP_400_BAD_REQUEST,
391
- content=f"incorrect user_id: {user_id}.",
886
+ content=output_content,
392
887
  )
393
- # ======================================================================================
394
888
 
395
- # ======================================================================================
396
- # validate refresh token
889
+ # validate new username
890
+ local_list_user_credentials_response = global_object_square_database_helper.get_rows_v0(
891
+ database_name=global_string_database_name,
892
+ schema_name=global_string_schema_name,
893
+ table_name=UserCredential.__tablename__,
894
+ filters=FiltersV0(
895
+ {
896
+ UserCredential.user_credential_username.name: FilterConditionsV0(
897
+ eq=new_username
898
+ ),
899
+ }
900
+ ),
901
+ )[
902
+ "data"
903
+ ][
904
+ "main"
905
+ ]
906
+ if len(local_list_user_credentials_response) != 0:
907
+ output_content = get_api_output_in_standard_format(
908
+ message=messages["USERNAME_ALREADY_EXISTS"],
909
+ log=f"{new_username} is taken.",
910
+ )
911
+ return JSONResponse(
912
+ status_code=status.HTTP_409_CONFLICT,
913
+ content=output_content,
914
+ )
915
+ """
916
+ main process
917
+ """
918
+ # edit the username
919
+ global_object_square_database_helper.edit_rows_v0(
920
+ database_name=global_string_database_name,
921
+ schema_name=global_string_schema_name,
922
+ table_name=UserCredential.__tablename__,
923
+ filters=FiltersV0(
924
+ {
925
+ UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
926
+ }
927
+ ),
928
+ data={
929
+ UserCredential.user_credential_username.name: new_username,
930
+ },
931
+ )
932
+ """
933
+ return value
934
+ """
935
+ output_content = get_api_output_in_standard_format(
936
+ data={"main": {"user_id": user_id, "username": new_username}},
937
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
938
+ )
939
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
940
+ except HTTPException as http_exception:
941
+ return JSONResponse(
942
+ status_code=http_exception.status_code, content=http_exception.detail
943
+ )
944
+ except Exception as e:
945
+ """
946
+ rollback logic
947
+ """
948
+ global_object_square_logger.logger.error(e, exc_info=True)
949
+ output_content = get_api_output_in_standard_format(
950
+ message=messages["GENERIC_500"],
951
+ log=str(e),
952
+ )
953
+ return JSONResponse(
954
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
955
+ )
397
956
 
398
- # validating if a session refresh token exists in the database.
399
- local_list_user_session_response = (
400
- global_object_square_database_helper.get_rows(
401
- database_name=local_string_database_name,
402
- schema_name=local_string_schema_name,
403
- table_name=UserSession.__tablename__,
404
- filters={
405
- UserSession.user_id.name: user_id,
406
- UserSession.user_session_refresh_token.name: refresh_token,
407
- },
957
+
958
+ @router.delete("/delete_user/v0")
959
+ @global_object_square_logger.async_auto_logger
960
+ async def delete_user_v0(
961
+ body: DeleteUserV0,
962
+ access_token: Annotated[str, Header()],
963
+ ):
964
+ password = body.password
965
+ try:
966
+ """
967
+ validation
968
+ """
969
+ # validate access token
970
+ try:
971
+ local_dict_access_token_payload = get_jwt_payload(
972
+ access_token, config_str_secret_key_for_access_token
408
973
  )
974
+ except Exception as error:
975
+ output_content = get_api_output_in_standard_format(
976
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
977
+ )
978
+ return JSONResponse(
979
+ status_code=status.HTTP_400_BAD_REQUEST,
980
+ content=output_content,
981
+ )
982
+ user_id = local_dict_access_token_payload["user_id"]
983
+
984
+ # validate user_id
985
+ local_list_authentication_user_response = (
986
+ global_object_square_database_helper.get_rows_v0(
987
+ database_name=global_string_database_name,
988
+ schema_name=global_string_schema_name,
989
+ table_name=UserCredential.__tablename__,
990
+ filters=FiltersV0(
991
+ {UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
992
+ ),
993
+ )["data"]["main"]
409
994
  )
995
+ if len(local_list_authentication_user_response) != 1:
996
+ output_content = get_api_output_in_standard_format(
997
+ message=messages["INCORRECT_USER_ID"],
998
+ log=f"incorrect user_id: {user_id}.",
999
+ )
1000
+ return JSONResponse(
1001
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
1002
+ )
410
1003
 
411
- if len(local_list_user_session_response) != 1:
1004
+ # validate password
1005
+ local_dict_user = local_list_authentication_user_response[0]
1006
+ if not (
1007
+ bcrypt.checkpw(
1008
+ password.encode("utf-8"),
1009
+ local_dict_user[
1010
+ UserCredential.user_credential_hashed_password.name
1011
+ ].encode("utf-8"),
1012
+ )
1013
+ ):
1014
+ output_content = get_api_output_in_standard_format(
1015
+ message=messages["INCORRECT_PASSWORD"],
1016
+ log=f"incorrect password for user_id {user_id}.",
1017
+ )
412
1018
  return JSONResponse(
413
1019
  status_code=status.HTTP_400_BAD_REQUEST,
414
- content=f"incorrect refresh token: {refresh_token} for user_id: {user_id}."
415
- f"for user_id: {user_id}.",
1020
+ content=output_content,
416
1021
  )
417
- # not validating if the refresh token is valid, active and of the same user.
418
- # ======================================================================================
1022
+ """
1023
+ main process
1024
+ """
1025
+ # delete the user.
1026
+ global_object_square_database_helper.delete_rows_v0(
1027
+ database_name=global_string_database_name,
1028
+ schema_name=global_string_schema_name,
1029
+ table_name=User.__tablename__,
1030
+ filters=FiltersV0(
1031
+ {
1032
+ User.user_id.name: FilterConditionsV0(eq=user_id),
1033
+ }
1034
+ ),
1035
+ )
1036
+ """
1037
+ return value
1038
+ """
1039
+ output_content = get_api_output_in_standard_format(
1040
+ message=messages["GENERIC_DELETE_SUCCESSFUL"],
1041
+ log=f"user_id: {user_id} deleted successfully.",
1042
+ )
1043
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1044
+ except HTTPException as http_exception:
1045
+ return JSONResponse(
1046
+ status_code=http_exception.status_code, content=http_exception.detail
1047
+ )
1048
+ except Exception as e:
1049
+ """
1050
+ rollback logic
1051
+ """
1052
+ global_object_square_logger.logger.error(e, exc_info=True)
1053
+ output_content = get_api_output_in_standard_format(
1054
+ message=messages["GENERIC_500"],
1055
+ log=str(e),
1056
+ )
1057
+ return JSONResponse(
1058
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
1059
+ )
419
1060
 
420
- # ======================================================================================
1061
+
1062
+ @router.patch("/update_password/v0")
1063
+ @global_object_square_logger.async_auto_logger
1064
+ async def update_password_v0(
1065
+ body: UpdatePasswordV0,
1066
+ access_token: Annotated[str, Header()],
1067
+ ):
1068
+ old_password = body.old_password
1069
+ new_password = body.new_password
1070
+ try:
1071
+ """
1072
+ validation
1073
+ """
421
1074
  # validate access token
422
- # validating if the access token is valid, active and of the same user.
423
1075
  try:
424
1076
  local_dict_access_token_payload = get_jwt_payload(
425
1077
  access_token, config_str_secret_key_for_access_token
426
1078
  )
427
1079
  except Exception as error:
428
- return JSONResponse(
429
- status_code=status.HTTP_400_BAD_REQUEST,
430
- content=str(error),
1080
+ output_content = get_api_output_in_standard_format(
1081
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
431
1082
  )
432
- if local_dict_access_token_payload["user_id"] != user_id:
433
1083
  return JSONResponse(
434
1084
  status_code=status.HTTP_400_BAD_REQUEST,
435
- content=f"access token and user_id mismatch.",
1085
+ content=output_content,
436
1086
  )
1087
+ user_id = local_dict_access_token_payload["user_id"]
437
1088
 
438
- # ======================================================================================
439
-
440
- # NOTE: if both access token and refresh token have expired for a user,
441
- # it can be assumed that user session only needs to be removed from the front end.
1089
+ # validate user_id
1090
+ local_list_authentication_user_response = (
1091
+ global_object_square_database_helper.get_rows_v0(
1092
+ database_name=global_string_database_name,
1093
+ schema_name=global_string_schema_name,
1094
+ table_name=UserCredential.__tablename__,
1095
+ filters=FiltersV0(
1096
+ {UserCredential.user_id.name: FilterConditionsV0(eq=user_id)}
1097
+ ),
1098
+ )["data"]["main"]
1099
+ )
1100
+ if len(local_list_authentication_user_response) != 1:
1101
+ output_content = get_api_output_in_standard_format(
1102
+ message=messages["INCORRECT_USER_ID"],
1103
+ log=f"incorrect user_id: {user_id}.",
1104
+ )
1105
+ return JSONResponse(
1106
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
1107
+ )
442
1108
 
443
- # ======================================================================================
444
- # delete session for user
445
- global_object_square_database_helper.delete_rows(
446
- database_name=local_string_database_name,
447
- schema_name=local_string_schema_name,
448
- table_name=UserSession.__tablename__,
449
- filters={
450
- UserSession.user_id.name: user_id,
451
- UserSession.user_session_refresh_token.name: refresh_token,
1109
+ # validate password
1110
+ local_dict_user = local_list_authentication_user_response[0]
1111
+ if not (
1112
+ bcrypt.checkpw(
1113
+ old_password.encode("utf-8"),
1114
+ local_dict_user[
1115
+ UserCredential.user_credential_hashed_password.name
1116
+ ].encode("utf-8"),
1117
+ )
1118
+ ):
1119
+ output_content = get_api_output_in_standard_format(
1120
+ message=messages["INCORRECT_PASSWORD"],
1121
+ log=f"incorrect password for user_id {user_id}.",
1122
+ )
1123
+ return JSONResponse(
1124
+ status_code=status.HTTP_400_BAD_REQUEST,
1125
+ content=output_content,
1126
+ )
1127
+ """
1128
+ main process
1129
+ """
1130
+ # delete the user.
1131
+ local_str_hashed_password = bcrypt.hashpw(
1132
+ new_password.encode("utf-8"), bcrypt.gensalt()
1133
+ ).decode("utf-8")
1134
+ global_object_square_database_helper.edit_rows_v0(
1135
+ database_name=global_string_database_name,
1136
+ schema_name=global_string_schema_name,
1137
+ table_name=UserCredential.__tablename__,
1138
+ filters=FiltersV0(
1139
+ {
1140
+ UserCredential.user_id.name: FilterConditionsV0(eq=user_id),
1141
+ }
1142
+ ),
1143
+ data={
1144
+ UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
452
1145
  },
453
1146
  )
454
-
1147
+ """
1148
+ return value
1149
+ """
1150
+ output_content = get_api_output_in_standard_format(
1151
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
1152
+ log=f"password for user_id: {user_id} updated successfully.",
1153
+ )
1154
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
1155
+ except HTTPException as http_exception:
455
1156
  return JSONResponse(
456
- status_code=status.HTTP_200_OK, content="Log out successful."
1157
+ status_code=http_exception.status_code, content=http_exception.detail
457
1158
  )
458
- # ======================================================================================
459
-
460
1159
  except Exception as e:
1160
+ """
1161
+ rollback logic
1162
+ """
461
1163
  global_object_square_logger.logger.error(e, exc_info=True)
1164
+ output_content = get_api_output_in_standard_format(
1165
+ message=messages["GENERIC_500"],
1166
+ log=str(e),
1167
+ )
462
1168
  return JSONResponse(
463
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
1169
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
464
1170
  )