61 lines
2.3 KiB
Python
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
|
|
|