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:
Innokentii Konstantinov 2023-06-09 13:21:38 +08:00 committed by GitHub
parent a0da31f745
commit 0b92210e16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 5 deletions

View file

@ -60,6 +60,7 @@ class PhoneCallRecord(models.Model):
class ProviderPhoneCall(models.Model):
"""
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).
It is needed to link phone call and alert group without exposing internals of concrete phone provider to PhoneBackend.

View file

@ -67,8 +67,9 @@ class SMSRecord(models.Model):
class ProviderSMS(models.Model):
"""
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:

View file

@ -15,9 +15,16 @@ class ProviderFlags:
"""
ProviderFlags is set of feature flags enabled for concrete provider.
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_call: bool
verification_call: bool
@ -29,7 +36,10 @@ class PhoneProvider(ABC):
PhoneProvider is an interface to all phone providers.
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:
SimplePhoneProvider as example of tiny, but working provider.

View file

@ -1,9 +1,13 @@
import logging
from random import randint
from django.core.cache import cache
from .exceptions import FailedToSendSMS, FailedToStartVerification
from .phone_provider import PhoneProvider, ProviderFlags
logger = logging.getLogger(__name__)
class SimplePhoneProvider(PhoneProvider):
"""
@ -15,12 +19,22 @@ class SimplePhoneProvider(PhoneProvider):
self.send_sms(number, message)
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):
code = str(randint(100000, 999999))
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):
has = cache.get(self._cache_key(number))
@ -32,6 +46,11 @@ class SimplePhoneProvider(PhoneProvider):
def _cache_key(self, 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
def flags(self) -> ProviderFlags:
return ProviderFlags(