""" AUTHOR: Khushal P Soonderji DATE: Tuesday, 10th Sept., 2024. OBJECTIVE: To provide a data structure for the JSON received in the API calls to generate and verify timed OTPs. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys sys.path.append(".") sys.path.append("..") # For making data models: from pydantic import BaseModel, Field, field_validator, Extra, EmailStr from typing import Optional, Any, Dict, List from typing_extensions import Annotated # My utils: from utils_v2.string import regex # To work with MongoDB: from bson.objectid import ObjectId # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # RegEx Patterns: REGEX_SESSION_TOKEN = r"^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$" # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** class TimedOTPRequestHeaders(BaseModel): sessionToken: str | None = Field( description = "the session token of the user who is requesting the service", pattern = REGEX_SESSION_TOKEN, frozen = True, default = None, alias = "X-Session-Token" ) # ┏┓ ┏• # ┃ ┏┓┏┓╋┓┏┓ # ┗┛┗┛┛┗┛┗┗┫ # ┛ class Config: extra = "allow" def model_dump(self, *args, **kwargs): return super().model_dump(*args, by_alias = True, **kwargs) # --------------------------------------------------------------------------------------------------------------------- class SendTimedOTPSMSFromSavvyBulkSMSKenyaRequestData(BaseModel): tokenKey: ObjectId | None = Field( description = ( "If you wish to use a specific account, you may send that account's token key, else the first SMS client " "account will be picked." ), frozen = True, default = None ) id: dict = Field( description = "Any identifier to associate the OTP with. Cannot be blank.", frozen = True ) attempts: int = Field( description = "How many times the user can try to verify the generated OTP.", frozen = True, gt = 0, lt = 11, default = 3 ) seconds: int | float = Field( description = "The no. of seconds until which the OTP will remain valid.", frozen = True, gt = 29.9, lt = 300.1, default = 3 ) recipientNo: str = Field( description = "The phone no. of the target recipient of the OTP.", frozen = True ) smsText: str = Field( description = "The templet of the message to send.", frozen = True, default = "Hello! Please use the following OTP ##OTP##" ) smsReplace: str = Field( description = "The substring in the 'smsText' template to replace with the actual OTP." ) tags: List[str] | None = Field( description = "A set of tags to associate with the message.", frozen = True, default = None ) # ┏┓ ┏• # ┃ ┏┓┏┓╋┓┏┓ # ┗┛┗┛┛┗┛┗┗┫ # ┛ class Config: extra = "forbid" arbitrary_types_allowed = True def get(self, key: str, default = None): return getattr(self, key, default) # ┓┏ ┓• ┓ • # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓ # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗ @field_validator("tokenKey", mode = "before") def parse_oid(cls, value): try: if value is not None: value = ObjectId(value) except: pass return value @field_validator("id", mode = "after") def validate_attempts(cls, value): if not value: raise ValueError("The 'id' field cannot be empty!") return value # --------------------------------------------------------------------------------------------------------------------- class VerifyTimedOTPRequestData(BaseModel): id: str | Dict | List otp: str isSignup: bool username: str password: str email: EmailStr phoneNo: str idClient: int | None = Field(default = None) clientName: str | None = Field(default = None) address: str | None = Field(default = None) city: str | None = Field(default = None) pincode: str | None = Field(default = None) country: str | None = Field(default = None) panCard: str | None = Field(default = None) gst: str | None = Field(default = None) entity: str | None = Field(default = None) startDate: str | None = Field(default = None) period: str | None = Field(default = None) amount: float | int | None = Field(default = None) class Config: extra = "forbid" def get(self, key: str, default = None): return getattr(self, key, default) # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass