Merge branch 'master' into celery-send-sms-code

Conflicts:
	tests/app/celery/test_tasks.py
This commit is contained in:
Rebecca Law
2016-02-17 15:43:57 +00:00
7 changed files with 74 additions and 11 deletions

View File

@@ -8,12 +8,14 @@ from werkzeug.local import LocalProxy
from utils import logging from utils import logging
from app.celery.celery import NotifyCelery from app.celery.celery import NotifyCelery
from app.clients.sms.twilio import TwilioClient from app.clients.sms.twilio import TwilioClient
from app.clients.sms.firetext import FiretextClient
from app.encryption import Encryption from app.encryption import Encryption
db = SQLAlchemy() db = SQLAlchemy()
ma = Marshmallow() ma = Marshmallow()
notify_celery = NotifyCelery() notify_celery = NotifyCelery()
twilio_client = TwilioClient() twilio_client = TwilioClient()
firetext_client = FiretextClient()
encryption = Encryption() encryption = Encryption()
api_user = LocalProxy(lambda: _request_ctx_stack.top.api_user) api_user = LocalProxy(lambda: _request_ctx_stack.top.api_user)
@@ -30,6 +32,7 @@ def create_app():
init_app(application) init_app(application)
logging.init_app(application) logging.init_app(application)
twilio_client.init_app(application) twilio_client.init_app(application)
firetext_client.init_app(application)
notify_celery.init_app(application) notify_celery.init_app(application)
encryption.init_app(application) encryption.init_app(application)

View File

@@ -1,5 +1,5 @@
from app import notify_celery, twilio_client, encryption from app import notify_celery, encryption, firetext_client
from app.clients.sms.twilio import TwilioClientException from app.clients.sms.firetext import FiretextClientException
from app.dao.templates_dao import get_model_templates from app.dao.templates_dao import get_model_templates
from app.dao.notifications_dao import save_notification from app.dao.notifications_dao import save_notification
from app.models import Notification from app.models import Notification
@@ -23,8 +23,8 @@ def send_sms(service_id, notification_id, encrypted_notification):
save_notification(notification_db_object) save_notification(notification_db_object)
try: try:
twilio_client.send_sms(notification['to'], template.content) firetext_client.send_sms(notification['to'], template.content)
except TwilioClientException as e: except FiretextClientException as e:
current_app.logger.debug(e) current_app.logger.debug(e)
save_notification(notification_db_object, {"status": "failed"}) save_notification(notification_db_object, {"status": "failed"})

View File

@@ -0,0 +1,52 @@
import logging
from app.clients.sms import (
SmsClient,
SmsClientException
)
from requests import request, RequestException, HTTPError
logger = logging.getLogger(__name__)
class FiretextClientException(SmsClientException):
pass
class FiretextClient(SmsClient):
'''
FireText sms client.
'''
def init_app(self, config, *args, **kwargs):
super(SmsClient, self).__init__(*args, **kwargs)
self.api_key = config.config.get('FIRETEXT_API_KEY')
self.from_number = config.config.get('FIRETEXT_NUMBER')
def send_sms(self, to, content):
data = {
"apiKey": self.api_key,
"from": self.from_number,
"to": to.replace('+', ''),
"message": content
}
try:
response = request(
"POST",
"https://www.firetext.co.uk/api/sendsms",
data=data
)
response.raise_for_status()
except RequestException as e:
api_error = HTTPError.create(e)
print(
"API {} request on {} failed with {} '{}'".format(
"POST",
"https://www.firetext.co.uk/api/sendsms",
api_error.status_code,
api_error.message
)
)
raise api_error
return response

View File

@@ -41,6 +41,8 @@ class Config(object):
TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID') TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN') TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
TWILIO_NUMBER = os.getenv('TWILIO_NUMBER') TWILIO_NUMBER = os.getenv('TWILIO_NUMBER')
FIRETEXT_NUMBER = os.getenv('FIRETEXT_NUMBER')
FIRETEXT_API_KEY = os.getenv("FIRETEXT_API_KEY")
class Development(Config): class Development(Config):

View File

@@ -12,4 +12,6 @@ export SQLALCHEMY_DATABASE_URI='postgresql://localhost/test_notification_api'
export VERIFY_CODE_FROM_EMAIL_ADDRESS='no-reply@notify.works' export VERIFY_CODE_FROM_EMAIL_ADDRESS='no-reply@notify.works'
export TWILIO_ACCOUNT_SID="test" export TWILIO_ACCOUNT_SID="test"
export TWILIO_AUTH_TOKEN="test" export TWILIO_AUTH_TOKEN="test"
export TWILIO_NUMBER="test" export TWILIO_NUMBER="test"
export FIRETEXT_API_KEY="Firetext"
export FIRETEXT_NUMBER="Firetext"

