mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-11 09:27:56 -04:00
Register a before_request event for all blueprints, that defines the authentication requirement.
There are three authentication methods: - requires_no_auth - public endpoint that does not require an Authorisation header - requires_auth - public endpoints that need an API key in the Authorisation header - requires_admin_auth - private endpoint that requires an Authorisation header which contains the API key for the defined as the client admin user
This commit is contained in:
@@ -2,7 +2,7 @@ import os
|
||||
import uuid
|
||||
|
||||
from flask import Flask, _request_ctx_stack
|
||||
from flask import request, url_for, g, jsonify
|
||||
from flask import request, g, jsonify
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from flask_marshmallow import Marshmallow
|
||||
from monotonic import monotonic
|
||||
@@ -20,7 +20,6 @@ from app.clients.sms.mmg import MMGClient
|
||||
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
||||
from app.encryption import Encryption
|
||||
|
||||
|
||||
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
|
||||
DATE_FORMAT = "%Y-%m-%d"
|
||||
|
||||
@@ -77,10 +76,10 @@ def create_app(app_name=None):
|
||||
|
||||
def register_blueprint(application):
|
||||
from app.service.rest import service_blueprint
|
||||
from app.user.rest import user as user_blueprint
|
||||
from app.template.rest import template as template_blueprint
|
||||
from app.user.rest import user_blueprint
|
||||
from app.template.rest import template_blueprint
|
||||
from app.status.healthcheck import status as status_blueprint
|
||||
from app.job.rest import job as job_blueprint
|
||||
from app.job.rest import job_blueprint
|
||||
from app.notifications.rest import notifications as notifications_blueprint
|
||||
from app.invite.rest import invite as invite_blueprint
|
||||
from app.accept_invite.rest import accept_invite
|
||||
@@ -90,49 +89,100 @@ def register_blueprint(application):
|
||||
from app.spec.rest import spec as spec_blueprint
|
||||
from app.organisation.rest import organisation_blueprint
|
||||
from app.delivery.rest import delivery_blueprint
|
||||
from app.notifications.receive_notifications import receive_notifications_blueprint
|
||||
from app.notifications.notifications_ses_callback import ses_callback_blueprint
|
||||
from app.notifications.notifications_sms_callback import sms_callback_blueprint
|
||||
from app.status.healthcheck import status
|
||||
from app.authentication.auth import requires_admin_auth, requires_auth, requires_no_auth
|
||||
|
||||
service_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(service_blueprint, url_prefix='/service')
|
||||
|
||||
user_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(user_blueprint, url_prefix='/user')
|
||||
|
||||
template_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(template_blueprint)
|
||||
|
||||
status_blueprint.before_request(requires_no_auth)
|
||||
application.register_blueprint(status_blueprint)
|
||||
|
||||
notifications_blueprint.before_request(requires_auth)
|
||||
receive_notifications_blueprint.before_request(requires_no_auth)
|
||||
|
||||
ses_callback_blueprint.before_request(requires_no_auth)
|
||||
application.register_blueprint(ses_callback_blueprint)
|
||||
|
||||
sms_callback_blueprint.before_request(requires_no_auth)
|
||||
application.register_blueprint(sms_callback_blueprint)
|
||||
|
||||
receive_notifications_blueprint.before_request(requires_no_auth)
|
||||
application.register_blueprint(receive_notifications_blueprint)
|
||||
|
||||
notifications_blueprint.before_request(requires_auth)
|
||||
application.register_blueprint(notifications_blueprint)
|
||||
|
||||
job_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(job_blueprint)
|
||||
|
||||
invite_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(invite_blueprint)
|
||||
|
||||
delivery_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(delivery_blueprint)
|
||||
|
||||
accept_invite.before_request(requires_admin_auth)
|
||||
application.register_blueprint(accept_invite, url_prefix='/invite')
|
||||
|
||||
template_statistics_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(template_statistics_blueprint)
|
||||
|
||||
events_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(events_blueprint)
|
||||
|
||||
provider_details_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(provider_details_blueprint, url_prefix='/provider-details')
|
||||
|
||||
spec_blueprint.before_request(requires_no_auth)
|
||||
application.register_blueprint(spec_blueprint, url_prefix='/spec')
|
||||
|
||||
organisation_blueprint.before_request(requires_admin_auth)
|
||||
application.register_blueprint(organisation_blueprint, url_prefix='/organisation')
|
||||
|
||||
status.before_request(requires_no_auth)
|
||||
application.register_blueprint(status)
|
||||
|
||||
|
||||
def register_v2_blueprints(application):
|
||||
from app.v2.notifications.post_notifications import notification_blueprint as post_notifications
|
||||
from app.v2.notifications.get_notifications import notification_blueprint as get_notifications
|
||||
from app.v2.notifications.post_notifications import v2_notification_blueprint as post_notifications
|
||||
from app.v2.notifications.get_notifications import v2_notification_blueprint as get_notifications
|
||||
from app.authentication.auth import requires_auth
|
||||
|
||||
post_notifications.before_request(requires_auth)
|
||||
application.register_blueprint(post_notifications)
|
||||
|
||||
get_notifications.before_request(requires_auth)
|
||||
application.register_blueprint(get_notifications)
|
||||
|
||||
|
||||
def init_app(app):
|
||||
@app.before_request
|
||||
def required_authentication():
|
||||
no_auth_req = [
|
||||
url_for('status.show_status'),
|
||||
url_for('notifications.process_ses_response'),
|
||||
url_for('notifications.process_firetext_response'),
|
||||
url_for('notifications.process_mmg_response'),
|
||||
url_for('notifications.receive_mmg_sms'),
|
||||
url_for('status.show_delivery_status'),
|
||||
url_for('spec.get_spec')
|
||||
]
|
||||
|
||||
if request.path not in no_auth_req:
|
||||
from app.authentication import auth
|
||||
error = auth.requires_auth()
|
||||
if error:
|
||||
return error
|
||||
# @app.before_request
|
||||
# def required_authentication():
|
||||
# no_auth_req = [
|
||||
# url_for('status.show_status'),
|
||||
# url_for('notifications.process_ses_response'),
|
||||
# url_for('notifications.process_firetext_response'),
|
||||
# url_for('notifications.process_mmg_response'),
|
||||
# url_for('notifications.receive_mmg_sms'),
|
||||
# url_for('status.show_delivery_status'),
|
||||
# url_for('spec.get_spec')
|
||||
# ]
|
||||
#
|
||||
# if request.path not in no_auth_req:
|
||||
# from app.authentication import auth
|
||||
# error = auth.requires_auth()
|
||||
# if error:
|
||||
# return error
|
||||
|
||||
@app.before_request
|
||||
def record_user_agent():
|
||||
|
||||
@@ -39,14 +39,13 @@ def get_auth_token(req):
|
||||
return auth_header[7:]
|
||||
|
||||
|
||||
def requires_no_auth():
|
||||
pass
|
||||
|
||||
|
||||
def requires_admin_auth():
|
||||
auth_token = get_auth_token(request)
|
||||
try:
|
||||
client = get_token_issuer(auth_token)
|
||||
except TokenDecodeError as e:
|
||||
raise AuthError(e.message, 403)
|
||||
except TokenIssuerError:
|
||||
raise AuthError("Invalid token: iss not provided", 403)
|
||||
client = __get_token_issuer(auth_token)
|
||||
|
||||
if client == current_app.config.get('ADMIN_CLIENT_USER_NAME'):
|
||||
g.service_id = current_app.config.get('ADMIN_CLIENT_USER_NAME')
|
||||
@@ -57,16 +56,7 @@ def requires_admin_auth():
|
||||
|
||||
def requires_auth():
|
||||
auth_token = get_auth_token(request)
|
||||
try:
|
||||
client = get_token_issuer(auth_token)
|
||||
except TokenDecodeError as e:
|
||||
raise AuthError(e.message, 403)
|
||||
except TokenIssuerError:
|
||||
raise AuthError("Invalid token: iss not provided", 403)
|
||||
|
||||
if client == current_app.config.get('ADMIN_CLIENT_USER_NAME'):
|
||||
g.service_id = current_app.config.get('ADMIN_CLIENT_USER_NAME')
|
||||
return handle_admin_key(auth_token, current_app.config.get('ADMIN_CLIENT_SECRET'))
|
||||
client = __get_token_issuer(auth_token)
|
||||
|
||||
try:
|
||||
service = dao_fetch_service_by_id(client)
|
||||
@@ -98,12 +88,22 @@ def requires_auth():
|
||||
raise AuthError("Invalid token: signature, api token is not valid", 403)
|
||||
|
||||
|
||||
def __get_token_issuer(auth_token):
|
||||
try:
|
||||
client = get_token_issuer(auth_token)
|
||||
except TokenIssuerError:
|
||||
raise AuthError("Invalid token: iss field not provided", 403)
|
||||
except TokenDecodeError as e:
|
||||
raise AuthError("Invalid token: signature, api token is not valid", 403)
|
||||
return client
|
||||
|
||||
|
||||
def handle_admin_key(auth_token, secret):
|
||||
try:
|
||||
get_decode_errors(auth_token, secret)
|
||||
return
|
||||
except TokenDecodeError as e:
|
||||
raise AuthError(e.message, 403)
|
||||
raise AuthError("Invalid token: signature, api token is not valid", 403)
|
||||
|
||||
|
||||
def get_decode_errors(auth_token, unsigned_secret):
|
||||
|
||||
@@ -34,17 +34,17 @@ from app.models import JOB_STATUS_SCHEDULED, JOB_STATUS_PENDING, JOB_STATUS_CANC
|
||||
|
||||
from app.utils import pagination_links
|
||||
|
||||
job = Blueprint('job', __name__, url_prefix='/service/<uuid:service_id>/job')
|
||||
job_blueprint = Blueprint('job', __name__, url_prefix='/service/<uuid:service_id>/job')
|
||||
|
||||
from app.errors import (
|
||||
register_errors,
|
||||
InvalidRequest
|
||||
)
|
||||
|
||||
register_errors(job)
|
||||
register_errors(job_blueprint)
|
||||
|
||||
|
||||
@job.route('/<job_id>', methods=['GET'])
|
||||
@job_blueprint.route('/<job_id>', methods=['GET'])
|
||||
def get_job_by_service_and_job_id(service_id, job_id):
|
||||
job = dao_get_job_by_service_id_and_job_id(service_id, job_id)
|
||||
statistics = dao_get_notification_outcomes_for_job(service_id, job_id)
|
||||
@@ -55,7 +55,7 @@ def get_job_by_service_and_job_id(service_id, job_id):
|
||||
return jsonify(data=data)
|
||||
|
||||
|
||||
@job.route('/<job_id>/cancel', methods=['POST'])
|
||||
@job_blueprint.route('/<job_id>/cancel', methods=['POST'])
|
||||
def cancel_job(service_id, job_id):
|
||||
job = dao_get_future_scheduled_job_by_id_and_service_id(job_id, service_id)
|
||||
job.job_status = JOB_STATUS_CANCELLED
|
||||
@@ -64,7 +64,7 @@ def cancel_job(service_id, job_id):
|
||||
return get_job_by_service_and_job_id(service_id, job_id)
|
||||
|
||||
|
||||
@job.route('/<job_id>/notifications', methods=['GET'])
|
||||
@job_blueprint.route('/<job_id>/notifications', methods=['GET'])
|
||||
def get_all_notifications_for_service_job(service_id, job_id):
|
||||
data = notifications_filter_schema.load(request.args).data
|
||||
page = data['page'] if 'page' in data else 1
|
||||
@@ -100,7 +100,7 @@ def get_all_notifications_for_service_job(service_id, job_id):
|
||||
), 200
|
||||
|
||||
|
||||
@job.route('', methods=['GET'])
|
||||
@job_blueprint.route('', methods=['GET'])
|
||||
def get_jobs_by_service(service_id):
|
||||
if request.args.get('limit_days'):
|
||||
try:
|
||||
@@ -117,7 +117,7 @@ def get_jobs_by_service(service_id):
|
||||
return jsonify(**get_paginated_jobs(service_id, limit_days, statuses, page))
|
||||
|
||||
|
||||
@job.route('', methods=['POST'])
|
||||
@job_blueprint.route('', methods=['POST'])
|
||||
def create_job(service_id):
|
||||
service = dao_fetch_service_by_id(service_id)
|
||||
if not service.active:
|
||||
|
||||
101
app/notifications/notifications_ses_callback.py
Normal file
101
app/notifications/notifications_ses_callback.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from datetime import datetime
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
jsonify,
|
||||
request,
|
||||
current_app,
|
||||
json
|
||||
)
|
||||
|
||||
from app import statsd_client
|
||||
from app.clients.email.aws_ses import get_aws_responses
|
||||
from app.dao import (
|
||||
notifications_dao
|
||||
)
|
||||
|
||||
from app.notifications.process_client_response import validate_callback_data
|
||||
|
||||
ses_callback_blueprint = Blueprint('notifications_ses_callback_', __name__)
|
||||
|
||||
from app.errors import (
|
||||
register_errors,
|
||||
InvalidRequest
|
||||
)
|
||||
register_errors(ses_callback_blueprint)
|
||||
|
||||
|
||||
@ses_callback_blueprint.route('/notifications/email/ses', methods=['POST'])
|
||||
def process_ses_response():
|
||||
client_name = 'SES'
|
||||
try:
|
||||
ses_request = json.loads(request.data)
|
||||
|
||||
if 'Type' in ses_request and ses_request['Type'] == 'SubscriptionConfirmation':
|
||||
current_app.logger.info("SNS subscription confirmation url: {}".format(ses_request['SubscribeURL']))
|
||||
|
||||
errors = validate_callback_data(data=ses_request, fields=['Message'], client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
ses_message = json.loads(ses_request['Message'])
|
||||
errors = validate_callback_data(data=ses_message, fields=['notificationType'], client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
notification_type = ses_message['notificationType']
|
||||
if notification_type == 'Bounce':
|
||||
if ses_message['bounce']['bounceType'] == 'Permanent':
|
||||
notification_type = ses_message['bounce']['bounceType'] # permanent or not
|
||||
else:
|
||||
notification_type = 'Temporary'
|
||||
try:
|
||||
aws_response_dict = get_aws_responses(notification_type)
|
||||
except KeyError:
|
||||
error = "{} callback failed: status {} not found".format(client_name, notification_type)
|
||||
raise InvalidRequest(error, status_code=400)
|
||||
|
||||
notification_status = aws_response_dict['notification_status']
|
||||
|
||||
try:
|
||||
reference = ses_message['mail']['messageId']
|
||||
notification = notifications_dao.update_notification_status_by_reference(
|
||||
reference,
|
||||
notification_status
|
||||
)
|
||||
if not notification:
|
||||
error = "SES callback failed: notification either not found or already updated " \
|
||||
"from sending. Status {} for notification reference {}".format(notification_status, reference)
|
||||
raise InvalidRequest(error, status_code=404)
|
||||
|
||||
if not aws_response_dict['success']:
|
||||
current_app.logger.info(
|
||||
"SES delivery failed: notification id {} and reference {} has error found. Status {}".format(
|
||||
notification.id,
|
||||
reference,
|
||||
aws_response_dict['message']
|
||||
)
|
||||
)
|
||||
else:
|
||||
current_app.logger.info('{} callback return status of {} for notification: {}'.format(
|
||||
client_name,
|
||||
notification_status,
|
||||
notification.id))
|
||||
statsd_client.incr('callback.ses.{}'.format(notification_status))
|
||||
if notification.sent_at:
|
||||
statsd_client.timing_with_dates(
|
||||
'callback.ses.elapsed-time'.format(client_name.lower()),
|
||||
datetime.utcnow(),
|
||||
notification.sent_at
|
||||
)
|
||||
return jsonify(
|
||||
result="success", message="SES callback succeeded"
|
||||
), 200
|
||||
|
||||
except KeyError:
|
||||
message = "SES callback failed: messageId missing"
|
||||
raise InvalidRequest(message, status_code=400)
|
||||
|
||||
except ValueError as ex:
|
||||
error = "{} callback failed: invalid json".format(client_name)
|
||||
raise InvalidRequest(error, status_code=400)
|
||||
47
app/notifications/notifications_sms_callback.py
Normal file
47
app/notifications/notifications_sms_callback.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from flask import Blueprint
|
||||
from flask import json
|
||||
from flask import request, jsonify
|
||||
|
||||
from app.errors import InvalidRequest, register_errors
|
||||
from app.notifications.process_client_response import validate_callback_data, process_sms_client_response
|
||||
|
||||
sms_callback_blueprint = Blueprint("sms_callback_blueprint", __name__, url_prefix="/notifications/sms")
|
||||
register_errors(sms_callback_blueprint)
|
||||
|
||||
|
||||
@sms_callback_blueprint.route('/mmg', methods=['POST'])
|
||||
def process_mmg_response():
|
||||
client_name = 'MMG'
|
||||
data = json.loads(request.data)
|
||||
errors = validate_callback_data(data=data,
|
||||
fields=['status', 'CID'],
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
success, errors = process_sms_client_response(status=str(data.get('status')),
|
||||
reference=data.get('CID'),
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
else:
|
||||
return jsonify(result='success', message=success), 200
|
||||
|
||||
|
||||
@sms_callback_blueprint.route('/firetext', methods=['POST'])
|
||||
def process_firetext_response():
|
||||
client_name = 'Firetext'
|
||||
errors = validate_callback_data(data=request.form,
|
||||
fields=['status', 'reference'],
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
status = request.form.get('status')
|
||||
success, errors = process_sms_client_response(status=status,
|
||||
reference=request.form.get('reference'),
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
else:
|
||||
return jsonify(result='success', message=success), 200
|
||||
17
app/notifications/receive_notifications.py
Normal file
17
app/notifications/receive_notifications.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from flask import Blueprint
|
||||
from flask import current_app
|
||||
from flask import request
|
||||
|
||||
from app.errors import register_errors
|
||||
|
||||
receive_notifications_blueprint = Blueprint('receive_notifications', __name__)
|
||||
register_errors(receive_notifications_blueprint)
|
||||
|
||||
|
||||
@receive_notifications_blueprint.route('/notifications/sms/receive/mmg', methods=['POST'])
|
||||
def receive_mmg_sms():
|
||||
post_data = request.get_json()
|
||||
post_data.pop('MSISDN', None)
|
||||
current_app.logger.info("Recieve notification form data: {}".format(post_data))
|
||||
|
||||
return "RECEIVED"
|
||||
@@ -1,5 +1,3 @@
|
||||
from datetime import datetime
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
jsonify,
|
||||
@@ -8,8 +6,7 @@ from flask import (
|
||||
json
|
||||
)
|
||||
|
||||
from app import api_user, statsd_client
|
||||
from app.clients.email.aws_ses import get_aws_responses
|
||||
from app import api_user
|
||||
from app.dao import (
|
||||
templates_dao,
|
||||
services_dao,
|
||||
@@ -49,129 +46,6 @@ from app.errors import (
|
||||
register_errors(notifications)
|
||||
|
||||
|
||||
@notifications.route('/notifications/sms/receive/mmg', methods=['POST'])
|
||||
def receive_mmg_sms():
|
||||
post_data = request.get_json()
|
||||
post_data.pop('MSISDN', None)
|
||||
current_app.logger.info("Recieve notification form data: {}".format(post_data))
|
||||
|
||||
return "RECEIVED"
|
||||
|
||||
|
||||
@notifications.route('/notifications/email/ses', methods=['POST'])
|
||||
def process_ses_response():
|
||||
client_name = 'SES'
|
||||
try:
|
||||
ses_request = json.loads(request.data)
|
||||
|
||||
if 'Type' in ses_request and ses_request['Type'] == 'SubscriptionConfirmation':
|
||||
current_app.logger.info("SNS subscription confirmation url: {}".format(ses_request['SubscribeURL']))
|
||||
|
||||
errors = validate_callback_data(data=ses_request, fields=['Message'], client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
ses_message = json.loads(ses_request['Message'])
|
||||
errors = validate_callback_data(data=ses_message, fields=['notificationType'], client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
notification_type = ses_message['notificationType']
|
||||
if notification_type == 'Bounce':
|
||||
if ses_message['bounce']['bounceType'] == 'Permanent':
|
||||
notification_type = ses_message['bounce']['bounceType'] # permanent or not
|
||||
else:
|
||||
notification_type = 'Temporary'
|
||||
try:
|
||||
aws_response_dict = get_aws_responses(notification_type)
|
||||
except KeyError:
|
||||
error = "{} callback failed: status {} not found".format(client_name, notification_type)
|
||||
raise InvalidRequest(error, status_code=400)
|
||||
|
||||
notification_status = aws_response_dict['notification_status']
|
||||
|
||||
try:
|
||||
reference = ses_message['mail']['messageId']
|
||||
notification = notifications_dao.update_notification_status_by_reference(
|
||||
reference,
|
||||
notification_status
|
||||
)
|
||||
if not notification:
|
||||
error = "SES callback failed: notification either not found or already updated " \
|
||||
"from sending. Status {} for notification reference {}".format(notification_status, reference)
|
||||
raise InvalidRequest(error, status_code=404)
|
||||
|
||||
if not aws_response_dict['success']:
|
||||
current_app.logger.info(
|
||||
"SES delivery failed: notification id {} and reference {} has error found. Status {}".format(
|
||||
notification.id,
|
||||
reference,
|
||||
aws_response_dict['message']
|
||||
)
|
||||
)
|
||||
else:
|
||||
current_app.logger.info('{} callback return status of {} for notification: {}'.format(
|
||||
client_name,
|
||||
notification_status,
|
||||
notification.id))
|
||||
statsd_client.incr('callback.ses.{}'.format(notification_status))
|
||||
if notification.sent_at:
|
||||
statsd_client.timing_with_dates(
|
||||
'callback.ses.elapsed-time'.format(client_name.lower()),
|
||||
datetime.utcnow(),
|
||||
notification.sent_at
|
||||
)
|
||||
return jsonify(
|
||||
result="success", message="SES callback succeeded"
|
||||
), 200
|
||||
|
||||
except KeyError:
|
||||
message = "SES callback failed: messageId missing"
|
||||
raise InvalidRequest(message, status_code=400)
|
||||
|
||||
except ValueError as ex:
|
||||
error = "{} callback failed: invalid json".format(client_name)
|
||||
raise InvalidRequest(error, status_code=400)
|
||||
|
||||
|
||||
@notifications.route('/notifications/sms/mmg', methods=['POST'])
|
||||
def process_mmg_response():
|
||||
client_name = 'MMG'
|
||||
data = json.loads(request.data)
|
||||
errors = validate_callback_data(data=data,
|
||||
fields=['status', 'CID'],
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
success, errors = process_sms_client_response(status=str(data.get('status')),
|
||||
reference=data.get('CID'),
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
else:
|
||||
return jsonify(result='success', message=success), 200
|
||||
|
||||
|
||||
@notifications.route('/notifications/sms/firetext', methods=['POST'])
|
||||
def process_firetext_response():
|
||||
client_name = 'Firetext'
|
||||
errors = validate_callback_data(data=request.form,
|
||||
fields=['status', 'reference'],
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
status = request.form.get('status')
|
||||
success, errors = process_sms_client_response(status=status,
|
||||
reference=request.form.get('reference'),
|
||||
client_name=client_name)
|
||||
if errors:
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
else:
|
||||
return jsonify(result='success', message=success), 200
|
||||
|
||||
|
||||
@notifications.route('/notifications/<uuid:notification_id>', methods=['GET'])
|
||||
def get_notification_by_id(notification_id):
|
||||
notification = notifications_dao.get_notification_with_personalisation(str(api_user.service_id),
|
||||
|
||||
@@ -41,8 +41,7 @@ from app.dao import notifications_dao
|
||||
from app.dao.provider_statistics_dao import get_fragment_count
|
||||
from app.dao.users_dao import get_user_by_id
|
||||
from app.errors import (
|
||||
InvalidRequest,
|
||||
register_errors)
|
||||
InvalidRequest, register_errors)
|
||||
from app.service import statistics
|
||||
from app.service.utils import get_whitelist_objects
|
||||
from app.schemas import (
|
||||
@@ -57,11 +56,8 @@ from app.schemas import (
|
||||
from app.utils import pagination_links, get_london_midnight_in_utc
|
||||
from flask import Blueprint
|
||||
|
||||
from app.authentication.auth import requires_admin_auth
|
||||
|
||||
service_blueprint = Blueprint('service', __name__)
|
||||
|
||||
service_blueprint.before_request(requires_admin_auth)
|
||||
register_errors(service_blueprint)
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from app.dao.services_dao import dao_fetch_service_by_id
|
||||
from app.models import SMS_TYPE
|
||||
from app.schemas import (template_schema, template_history_schema)
|
||||
|
||||
template = Blueprint('template', __name__, url_prefix='/service/<uuid:service_id>/template')
|
||||
template_blueprint = Blueprint('template', __name__, url_prefix='/service/<uuid:service_id>/template')
|
||||
|
||||
from app.errors import (
|
||||
register_errors,
|
||||
@@ -25,7 +25,7 @@ from app.errors import (
|
||||
)
|
||||
from app.utils import get_template_instance
|
||||
|
||||
register_errors(template)
|
||||
register_errors(template_blueprint)
|
||||
|
||||
|
||||
def _content_count_greater_than_limit(content, template_type):
|
||||
@@ -35,7 +35,7 @@ def _content_count_greater_than_limit(content, template_type):
|
||||
return template.content_count > current_app.config.get('SMS_CHAR_COUNT_LIMIT')
|
||||
|
||||
|
||||
@template.route('', methods=['POST'])
|
||||
@template_blueprint.route('', methods=['POST'])
|
||||
def create_template(service_id):
|
||||
fetched_service = dao_fetch_service_by_id(service_id=service_id)
|
||||
new_template = template_schema.load(request.get_json()).data
|
||||
@@ -51,7 +51,7 @@ def create_template(service_id):
|
||||
return jsonify(data=template_schema.dump(new_template).data), 201
|
||||
|
||||
|
||||
@template.route('/<uuid:template_id>', methods=['POST'])
|
||||
@template_blueprint.route('/<uuid:template_id>', methods=['POST'])
|
||||
def update_template(service_id, template_id):
|
||||
fetched_template = dao_get_template_by_id_and_service_id(template_id=template_id, service_id=service_id)
|
||||
|
||||
@@ -73,21 +73,21 @@ def update_template(service_id, template_id):
|
||||
return jsonify(data=template_schema.dump(update_dict).data), 200
|
||||
|
||||
|
||||
@template.route('', methods=['GET'])
|
||||
@template_blueprint.route('', methods=['GET'])
|
||||
def get_all_templates_for_service(service_id):
|
||||
templates = dao_get_all_templates_for_service(service_id=service_id)
|
||||
data = template_schema.dump(templates, many=True).data
|
||||
return jsonify(data=data)
|
||||
|
||||
|
||||
@template.route('/<uuid:template_id>', methods=['GET'])
|
||||
@template_blueprint.route('/<uuid:template_id>', methods=['GET'])
|
||||
def get_template_by_id_and_service_id(service_id, template_id):
|
||||
fetched_template = dao_get_template_by_id_and_service_id(template_id=template_id, service_id=service_id)
|
||||
data = template_schema.dump(fetched_template).data
|
||||
return jsonify(data=data)
|
||||
|
||||
|
||||
@template.route('/<uuid:template_id>/preview', methods=['GET'])
|
||||
@template_blueprint.route('/<uuid:template_id>/preview', methods=['GET'])
|
||||
def preview_template_by_id_and_service_id(service_id, template_id):
|
||||
fetched_template = dao_get_template_by_id_and_service_id(template_id=template_id, service_id=service_id)
|
||||
data = template_schema.dump(fetched_template).data
|
||||
@@ -106,7 +106,7 @@ def preview_template_by_id_and_service_id(service_id, template_id):
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@template.route('/<uuid:template_id>/version/<int:version>')
|
||||
@template_blueprint.route('/<uuid:template_id>/version/<int:version>')
|
||||
def get_template_version(service_id, template_id, version):
|
||||
data = template_history_schema.dump(
|
||||
dao_get_template_by_id_and_service_id(
|
||||
@@ -118,7 +118,7 @@ def get_template_version(service_id, template_id, version):
|
||||
return jsonify(data=data)
|
||||
|
||||
|
||||
@template.route('/<uuid:template_id>/versions')
|
||||
@template_blueprint.route('/<uuid:template_id>/versions')
|
||||
def get_template_versions(service_id, template_id):
|
||||
data = template_history_schema.dump(
|
||||
dao_get_template_versions(service_id=service_id, template_id=template_id),
|
||||
|
||||
@@ -41,11 +41,11 @@ from app.errors import (
|
||||
)
|
||||
from app.utils import url_with_token
|
||||
|
||||
user = Blueprint('user', __name__)
|
||||
register_errors(user)
|
||||
user_blueprint = Blueprint('user', __name__)
|
||||
register_errors(user_blueprint)
|
||||
|
||||
|
||||
@user.route('', methods=['POST'])
|
||||
@user_blueprint.route('', methods=['POST'])
|
||||
def create_user():
|
||||
user_to_create, errors = user_schema.load(request.get_json())
|
||||
req_json = request.get_json()
|
||||
@@ -56,7 +56,7 @@ def create_user():
|
||||
return jsonify(data=user_schema.dump(user_to_create).data), 201
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>', methods=['PUT'])
|
||||
@user_blueprint.route('/<uuid:user_id>', methods=['PUT'])
|
||||
def update_user(user_id):
|
||||
user_to_update = get_user_by_id(user_id=user_id)
|
||||
req_json = request.get_json()
|
||||
@@ -73,7 +73,7 @@ def update_user(user_id):
|
||||
return jsonify(data=user_schema.dump(user_to_update).data), 200
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>', methods=['POST'])
|
||||
def update_user_attribute(user_id):
|
||||
user_to_update = get_user_by_id(user_id=user_id)
|
||||
req_json = request.get_json()
|
||||
@@ -84,14 +84,14 @@ def update_user_attribute(user_id):
|
||||
return jsonify(data=user_schema.dump(user_to_update).data), 200
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/reset-failed-login-count', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/reset-failed-login-count', methods=['POST'])
|
||||
def user_reset_failed_login_count(user_id):
|
||||
user_to_update = get_user_by_id(user_id=user_id)
|
||||
reset_failed_login_count(user_to_update)
|
||||
return jsonify(data=user_schema.dump(user_to_update).data), 200
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/verify/password', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/verify/password', methods=['POST'])
|
||||
def verify_user_password(user_id):
|
||||
user_to_verify = get_user_by_id(user_id=user_id)
|
||||
|
||||
@@ -112,7 +112,7 @@ def verify_user_password(user_id):
|
||||
raise InvalidRequest(errors, status_code=400)
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/verify/code', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/verify/code', methods=['POST'])
|
||||
def verify_user_code(user_id):
|
||||
user_to_verify = get_user_by_id(user_id=user_id)
|
||||
|
||||
@@ -151,7 +151,7 @@ def verify_user_code(user_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/sms-code', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/sms-code', methods=['POST'])
|
||||
def send_user_sms_code(user_id):
|
||||
user_to_send_to = get_user_by_id(user_id=user_id)
|
||||
verify_code, errors = request_verify_code_schema.load(request.get_json())
|
||||
@@ -187,7 +187,7 @@ def send_user_sms_code(user_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/change-email-verification', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/change-email-verification', methods=['POST'])
|
||||
def send_user_confirm_new_email(user_id):
|
||||
user_to_send_to = get_user_by_id(user_id=user_id)
|
||||
email, errors = email_data_request_schema.load(request.get_json())
|
||||
@@ -216,7 +216,7 @@ def send_user_confirm_new_email(user_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/email-verification', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/email-verification', methods=['POST'])
|
||||
def send_user_email_verification(user_id):
|
||||
user_to_send_to = get_user_by_id(user_id=user_id)
|
||||
secret_code = create_secret_code()
|
||||
@@ -244,7 +244,7 @@ def send_user_email_verification(user_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/email-already-registered', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/email-already-registered', methods=['POST'])
|
||||
def send_already_registered_email(user_id):
|
||||
to, errors = email_data_request_schema.load(request.get_json())
|
||||
template = dao_get_template_by_id(current_app.config['ALREADY_REGISTERED_EMAIL_TEMPLATE_ID'])
|
||||
@@ -270,15 +270,15 @@ def send_already_registered_email(user_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>', methods=['GET'])
|
||||
@user.route('', methods=['GET'])
|
||||
@user_blueprint.route('/<uuid:user_id>', methods=['GET'])
|
||||
@user_blueprint.route('', methods=['GET'])
|
||||
def get_user(user_id=None):
|
||||
users = get_user_by_id(user_id=user_id)
|
||||
result = user_schema.dump(users, many=True) if isinstance(users, list) else user_schema.dump(users)
|
||||
return jsonify(data=result.data)
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/service/<uuid:service_id>/permission', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/service/<uuid:service_id>/permission', methods=['POST'])
|
||||
def set_permissions(user_id, service_id):
|
||||
# TODO fix security hole, how do we verify that the user
|
||||
# who is making this request has permission to make the request.
|
||||
@@ -293,7 +293,7 @@ def set_permissions(user_id, service_id):
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/email', methods=['GET'])
|
||||
@user_blueprint.route('/email', methods=['GET'])
|
||||
def get_by_email():
|
||||
email = request.args.get('email')
|
||||
if not email:
|
||||
@@ -305,7 +305,7 @@ def get_by_email():
|
||||
return jsonify(data=result.data)
|
||||
|
||||
|
||||
@user.route('/reset-password', methods=['POST'])
|
||||
@user_blueprint.route('/reset-password', methods=['POST'])
|
||||
def send_user_reset_password():
|
||||
email, errors = email_data_request_schema.load(request.get_json())
|
||||
|
||||
@@ -332,7 +332,7 @@ def send_user_reset_password():
|
||||
return jsonify({}), 204
|
||||
|
||||
|
||||
@user.route('/<uuid:user_id>/update-password', methods=['POST'])
|
||||
@user_blueprint.route('/<uuid:user_id>/update-password', methods=['POST'])
|
||||
def update_password(user_id):
|
||||
user = get_user_by_id(user_id=user_id)
|
||||
req_json = request.get_json()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from flask import Blueprint
|
||||
|
||||
from app.v2.errors import register_errors
|
||||
|
||||
notification_blueprint = Blueprint("v2_notifications", __name__, url_prefix='/v2/notifications')
|
||||
v2_notification_blueprint = Blueprint("v2_notifications", __name__, url_prefix='/v2/notifications')
|
||||
|
||||
register_errors(notification_blueprint)
|
||||
register_errors(v2_notification_blueprint)
|
||||
|
||||
@@ -6,11 +6,11 @@ from werkzeug.exceptions import abort
|
||||
from app import api_user
|
||||
from app.dao import notifications_dao
|
||||
from app.schema_validation import validate
|
||||
from app.v2.notifications import notification_blueprint
|
||||
from app.v2.notifications import v2_notification_blueprint
|
||||
from app.v2.notifications.notification_schemas import get_notifications_request
|
||||
|
||||
|
||||
@notification_blueprint.route("/<id>", methods=['GET'])
|
||||
@v2_notification_blueprint.route("/<id>", methods=['GET'])
|
||||
def get_notification_by_id(id):
|
||||
try:
|
||||
casted_id = uuid.UUID(id)
|
||||
@@ -23,7 +23,7 @@ def get_notification_by_id(id):
|
||||
return jsonify(notification.serialize()), 200
|
||||
|
||||
|
||||
@notification_blueprint.route("", methods=['GET'])
|
||||
@v2_notification_blueprint.route("", methods=['GET'])
|
||||
def get_notifications():
|
||||
_data = request.args.to_dict(flat=False)
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ from app.notifications.validators import (check_service_message_limit,
|
||||
validate_and_format_recipient)
|
||||
from app.schema_validation import validate
|
||||
from app.v2.errors import BadRequestError
|
||||
from app.v2.notifications import notification_blueprint
|
||||
from app.v2.notifications import v2_notification_blueprint
|
||||
from app.v2.notifications.notification_schemas import (post_sms_request,
|
||||
create_post_sms_response_from_notification, post_email_request,
|
||||
create_post_email_response_from_notification)
|
||||
|
||||
|
||||
@notification_blueprint.route('/<notification_type>', methods=['POST'])
|
||||
@v2_notification_blueprint.route('/<notification_type>', methods=['POST'])
|
||||
def post_notification(notification_type):
|
||||
if notification_type == EMAIL_TYPE:
|
||||
form = validate(request.get_json(), post_email_request)
|
||||
|
||||
Reference in New Issue
Block a user