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.
@@ -0,0 +1,647 @@
1
+ import random
2
+ from datetime import datetime, timedelta, timezone
3
+
4
+ import bcrypt
5
+ from fastapi import HTTPException, status
6
+ from fastapi.responses import JSONResponse
7
+ from square_commons import get_api_output_in_standard_format
8
+ from square_commons.email import send_email_using_mailgun
9
+ from square_database_helper import FiltersV0
10
+ from square_database_helper.pydantic_models import FilterConditionsV0
11
+ from square_database_structure.square import global_string_database_name
12
+ from square_database_structure.square.authentication import global_string_schema_name
13
+ from square_database_structure.square.authentication.enums import (
14
+ VerificationCodeTypeEnum,
15
+ )
16
+ from square_database_structure.square.authentication.tables import (
17
+ UserProfile,
18
+ UserVerificationCode,
19
+ )
20
+ from square_database_structure.square.email import (
21
+ global_string_schema_name as email_schema_name,
22
+ )
23
+ from square_database_structure.square.email.enums import EmailStatusEnum, EmailTypeEnum
24
+ from square_database_structure.square.email.tables import EmailLog
25
+
26
+ from square_authentication.configuration import (
27
+ EXPIRY_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS,
28
+ MAIL_GUN_API_KEY,
29
+ NUMBER_OF_DIGITS_IN_EMAIL_VERIFICATION_CODE,
30
+ RESEND_COOL_DOWN_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS,
31
+ config_str_secret_key_for_access_token,
32
+ global_object_square_database_helper,
33
+ global_object_square_logger,
34
+ )
35
+ from square_authentication.configuration import (
36
+ global_object_square_file_store_helper,
37
+ )
38
+ from square_authentication.messages import messages
39
+ from square_authentication.utils.token import get_jwt_payload
40
+
41
+
42
+ @global_object_square_logger.auto_logger()
43
+ def util_update_profile_photo_v0(access_token, profile_photo):
44
+ try:
45
+ """
46
+ validation
47
+ """
48
+ # validate access token
49
+ try:
50
+ local_dict_access_token_payload = get_jwt_payload(
51
+ access_token, config_str_secret_key_for_access_token
52
+ )
53
+ except Exception as error:
54
+ output_content = get_api_output_in_standard_format(
55
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
56
+ )
57
+ raise HTTPException(
58
+ status_code=status.HTTP_400_BAD_REQUEST,
59
+ detail=output_content,
60
+ )
61
+ user_id = local_dict_access_token_payload["user_id"]
62
+
63
+ # validate file format
64
+ if profile_photo and not profile_photo.filename.endswith(
65
+ (".jpg", ".jpeg", ".png")
66
+ ):
67
+ output_content = get_api_output_in_standard_format(
68
+ message=messages["INVALID_FILE_FORMAT"]
69
+ )
70
+ raise HTTPException(
71
+ status_code=status.HTTP_400_BAD_REQUEST,
72
+ detail=output_content,
73
+ )
74
+
75
+ # validate file size
76
+ file_size_limit_in_mib = 5
77
+ if profile_photo and profile_photo.size > (
78
+ file_size_limit_in_mib * 1024 * 1024
79
+ ):
80
+ output_content = get_api_output_in_standard_format(
81
+ message=messages["FILE_SIZE_EXCEEDS_LIMIT"]
82
+ )
83
+ raise HTTPException(
84
+ status_code=status.HTTP_400_BAD_REQUEST,
85
+ detail=output_content,
86
+ )
87
+ """
88
+ main process
89
+ """
90
+ old_profile_photo_response = global_object_square_database_helper.get_rows_v0(
91
+ database_name=global_string_database_name,
92
+ schema_name=global_string_schema_name,
93
+ table_name=UserProfile.__tablename__,
94
+ filters=FiltersV0(
95
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
96
+ ),
97
+ apply_filters=True,
98
+ )
99
+ old_profile_photo_token = old_profile_photo_response["data"]["main"][0][
100
+ "user_profile_photo_storage_token"
101
+ ]
102
+
103
+ if profile_photo:
104
+ # uploading to square file store
105
+ file_upload_response = (
106
+ global_object_square_file_store_helper.upload_file_using_tuple_v0(
107
+ file=(
108
+ profile_photo.filename,
109
+ profile_photo.file,
110
+ profile_photo.content_type,
111
+ ),
112
+ system_relative_path="global/users/profile_photos",
113
+ )
114
+ )
115
+ # updating user profile
116
+ profile_update_response = global_object_square_database_helper.edit_rows_v0(
117
+ data={
118
+ UserProfile.user_profile_photo_storage_token.name: file_upload_response[
119
+ "data"
120
+ ][
121
+ "main"
122
+ ]
123
+ },
124
+ filters=FiltersV0(
125
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
126
+ ),
127
+ database_name=global_string_database_name,
128
+ schema_name=global_string_schema_name,
129
+ table_name=UserProfile.__tablename__,
130
+ apply_filters=True,
131
+ )
132
+ else:
133
+ # updating user profile
134
+ profile_update_response = global_object_square_database_helper.edit_rows_v0(
135
+ data={UserProfile.user_profile_photo_storage_token.name: None},
136
+ filters=FiltersV0(
137
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
138
+ ),
139
+ database_name=global_string_database_name,
140
+ schema_name=global_string_schema_name,
141
+ table_name=UserProfile.__tablename__,
142
+ apply_filters=True,
143
+ )
144
+
145
+ if old_profile_photo_token:
146
+ global_object_square_file_store_helper.delete_file_v0(
147
+ [old_profile_photo_token]
148
+ )
149
+
150
+ """
151
+ return value
152
+ """
153
+ output_content = get_api_output_in_standard_format(
154
+ data=profile_update_response["data"],
155
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
156
+ )
157
+ return JSONResponse(
158
+ status_code=status.HTTP_200_OK,
159
+ content=output_content,
160
+ )
161
+ except HTTPException as http_exception:
162
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
163
+ return JSONResponse(
164
+ status_code=http_exception.status_code, content=http_exception.detail
165
+ )
166
+ except Exception as e:
167
+ """
168
+ rollback logic
169
+ """
170
+ global_object_square_logger.logger.error(e, exc_info=True)
171
+ output_content = get_api_output_in_standard_format(
172
+ message=messages["GENERIC_500"],
173
+ log=str(e),
174
+ )
175
+ return JSONResponse(
176
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
177
+ )
178
+
179
+
180
+ @global_object_square_logger.auto_logger()
181
+ def util_update_profile_details_v0(
182
+ access_token,
183
+ first_name,
184
+ last_name,
185
+ email,
186
+ phone_number_country_code,
187
+ phone_number,
188
+ ):
189
+ try:
190
+ """
191
+ validation
192
+ """
193
+ # validate access token
194
+ try:
195
+ local_dict_access_token_payload = get_jwt_payload(
196
+ access_token, config_str_secret_key_for_access_token
197
+ )
198
+ except Exception as error:
199
+ output_content = get_api_output_in_standard_format(
200
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
201
+ )
202
+ raise HTTPException(
203
+ status_code=status.HTTP_400_BAD_REQUEST,
204
+ detail=output_content,
205
+ )
206
+ user_id = local_dict_access_token_payload["user_id"]
207
+
208
+ # validate email format
209
+ if email and "@" not in email:
210
+ output_content = get_api_output_in_standard_format(
211
+ message=messages["INVALID_EMAIL_FORMAT"]
212
+ )
213
+ raise HTTPException(
214
+ status_code=status.HTTP_400_BAD_REQUEST,
215
+ detail=output_content,
216
+ )
217
+
218
+ # validate phone number format
219
+ if phone_number and not phone_number.isdigit():
220
+ output_content = get_api_output_in_standard_format(
221
+ message=messages["INVALID_PHONE_NUMBER_FORMAT"]
222
+ )
223
+ raise HTTPException(
224
+ status_code=status.HTTP_400_BAD_REQUEST,
225
+ detail=output_content,
226
+ )
227
+ if (phone_number and not phone_number_country_code) or (
228
+ phone_number_country_code and not phone_number
229
+ ):
230
+ output_content = get_api_output_in_standard_format(
231
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
232
+ log="both phone number and country code must be provided together.",
233
+ )
234
+ raise HTTPException(
235
+ status_code=status.HTTP_400_BAD_REQUEST,
236
+ detail=output_content,
237
+ )
238
+
239
+ """
240
+ main process
241
+ """
242
+ profile_update_data = {}
243
+ if first_name is not None:
244
+ profile_update_data[UserProfile.user_profile_first_name.name] = first_name
245
+ if last_name is not None:
246
+ profile_update_data[UserProfile.user_profile_last_name.name] = last_name
247
+ if email is not None:
248
+ profile_update_data[UserProfile.user_profile_email.name] = email
249
+ if phone_number is not None and phone_number_country_code is not None:
250
+ profile_update_data[UserProfile.user_profile_phone_number.name] = (
251
+ phone_number
252
+ )
253
+ profile_update_data[
254
+ UserProfile.user_profile_phone_number_country_code.name
255
+ ] = phone_number_country_code
256
+
257
+ # updating user profile
258
+ profile_update_response = global_object_square_database_helper.edit_rows_v0(
259
+ data=profile_update_data,
260
+ filters=FiltersV0(
261
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
262
+ ),
263
+ database_name=global_string_database_name,
264
+ schema_name=global_string_schema_name,
265
+ table_name=UserProfile.__tablename__,
266
+ apply_filters=True,
267
+ )
268
+
269
+ """
270
+ return value
271
+ """
272
+ output_content = get_api_output_in_standard_format(
273
+ data=profile_update_response["data"],
274
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
275
+ )
276
+ return JSONResponse(
277
+ status_code=status.HTTP_200_OK,
278
+ content=output_content,
279
+ )
280
+ except HTTPException as http_exception:
281
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
282
+ return JSONResponse(
283
+ status_code=http_exception.status_code, content=http_exception.detail
284
+ )
285
+ except Exception as e:
286
+ """
287
+ rollback logic
288
+ """
289
+ global_object_square_logger.logger.error(e, exc_info=True)
290
+ output_content = get_api_output_in_standard_format(
291
+ message=messages["GENERIC_500"],
292
+ log=str(e),
293
+ )
294
+ return JSONResponse(
295
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
296
+ )
297
+
298
+
299
+ @global_object_square_logger.auto_logger()
300
+ def util_send_verification_email_v0(access_token):
301
+ try:
302
+ """
303
+ validation
304
+ """
305
+ # validate access token
306
+ try:
307
+ local_dict_access_token_payload = get_jwt_payload(
308
+ access_token, config_str_secret_key_for_access_token
309
+ )
310
+ except Exception as error:
311
+ output_content = get_api_output_in_standard_format(
312
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
313
+ )
314
+ raise HTTPException(
315
+ status_code=status.HTTP_400_BAD_REQUEST,
316
+ detail=output_content,
317
+ )
318
+ user_id = local_dict_access_token_payload["user_id"]
319
+
320
+ # validate if user has email in profile
321
+ user_profile_response = global_object_square_database_helper.get_rows_v0(
322
+ database_name=global_string_database_name,
323
+ schema_name=global_string_schema_name,
324
+ table_name=UserProfile.__tablename__,
325
+ filters=FiltersV0(
326
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
327
+ ),
328
+ apply_filters=True,
329
+ )
330
+ user_profile_data = user_profile_response["data"]["main"][0]
331
+ if not user_profile_data.get(UserProfile.user_profile_email.name):
332
+ output_content = get_api_output_in_standard_format(
333
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
334
+ log="email is required to send verification email.",
335
+ )
336
+ raise HTTPException(
337
+ status_code=status.HTTP_400_BAD_REQUEST,
338
+ detail=output_content,
339
+ )
340
+ # check if email is already verified
341
+ if user_profile_data.get(UserProfile.user_profile_email_verified.name):
342
+ output_content = get_api_output_in_standard_format(
343
+ message=messages["EMAIL_ALREADY_VERIFIED"]
344
+ )
345
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
346
+ # check if email verification code already exists
347
+ existing_verification_code_response = 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=UserVerificationCode.__tablename__,
351
+ filters=FiltersV0(
352
+ root={
353
+ UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
354
+ UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
355
+ eq=VerificationCodeTypeEnum.EMAIL_VERIFICATION.value
356
+ ),
357
+ UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
358
+ is_null=True
359
+ ),
360
+ UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
361
+ gte=datetime.now(timezone.utc).strftime(
362
+ "%Y-%m-%d %H:%M:%S.%f+00"
363
+ )
364
+ ),
365
+ }
366
+ ),
367
+ order_by=[
368
+ "-" + UserVerificationCode.user_verification_code_created_at.name
369
+ ],
370
+ limit=1,
371
+ apply_filters=True,
372
+ )
373
+ if len(existing_verification_code_response["data"]["main"]) > 0:
374
+ existing_verification_code_data = existing_verification_code_response[
375
+ "data"
376
+ ]["main"][0]
377
+ if (
378
+ datetime.now(timezone.utc)
379
+ - datetime.fromisoformat(
380
+ existing_verification_code_data[
381
+ UserVerificationCode.user_verification_code_created_at.name
382
+ ]
383
+ )
384
+ ).total_seconds() < RESEND_COOL_DOWN_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS:
385
+ output_content = get_api_output_in_standard_format(
386
+ message=messages["GENERIC_400"],
387
+ log="verification code already exists and was sent within the cooldown period.",
388
+ )
389
+ raise HTTPException(
390
+ status_code=status.HTTP_400_BAD_REQUEST,
391
+ detail=output_content,
392
+ )
393
+
394
+ """
395
+ main process
396
+ """
397
+ verification_code = random.randint(
398
+ 10 ** (NUMBER_OF_DIGITS_IN_EMAIL_VERIFICATION_CODE - 1),
399
+ 10**NUMBER_OF_DIGITS_IN_EMAIL_VERIFICATION_CODE - 1,
400
+ )
401
+ # hash the verification code
402
+ hashed_verification_code = bcrypt.hashpw(
403
+ str(verification_code).encode("utf-8"), bcrypt.gensalt()
404
+ ).decode("utf-8")
405
+ expires_at = datetime.now(timezone.utc) + timedelta(
406
+ seconds=EXPIRY_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS
407
+ )
408
+ # add verification code to UserVerification code table
409
+ global_object_square_database_helper.insert_rows_v0(
410
+ database_name=global_string_database_name,
411
+ schema_name=global_string_schema_name,
412
+ table_name=UserVerificationCode.__tablename__,
413
+ data=[
414
+ {
415
+ UserVerificationCode.user_id.name: user_id,
416
+ UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.EMAIL_VERIFICATION.value,
417
+ UserVerificationCode.user_verification_code_hash.name: hashed_verification_code,
418
+ UserVerificationCode.user_verification_code_expires_at.name: expires_at.strftime(
419
+ "%Y-%m-%d %H:%M:%S.%f+00"
420
+ ),
421
+ }
422
+ ],
423
+ )
424
+ # send verification email
425
+ if (
426
+ user_profile_data[UserProfile.user_profile_first_name.name]
427
+ and user_profile_data[UserProfile.user_profile_last_name.name]
428
+ ):
429
+ user_to_name = f"{user_profile_data[UserProfile.user_profile_first_name.name]} {user_profile_data[UserProfile.user_profile_last_name.name]}"
430
+ elif user_profile_data[UserProfile.user_profile_first_name.name]:
431
+ user_to_name = user_profile_data[UserProfile.user_profile_first_name.name]
432
+ elif user_profile_data[UserProfile.user_profile_last_name.name]:
433
+ user_to_name = user_profile_data[UserProfile.user_profile_last_name.name]
434
+ else:
435
+ user_to_name = ""
436
+
437
+ mailgun_response = send_email_using_mailgun(
438
+ from_email="auth@thepmsquare.com",
439
+ from_name="square_authentication",
440
+ to_email=user_profile_data[UserProfile.user_profile_email.name],
441
+ to_name=user_to_name,
442
+ subject="Email Verification",
443
+ body=f"Your verification code is {verification_code}. It will expire in {EXPIRY_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS / 60} minutes.",
444
+ api_key=MAIL_GUN_API_KEY,
445
+ domain_name="thepmsquare.com",
446
+ )
447
+ # add log for email sending
448
+ global_object_square_database_helper.insert_rows_v0(
449
+ database_name=global_string_database_name,
450
+ schema_name=email_schema_name,
451
+ table_name=EmailLog.__tablename__,
452
+ data=[
453
+ {
454
+ EmailLog.user_id.name: user_id,
455
+ EmailLog.recipient_email.name: user_profile_data[
456
+ UserProfile.user_profile_email.name
457
+ ],
458
+ EmailLog.email_type.name: EmailTypeEnum.VERIFY_EMAIL.value,
459
+ EmailLog.status.name: EmailStatusEnum.SENT.value,
460
+ EmailLog.third_party_message_id.name: mailgun_response.get("id"),
461
+ }
462
+ ],
463
+ )
464
+ """
465
+ return value
466
+ """
467
+ cooldown_reset_at = datetime.now(timezone.utc) + timedelta(
468
+ seconds=RESEND_COOL_DOWN_TIME_FOR_EMAIL_VERIFICATION_CODE_IN_SECONDS
469
+ )
470
+ output_content = get_api_output_in_standard_format(
471
+ data={
472
+ "expires_at": expires_at.isoformat(),
473
+ "cooldown_reset_at": cooldown_reset_at.isoformat(),
474
+ },
475
+ message=messages["GENERIC_ACTION_SUCCESSFUL"],
476
+ )
477
+ return JSONResponse(
478
+ status_code=status.HTTP_200_OK,
479
+ content=output_content,
480
+ )
481
+ except HTTPException as http_exception:
482
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
483
+ return JSONResponse(
484
+ status_code=http_exception.status_code, content=http_exception.detail
485
+ )
486
+ except Exception as e:
487
+ """
488
+ rollback logic
489
+ """
490
+ global_object_square_logger.logger.error(e, exc_info=True)
491
+ output_content = get_api_output_in_standard_format(
492
+ message=messages["GENERIC_500"],
493
+ log=str(e),
494
+ )
495
+ return JSONResponse(
496
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
497
+ )
498
+
499
+
500
+ @global_object_square_logger.auto_logger()
501
+ def util_validate_email_verification_code_v0(access_token, verification_code):
502
+ try:
503
+ """
504
+ validation
505
+ """
506
+ # validate access token
507
+ try:
508
+ local_dict_access_token_payload = get_jwt_payload(
509
+ access_token, config_str_secret_key_for_access_token
510
+ )
511
+ except Exception as error:
512
+ output_content = get_api_output_in_standard_format(
513
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
514
+ )
515
+ raise HTTPException(
516
+ status_code=status.HTTP_400_BAD_REQUEST,
517
+ detail=output_content,
518
+ )
519
+ user_id = local_dict_access_token_payload["user_id"]
520
+
521
+ # validate if user has email in profile
522
+ user_profile_response = global_object_square_database_helper.get_rows_v0(
523
+ database_name=global_string_database_name,
524
+ schema_name=global_string_schema_name,
525
+ table_name=UserProfile.__tablename__,
526
+ filters=FiltersV0(
527
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
528
+ ),
529
+ apply_filters=True,
530
+ )
531
+ user_profile_data = user_profile_response["data"]["main"][0]
532
+ if not user_profile_data.get(UserProfile.user_profile_email.name):
533
+ output_content = get_api_output_in_standard_format(
534
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
535
+ log="email is required to send verification email.",
536
+ )
537
+ raise HTTPException(
538
+ status_code=status.HTTP_400_BAD_REQUEST,
539
+ detail=output_content,
540
+ )
541
+ # check if email is already verified
542
+ if user_profile_data.get(UserProfile.user_profile_email_verified.name):
543
+ output_content = get_api_output_in_standard_format(
544
+ message=messages["EMAIL_ALREADY_VERIFIED"]
545
+ )
546
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
547
+ # check for verification code in UserVerificationCode table
548
+ verification_code_response = global_object_square_database_helper.get_rows_v0(
549
+ database_name=global_string_database_name,
550
+ schema_name=global_string_schema_name,
551
+ table_name=UserVerificationCode.__tablename__,
552
+ filters=FiltersV0(
553
+ root={
554
+ UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
555
+ UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
556
+ eq=VerificationCodeTypeEnum.EMAIL_VERIFICATION.value
557
+ ),
558
+ UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
559
+ is_null=True
560
+ ),
561
+ UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
562
+ gte=datetime.now(timezone.utc).strftime(
563
+ "%Y-%m-%d %H:%M:%S.%f+00"
564
+ )
565
+ ),
566
+ }
567
+ ),
568
+ order_by=[
569
+ "-" + UserVerificationCode.user_verification_code_created_at.name
570
+ ],
571
+ limit=1,
572
+ apply_filters=True,
573
+ )
574
+ if len(verification_code_response["data"]["main"]) != 1:
575
+ output_content = get_api_output_in_standard_format(
576
+ message=messages["INCORRECT_VERIFICATION_CODE"]
577
+ )
578
+ raise HTTPException(
579
+ status_code=status.HTTP_400_BAD_REQUEST,
580
+ detail=output_content,
581
+ )
582
+ """
583
+ main process
584
+ """
585
+
586
+ # check if the latest verification code matches the provided code
587
+ latest_verification_code_data = verification_code_response["data"]["main"][0]
588
+ latest_verification_code_hash = latest_verification_code_data[
589
+ UserVerificationCode.user_verification_code_hash.name
590
+ ]
591
+ if not bcrypt.checkpw(
592
+ str(verification_code).encode("utf-8"),
593
+ latest_verification_code_hash.encode("utf-8"),
594
+ ):
595
+ output_content = get_api_output_in_standard_format(
596
+ message=messages["INCORRECT_VERIFICATION_CODE"]
597
+ )
598
+ raise HTTPException(
599
+ status_code=status.HTTP_400_BAD_REQUEST,
600
+ detail=output_content,
601
+ )
602
+ # update user profile to mark email as verified
603
+ email_verified_time = datetime.now(timezone.utc)
604
+ global_object_square_database_helper.edit_rows_v0(
605
+ database_name=global_string_database_name,
606
+ schema_name=global_string_schema_name,
607
+ table_name=UserProfile.__tablename__,
608
+ filters=FiltersV0(
609
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
610
+ ),
611
+ data={
612
+ UserProfile.user_profile_email_verified.name: email_verified_time.strftime(
613
+ "%Y-%m-%d %H:%M:%S.%f+00"
614
+ ),
615
+ },
616
+ apply_filters=True,
617
+ )
618
+ """
619
+ return value
620
+ """
621
+ output_content = get_api_output_in_standard_format(
622
+ data={
623
+ UserProfile.user_profile_email_verified.name: email_verified_time.isoformat(),
624
+ },
625
+ message=messages["GENERIC_ACTION_SUCCESSFUL"],
626
+ )
627
+ return JSONResponse(
628
+ status_code=status.HTTP_200_OK,
629
+ content=output_content,
630
+ )
631
+ except HTTPException as http_exception:
632
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
633
+ return JSONResponse(
634
+ status_code=http_exception.status_code, content=http_exception.detail
635
+ )
636
+ except Exception as e:
637
+ """
638
+ rollback logic
639
+ """
640
+ global_object_square_logger.logger.error(e, exc_info=True)
641
+ output_content = get_api_output_in_standard_format(
642
+ message=messages["GENERIC_500"],
643
+ log=str(e),
644
+ )
645
+ return JSONResponse(
646
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
647
+ )
@@ -0,0 +1,55 @@
1
+ import bcrypt
2
+ from fastapi import status, HTTPException
3
+ from fastapi.responses import JSONResponse
4
+ from square_commons import get_api_output_in_standard_format
5
+
6
+ from square_authentication.configuration import global_object_square_logger
7
+ from square_authentication.messages import messages
8
+
9
+
10
+ @global_object_square_logger.auto_logger()
11
+ def util_get_text_hash_v0(plain_text):
12
+ try:
13
+ """
14
+ validation
15
+ """
16
+ # pass
17
+ """
18
+ main process
19
+ """
20
+ local_str_hashed_text = bcrypt.hashpw(
21
+ plain_text.encode("utf-8"), bcrypt.gensalt()
22
+ ).decode("utf-8")
23
+ """
24
+ return value
25
+ """
26
+ output_content = get_api_output_in_standard_format(
27
+ message=messages["GENERIC_READ_SUCCESSFUL"],
28
+ data={"main": local_str_hashed_text},
29
+ )
30
+ return JSONResponse(
31
+ status_code=status.HTTP_200_OK,
32
+ content=output_content,
33
+ )
34
+ except HTTPException as http_exception:
35
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
36
+ """
37
+ rollback logic
38
+ """
39
+ # pass
40
+ return JSONResponse(
41
+ status_code=http_exception.status_code, content=http_exception.detail
42
+ )
43
+ except Exception as e:
44
+ global_object_square_logger.logger.error(e, exc_info=True)
45
+ """
46
+ rollback logic
47
+ """
48
+ # pass
49
+ output_content = get_api_output_in_standard_format(
50
+ message=messages["GENERIC_500"],
51
+ log=str(e),
52
+ )
53
+ return JSONResponse(
54
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
55
+ )