View File

@@ -13,6 +13,7 @@ itsdangerous==0.24
Flask-Bcrypt==0.6.2 Flask-Bcrypt==0.6.2
credstash==1.8.0 credstash==1.8.0
boto3==1.2.3 boto3==1.2.3
boto==2.39.0
celery==3.1.20 celery==3.1.20
twilio==4.6.0 twilio==4.6.0

View File

@@ -3,6 +3,9 @@ import pytest
from app.celery.tasks import (send_sms, send_sms_code) from app.celery.tasks import (send_sms, send_sms_code)
from app import twilio_client, encryption from app import twilio_client, encryption
from app.clients.sms.twilio import TwilioClientException from app.clients.sms.twilio import TwilioClientException
from app.celery.tasks import send_sms
from app import firetext_client
from app.clients.sms.firetext import FiretextClientException
from app.dao import notifications_dao from app.dao import notifications_dao
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
@@ -14,7 +17,7 @@ def test_should_send_template_to_correct_sms_provider_and_persist(sample_templat
"to": "+441234123123" "to": "+441234123123"
} }
mocker.patch('app.encryption.decrypt', return_value=notification) mocker.patch('app.encryption.decrypt', return_value=notification)
mocker.patch('app.twilio_client.send_sms') mocker.patch('app.firetext_client.send_sms')
notification_id = uuid.uuid4() notification_id = uuid.uuid4()
@@ -23,7 +26,7 @@ def test_should_send_template_to_correct_sms_provider_and_persist(sample_templat
notification_id, notification_id,
"encrypted-in-reality") "encrypted-in-reality")
twilio_client.send_sms.assert_called_once_with("+441234123123", sample_template.content) firetext_client.send_sms.assert_called_once_with("+441234123123", sample_template.content)
persisted_notification = notifications_dao.get_notification(sample_template.service_id, notification_id) persisted_notification = notifications_dao.get_notification(sample_template.service_id, notification_id)
assert persisted_notification.id == notification_id assert persisted_notification.id == notification_id
assert persisted_notification.to == '+441234123123' assert persisted_notification.to == '+441234123123'
@@ -37,7 +40,7 @@ def test_should_persist_notification_as_failed_if_sms_client_fails(sample_templa
"to": "+441234123123" "to": "+441234123123"
} }
mocker.patch('app.encryption.decrypt', return_value=notification) mocker.patch('app.encryption.decrypt', return_value=notification)
mocker.patch('app.twilio_client.send_sms', side_effect=TwilioClientException()) mocker.patch('app.firetext_client.send_sms', side_effect=FiretextClientException())
notification_id = uuid.uuid4() notification_id = uuid.uuid4()
@@ -46,7 +49,7 @@ def test_should_persist_notification_as_failed_if_sms_client_fails(sample_templa
notification_id, notification_id,
"encrypted-in-reality") "encrypted-in-reality")
twilio_client.send_sms.assert_called_once_with("+441234123123", sample_template.content) firetext_client.send_sms.assert_called_once_with("+441234123123", sample_template.content)
persisted_notification = notifications_dao.get_notification(sample_template.service_id, notification_id) persisted_notification = notifications_dao.get_notification(sample_template.service_id, notification_id)
assert persisted_notification.id == notification_id assert persisted_notification.id == notification_id
assert persisted_notification.to == '+441234123123' assert persisted_notification.to == '+441234123123'
@@ -60,7 +63,7 @@ def test_should_not_send_sms_if_db_peristance_failed(sample_template, mocker):
"to": "+441234123123" "to": "+441234123123"
} }
mocker.patch('app.encryption.decrypt', return_value=notification) mocker.patch('app.encryption.decrypt', return_value=notification)
mocker.patch('app.twilio_client.send_sms', side_effect=TwilioClientException()) mocker.patch('app.firetext_client.send_sms', side_effect=FiretextClientException())
mocker.patch('app.db.session.add', side_effect=SQLAlchemyError()) mocker.patch('app.db.session.add', side_effect=SQLAlchemyError())
notification_id = uuid.uuid4() notification_id = uuid.uuid4()
@@ -70,7 +73,7 @@ def test_should_not_send_sms_if_db_peristance_failed(sample_template, mocker):
notification_id, notification_id,
"encrypted-in-reality") "encrypted-in-reality")
twilio_client.send_sms.assert_not_called() firetext_client.send_sms.assert_not_called()
with pytest.raises(NoResultFound) as e: with pytest.raises(NoResultFound) as e:
notifications_dao.get_notification(sample_template.service_id, notification_id) notifications_dao.get_notification(sample_template.service_id, notification_id)
assert 'No row was found for one' in str(e.value) assert 'No row was found for one' in str(e.value)