(20241209) Many changes to the SMS section.

This commit is contained in:
2024-12-09 19:38:47 +05:30
parent 725d68f195
commit d10b156c0b
14 changed files with 1406 additions and 250 deletions
@@ -43,6 +43,9 @@ sys.path.append("..")
# To make API Calls:
import httpx
# Data models:
from utils_v2.sms.models.data.sms_message import SentSMSMessageModel
# For debugging:
from icecream import IceCreamDebugger
@@ -172,12 +175,12 @@ class AsyncNimbusSMS:
async def send_sms(
self,
template_id,
recipient_number,
message,
message_type = MESSAGE_TYPE_REGULAR,
flash = MESSAGE_TYPE_NOT_FLASH
):
template_id: str,
recipient_number: str,
message: str,
message_type: int = MESSAGE_TYPE_REGULAR,
flash: int = MESSAGE_TYPE_NOT_FLASH
) -> SentSMSMessageModel:
"""
Sends one SMS through Nimbus IT's system. The text of the message must match the template that had been
@@ -195,17 +198,14 @@ class AsyncNimbusSMS:
"""
# Construct the basic structure of the response of this method:
summary = {
"success": False,
"info": None,
"sender": self.__sender_id,
"recipient": recipient_number,
"message": message,
"length": len(message),
"template_id": template_id,
"raw": None,
"isFlash": True if flash else False
}
summary = SentSMSMessageModel(
sender = {"senderId": self.__sender_id},
recipient = {"recipientNo": recipient_number},
text = message,
length = len(message),
isFlash = True if flash else False,
metadata = {"templateId": template_id}
)
try:
@@ -231,18 +231,13 @@ class AsyncNimbusSMS:
# For a successful API call:
if response.status_code == 200:
response_json = response.json()
summary["success"] = True if response_json.get("STATUS", "ERROR").lower() in ["ok"] else False
summary["info"] = response_json.get("RESPONSE", {}).get("INFO")
summary["raw"] = {
"http_code": response.status_code,
"response": response_json,
}
summary.rawResponse = response_json
summary.success = True if response_json.get("STATUS", "ERROR").lower() in ["ok"] else False
if summary.success: summary.messageId = response_json.get("RESPONSE", {}).get("UID")
else: summary.brief = response_json.get("RESPONSE", {}).get("INFO")
# For any other code that indicates some form of failure:
else: summary["raw"] = {
"http_code": response.status_code,
"response": response.content.decode()
}
else: summary.rawResponse = response.content.decode()
except Exception as exception:
self.__printer(exception)
@@ -263,21 +258,21 @@ if __name__ == "__main__":
async def main():
sender = AsyncNimbusSMS(
entity_id = "<your_entity_id>",
sender_id = "<your_sender_id>",
user_id = "<your_nimbus_user_id>",
api_key = "<your_nimbus_api_key>"
client = AsyncNimbusSMS(
entity_id = "1701172465456946915",
sender_id = "TCAOFF",
user_id = "210844",
api_key = "92UnZwiiY7zps"
)
response = await sender.send_sms(
template_id = "<your_sms_template_id>",
recipient_number = "<the_number_you_want_to_send_the_message_to>",
message = "<your_sms_message>"
response = await client.send_sms(
template_id = "1707172474709021546",
recipient_number = "987039115511",
message = "OTP for The CA Office registration request is 583920. Please enter this to verify your identity and proceed with the registration request. - TCAOFF"
)
print("SMS API RESPONSE:", response)
my_balance = await sender.get_balance()
my_balance = await client.get_balance()
print("REMAINING BALANCE:", my_balance)
@@ -42,6 +42,9 @@ sys.path.append("..")
# To make API Calls:
import httpx
# Data models:
from utils_v2.sms.models.data.sms_message import SentSMSMessageModel
# For debugging:
from icecream import IceCreamDebugger
@@ -149,18 +152,19 @@ class AsyncSavvyBulkSMS:
"""
# Construct the basic structure of the response of this method:
summary = {
"success": False,
"info": None,
"sender": {
summary = SentSMSMessageModel(
sender = {
"partnerId": self.__partner_id,
"shortCode": self.__short_code
},
"recipient": recipient_number,
"message": message,
"length": len(message),
"raw": None,
}
recipient = {
"recipientNo": recipient_number
},
text = message,
length = len(message),
isFlash = False,
metadata = None
)
try:
@@ -179,18 +183,15 @@ class AsyncSavvyBulkSMS:
# For a successful API call:
if api_response.status_code in [200]:
api_json = api_response.json()
first_desc = api_json.get("responses", [{}])[0].get("response-description", "N/A").lower().strip()
summary["success"] = True if first_desc == "success" else False
summary["raw"] = {
"http_code": api_response.status_code,
"response": api_json,
}
summary.rawResponse = api_json
first_response = api_json.get("responses", [{}])[0]
first_desc = first_response.get("response-description", "N/A").lower().strip()
summary.success = True if first_desc == "success" else False
if summary.success: summary.messageId = first_response.get("messageid")
else: summary.brief = first_response.get("response-description")
# For any other code that indicates some form of failure:
else: summary["raw"] = {
"http_code": api_response.status_code,
"response": api_response.content.decode()
}
else: summary.rawResponse = api_response.content.decode()
# If something goes wrong along the way:
except Exception as exception:
@@ -214,14 +215,14 @@ if __name__ == "__main__":
async def main():
sender = AsyncSavvyBulkSMS(
api_key = "<your_api_key>",
partner_id = "<your_partner_id>",
short_code = "<your_short_code>"
api_key = "19250bdd74050f7cec980c71e75f851a",
partner_id = "7462",
short_code = "HTL TV-NET"
)
response = await sender.send_sms(
recipient_number = "<target_recipient>",
message = "<message_for_recipient>"
recipient_number = "254748877373 123",
message = "Test 123"
)
print("SMS API RESPONSE:", response)
+157
View File
@@ -0,0 +1,157 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Monday, 9th Dec., 2024.
OBJECTIVE:
To define how messages will be stored in the database.
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 behaviour_models:
from pydantic import BaseModel, Field, field_validator, PastDatetime, AwareDatetime
from typing import Optional, Literal, Union, Any
# My utils:
from utils_v2.string import regex
from utils_v2.date_time import date_time
# To work with MongoDB:
from bson.objectid import ObjectId
# To work with date and time:
import datetime
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
class SentSMSMessageModel(BaseModel):
ts: AwareDatetime = Field(
description = "the time (utc) at which this message was sent by the sender",
frozen = True,
default_factory = lambda: date_time.get_current_utc_date_time(as_string = False)
)
sender: dict = Field(
description = "the sender of this message",
frozen = True
)
recipient: dict = Field(
description = "the recipient of this message",
frozen = True
)
text: str = Field(
description = "the actual text that was sent",
frozen = True
)
length: int = Field(
description = "the no. of chars in this message",
frozen = True
)
isFlash: bool = Field(
description = "to know whether this message is a flash message or a regular message",
frozen = True
)
success: bool = Field(
description = "to know whether this message was sent successfully or not",
default = False
)
brief: str | None = Field(
description = "a brief message about what happened; useful when something goes wrong",
default = None
)
metadata: dict | None = Field(
description = "any extra data about this message",
frozen = True
)
rawResponse: Any | None = Field(
description = "the raw response from the third-party client",
default = None
)
messageId: int | str | None = Field(
description = "how the client recognizes this message",
frozen = False,
default = None
)
# ┏┓ ┏•
# ┃ ┏┓┏┓╋┓┏┓
# ┗┛┗┛┛┗┛┗┗┫
# ┛
class Config:
extra = "allow"
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
pass