Better simple phone provider (#2143)
# What this PR does ## Which issue(s) this PR fixes ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
This commit is contained in:
parent
a0da31f745
commit
0b92210e16
4 changed files with 36 additions and 5 deletions
|
|
@ -60,6 +60,7 @@ class PhoneCallRecord(models.Model):
|
||||||
class ProviderPhoneCall(models.Model):
|
class ProviderPhoneCall(models.Model):
|
||||||
"""
|
"""
|
||||||
ProviderPhoneCall is an interface between PhoneCallRecord and call data returned from PhoneProvider.
|
ProviderPhoneCall is an interface between PhoneCallRecord and call data returned from PhoneProvider.
|
||||||
|
Concrete provider phone call should be inherited from ProviderPhoneCall.
|
||||||
|
|
||||||
Some phone providers allows to track status of call or gather pressed digits (we use it to ack/resolve alert group).
|
Some phone providers allows to track status of call or gather pressed digits (we use it to ack/resolve alert group).
|
||||||
It is needed to link phone call and alert group without exposing internals of concrete phone provider to PhoneBackend.
|
It is needed to link phone call and alert group without exposing internals of concrete phone provider to PhoneBackend.
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,9 @@ class SMSRecord(models.Model):
|
||||||
class ProviderSMS(models.Model):
|
class ProviderSMS(models.Model):
|
||||||
"""
|
"""
|
||||||
ProviderSMS is an interface between SMSRecord and call data returned from PhoneProvider.
|
ProviderSMS is an interface between SMSRecord and call data returned from PhoneProvider.
|
||||||
|
Concrete provider sms be inherited from ProviderSMS.
|
||||||
|
|
||||||
The idea is same as for ProviderCall - to save provider specific data without exposing them to ProheBackend.
|
The idea is same as for ProviderCall - to save provider specific data without exposing them to PhoneBackend.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,16 @@ class ProviderFlags:
|
||||||
"""
|
"""
|
||||||
ProviderFlags is set of feature flags enabled for concrete provider.
|
ProviderFlags is set of feature flags enabled for concrete provider.
|
||||||
It is needed to show correct buttons in UI.
|
It is needed to show correct buttons in UI.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
configured: Indicates if provider LiveSettings are valid. If LiveSettings cannot be validated, return True.
|
||||||
|
test_sms: Indicates if provider allows to send test_sms
|
||||||
|
test_call: Indicates if provider allows to make test_call
|
||||||
|
verification_call: Indicates if provider allows to validate number via call
|
||||||
|
verification_sms: Indicates if provider allows to validate number via sms
|
||||||
"""
|
"""
|
||||||
|
|
||||||
configured: bool # indicates if provider live settings are present and valid
|
configured: bool
|
||||||
test_sms: bool
|
test_sms: bool
|
||||||
test_call: bool
|
test_call: bool
|
||||||
verification_call: bool
|
verification_call: bool
|
||||||
|
|
@ -29,7 +36,10 @@ class PhoneProvider(ABC):
|
||||||
PhoneProvider is an interface to all phone providers.
|
PhoneProvider is an interface to all phone providers.
|
||||||
It is needed to hide details of external phone providers from core code.
|
It is needed to hide details of external phone providers from core code.
|
||||||
|
|
||||||
New PhoneProviders should be added to settings.PHONE_PROVIDERS dict.
|
To implement custom phone provider:
|
||||||
|
1. Implement your ConcretePhoneProvider inherited from PhoneProvider.
|
||||||
|
2. Add needed env variables to django settings and to LiveSettings.
|
||||||
|
3. Add your PhoneProvider to settings.PHONE_PROVIDERS dict.
|
||||||
|
|
||||||
For reference, you can check:
|
For reference, you can check:
|
||||||
SimplePhoneProvider as example of tiny, but working provider.
|
SimplePhoneProvider as example of tiny, but working provider.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
|
import logging
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
from .exceptions import FailedToSendSMS, FailedToStartVerification
|
||||||
from .phone_provider import PhoneProvider, ProviderFlags
|
from .phone_provider import PhoneProvider, ProviderFlags
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SimplePhoneProvider(PhoneProvider):
|
class SimplePhoneProvider(PhoneProvider):
|
||||||
"""
|
"""
|
||||||
|
|
@ -15,12 +19,22 @@ class SimplePhoneProvider(PhoneProvider):
|
||||||
self.send_sms(number, message)
|
self.send_sms(number, message)
|
||||||
|
|
||||||
def send_sms(self, number, text):
|
def send_sms(self, number, text):
|
||||||
print(f'SimplePhoneProvider.send_sms: send message "{text}" to {number}')
|
try:
|
||||||
|
self._write_to_stdout(number, text)
|
||||||
|
except Exception as e:
|
||||||
|
# example of handling provider exceptions and converting them to exceptions from core OnCall code.
|
||||||
|
logger.error(f"SimplePhoneProvider.send_sms: failed {e}")
|
||||||
|
raise FailedToSendSMS
|
||||||
|
|
||||||
def send_verification_sms(self, number):
|
def send_verification_sms(self, number):
|
||||||
code = str(randint(100000, 999999))
|
code = str(randint(100000, 999999))
|
||||||
cache.set(self._cache_key(number), code, timeout=10 * 60)
|
cache.set(self._cache_key(number), code, timeout=10 * 60)
|
||||||
self.send_sms(number, f"Your verification code is {code}")
|
try:
|
||||||
|
self._write_to_stdout(number, f"Your verification code is {code}")
|
||||||
|
except Exception as e:
|
||||||
|
# Example of handling provider exceptions and converting them to exceptions from core OnCall code.
|
||||||
|
logger.error(f"SimplePhoneProvider.send_verification_sms: failed {e}")
|
||||||
|
raise FailedToStartVerification
|
||||||
|
|
||||||
def finish_verification(self, number, code):
|
def finish_verification(self, number, code):
|
||||||
has = cache.get(self._cache_key(number))
|
has = cache.get(self._cache_key(number))
|
||||||
|
|
@ -32,6 +46,11 @@ class SimplePhoneProvider(PhoneProvider):
|
||||||
def _cache_key(self, number):
|
def _cache_key(self, number):
|
||||||
return f"simple_provider_{number}"
|
return f"simple_provider_{number}"
|
||||||
|
|
||||||
|
def _write_to_stdout(self, number, text):
|
||||||
|
# print is just example of sending sms.
|
||||||
|
# In real-life provider it will be some external api call.
|
||||||
|
print(f'send message "{text}" to {number}')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def flags(self) -> ProviderFlags:
|
def flags(self) -> ProviderFlags:
|
||||||
return ProviderFlags(
|
return ProviderFlags(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue