Files
crmApi/utils/services/sms.py
T
2026-10-09 10:32:27 +03:30

61 lines
2.3 KiB
Python

from abc import ABC, abstractmethod
import requests
import logging
from django.conf import settings
logger = logging.getLogger(__name__)
class SmsProviderABC(ABC):
@abstractmethod
def send_sms(self, mobile: str, message: str) -> bool | None:
pass
class DefaultSmsProvider(SmsProviderABC):
def send_sms(self, mobile: str, message: str) -> bool | None:
default_provider = DosefrNavadHashtSMS()
return default_provider.send_sms(mobile, message)
class DosefrNavadHashtSMS(SmsProviderABC):
def send_sms(self, mobile: str, message: str) -> bool | None:
payload = {
'USERNAME': 'vsms7937',
'PASSWORD': '335577775533',
'FROM': '30005367',
'TO': int(mobile),
'TEXT': f'{message}'
}
try:
r = requests.get('http://www.0098sms.com/sendsmslink.aspx', params=payload, timeout=10)
r.raise_for_status()
except (requests.Timeout, requests.ConnectionError):
# The provider may have dispatched the SMS before its reply was lost.
logger.warning('SMS provider reply unavailable; dispatch is unconfirmed')
return None
except requests.HTTPError as error:
if error.response is not None and error.response.status_code >= 500:
logger.warning('SMS provider server error; dispatch is unconfirmed')
return None
return False
except requests.RequestException:
return False
# Unknown bodies are NOT evidence of rejection. In particular, never
# discard a delivered OTP just because the response contract differs.
success_codes = getattr(settings, 'SMS_SUCCESS_CODES', ('0',))
failure_codes = getattr(settings, 'SMS_FAILURE_CODES', ('error',))
body = r.text.strip().lstrip('\ufeff').strip()
def codes(values):
if isinstance(values, str):
values = values.split(',')
return {str(value).strip() for value in values}
if body in codes(success_codes):
return True
if body in codes(failure_codes):
return False
# Do not log the reply, URL, credentials, mobile, or OTP.
logger.warning('SMS provider returned an unrecognized reply; dispatch is unconfirmed')
return None