mirror of
https://github.com/GSA/notifications-api.git
synced 2025-12-10 07:12:20 -05:00
Made SMS messages go through celery
- twilio client pulled in from delivery app - made method to perform task
This commit is contained in:
@@ -12,12 +12,14 @@ from config import configs
|
||||
from utils import logging
|
||||
from notify_client import NotifyAPIClient
|
||||
from app.celery.celery import NotifyCelery
|
||||
|
||||
from app.clients.sms.twilio import TwilioClient
|
||||
|
||||
db = SQLAlchemy()
|
||||
ma = Marshmallow()
|
||||
notify_alpha_client = NotifyAPIClient()
|
||||
celery = NotifyCelery()
|
||||
twilio_client = TwilioClient()
|
||||
|
||||
|
||||
api_user = LocalProxy(lambda: _request_ctx_stack.top.api_user)
|
||||
|
||||
@@ -32,7 +34,7 @@ def create_app(config_name, config_overrides=None):
|
||||
ma.init_app(application)
|
||||
init_app(application, config_overrides)
|
||||
logging.init_app(application)
|
||||
|
||||
twilio_client.init_app(application)
|
||||
celery.init_app(application)
|
||||
|
||||
from app.service.rest import service as service_blueprint
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
from app import celery
|
||||
from app.dao.services_dao import get_model_services
|
||||
from itsdangerous import URLSafeSerializer
|
||||
from app import celery, twilio_client, db
|
||||
from app.clients.sms.twilio import TwilioClientException
|
||||
from app.dao.templates_dao import get_model_templates
|
||||
from app.models import Notification
|
||||
from flask import current_app
|
||||
|
||||
|
||||
@celery.task(name="refresh-services")
|
||||
def refresh_services():
|
||||
print(get_model_services())
|
||||
for service in get_model_services():
|
||||
celery.control.add_consumer(str(service.id))
|
||||
@celery.task(name="send-sms", bind="True")
|
||||
def send_sms(service_id, notification_id, encrypted_notification, secret_key, salt):
|
||||
serializer = URLSafeSerializer(secret_key)
|
||||
|
||||
notification = serializer.loads(encrypted_notification, salt=salt)
|
||||
template = get_model_templates(notification['template'])
|
||||
|
||||
status = 'sent'
|
||||
|
||||
try:
|
||||
twilio_client.send_sms(notification, template.content)
|
||||
except TwilioClientException as e:
|
||||
current_app.logger.info(e)
|
||||
status = 'failed'
|
||||
|
||||
notification_db_object = Notification(
|
||||
id=notification_id,
|
||||
template_id=notification['template'],
|
||||
to=notification['to'],
|
||||
service_id=service_id,
|
||||
status=status
|
||||
)
|
||||
|
||||
db.session.add(notification_db_object)
|
||||
db.session.commit()
|
||||
|
||||
13
app/clients/__init__.py
Normal file
13
app/clients/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
class ClientException(Exception):
|
||||
'''
|
||||
Base Exceptions for sending notifications that fail
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class Client(object):
|
||||
'''
|
||||
Base client for sending notifications.
|
||||
'''
|
||||
pass
|
||||
17
app/clients/sms/__init__.py
Normal file
17
app/clients/sms/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from app.clients import (Client, ClientException)
|
||||
|
||||
|
||||
class SmsClientException(ClientException):
|
||||
'''
|
||||
Base Exception for SmsClients
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class SmsClient(Client):
|
||||
'''
|
||||
Base Sms client for sending smss.
|
||||
'''
|
||||
|
||||
def send_sms(self, *args, **kwargs):
|
||||
raise NotImplemented('TODO Need to implement.')
|
||||
48
app/clients/sms/twilio.py
Normal file
48
app/clients/sms/twilio.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import logging
|
||||
from app.clients.sms import (
|
||||
SmsClient, SmsClientException)
|
||||
from twilio.rest import TwilioRestClient
|
||||
from twilio import TwilioRestException
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TwilioClientException(SmsClientException):
|
||||
pass
|
||||
|
||||
|
||||
class TwilioClient(SmsClient):
|
||||
'''
|
||||
Twilio sms client.
|
||||
'''
|
||||
def init_app(self, config, *args, **kwargs):
|
||||
super(TwilioClient, self).__init__(*args, **kwargs)
|
||||
self.client = TwilioRestClient(
|
||||
config.config.get('TWILIO_ACCOUNT_SID'),
|
||||
config.config.get('TWILIO_AUTH_TOKEN'))
|
||||
self.from_number = config.config.get('TWILIO_NUMBER')
|
||||
print(config.config)
|
||||
|
||||
|
||||
def send_sms(self, notification, content):
|
||||
try:
|
||||
response = self.client.messages.create(
|
||||
body=content,
|
||||
to=notification['to'],
|
||||
from_=self.from_number
|
||||
)
|
||||
return response.sid
|
||||
except TwilioRestException as e:
|
||||
logger.exception(e)
|
||||
raise TwilioClientException(e)
|
||||
|
||||
def status(self, message_id):
|
||||
try:
|
||||
response = self.client.messages.get(message_id)
|
||||
if response.status in ('delivered', 'undelivered', 'failed'):
|
||||
return response.status
|
||||
return None
|
||||
except TwilioRestException as e:
|
||||
logger.exception(e)
|
||||
raise TwilioClientException(e)
|
||||
@@ -3,43 +3,50 @@ import uuid
|
||||
from flask import (
|
||||
Blueprint,
|
||||
jsonify,
|
||||
request
|
||||
)
|
||||
request,
|
||||
current_app)
|
||||
from itsdangerous import URLSafeSerializer
|
||||
|
||||
from app import api_user
|
||||
from app.aws_sqs import add_notification_to_queue
|
||||
from app.dao import (templates_dao)
|
||||
from app.schemas import (
|
||||
email_notification_schema, sms_template_notification_schema)
|
||||
from app import celery
|
||||
from app.celery.tasks import send_sms
|
||||
|
||||
|
||||
notifications = Blueprint('notifications', __name__)
|
||||
|
||||
|
||||
def create_notification_id():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
@notifications.route('/<notification_id>', methods=['GET'])
|
||||
def get_notifications(notification_id):
|
||||
# TODO return notification id details
|
||||
return jsonify({'id': notification_id}), 200
|
||||
|
||||
|
||||
@celery.task(name="make-sms", bind="True")
|
||||
def send_sms(self):
|
||||
print('Executing task id {0.id}, args: {0.args!r} kwargs: {0.kwargs!r}'.format(self.request))
|
||||
from time import sleep
|
||||
sleep(0.5)
|
||||
print('finished')
|
||||
|
||||
|
||||
@notifications.route('/sms', methods=['POST'])
|
||||
def create_sms_notification():
|
||||
serializer = URLSafeSerializer(current_app.config.get('SECRET_KEY'))
|
||||
|
||||
resp_json = request.get_json()
|
||||
|
||||
notification, errors = sms_template_notification_schema.load(resp_json)
|
||||
if errors:
|
||||
return jsonify(result="error", message=errors), 400
|
||||
|
||||
send_sms.delay()
|
||||
notification_id = add_notification_to_queue(api_user['client'], notification['template'], 'sms', notification)
|
||||
notification_id = create_notification_id()
|
||||
encrypted_notification = serializer.dumps(notification, current_app.config.get('DANGEROUS_SALT'))
|
||||
|
||||
send_sms.apply_async((
|
||||
api_user['client'],
|
||||
notification_id,
|
||||
encrypted_notification,
|
||||
current_app.config.get('SECRET_KEY'),
|
||||
current_app.config.get('DANGEROUS_SALT')))
|
||||
return jsonify({'notification_id': notification_id}), 201
|
||||
|
||||
|
||||
|
||||
17
config.py
17
config.py
@@ -22,7 +22,7 @@ class Config(object):
|
||||
# Notification Queue names are a combination of a prefx plus a name
|
||||
NOTIFICATION_QUEUE_PREFIX = 'notification'
|
||||
|
||||
BROKER_URL = 'amqp://guest:guest@localhost:5672//'
|
||||
BROKER_URL = 'sqs://'
|
||||
BROKER_TRANSPORT_OPTIONS = {
|
||||
'region': 'eu-west-1',
|
||||
'polling_interval': 10, # 1 second
|
||||
@@ -33,13 +33,16 @@ class Config(object):
|
||||
CELERY_TIMEZONE = 'Europe/London'
|
||||
CELERY_ACCEPT_CONTENT = ['json']
|
||||
CELERY_TASK_SERIALIZER = 'json'
|
||||
CELERYBEAT_SCHEDULE = {
|
||||
'refresh-queues': {
|
||||
'task': 'refresh-services',
|
||||
'schedule': timedelta(seconds=5)
|
||||
}
|
||||
}
|
||||
# CELERYBEAT_SCHEDULE = {
|
||||
# 'refresh-queues': {
|
||||
# 'task': 'refresh-services',
|
||||
# 'schedule': timedelta(seconds=5)
|
||||
# }
|
||||
# }
|
||||
CELERY_IMPORTS = ('app.celery.tasks',)
|
||||
TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
|
||||
TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
|
||||
TWILIO_NUMBER = os.getenv('TWILIO_NUMBER')
|
||||
|
||||
|
||||
class Development(Config):
|
||||
|
||||
@@ -14,7 +14,8 @@ Flask-Bcrypt==0.6.2
|
||||
credstash==1.8.0
|
||||
boto3==1.2.3
|
||||
celery==3.1.20
|
||||
redis==2.10.5
|
||||
twilio==4.6.0
|
||||
|
||||
|
||||
git+https://github.com/alphagov/notifications-python-client.git@0.2.6#egg=notifications-python-client==0.2.6
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
from app import celery, create_app
|
||||
from app.celery.tasks import refresh_services
|
||||
|
||||
application = create_app(os.getenv('NOTIFY_API_ENVIRONMENT') or 'development')
|
||||
application.app_context().push()
|
||||
|
||||
Reference in New Issue
Block a user