From c7121be5a2c59f62b1baad62db1b93ed22897584 Mon Sep 17 00:00:00 2001 From: Adam Shimali Date: Tue, 9 Feb 2016 12:01:17 +0000 Subject: [PATCH 1/6] [WIP] New model class and dao for notification. This will be used for recording status and outcome of sending notifications. --- app/dao/notifications_dao.py | 22 ++++++ app/models.py | 29 ++++++++ migrations/versions/0013_add_notifications.py | 47 ++++++++++++ tests/app/conftest.py | 31 +++++++- tests/app/dao/test_notification_dao.py | 74 +++++++++++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 app/dao/notifications_dao.py create mode 100644 migrations/versions/0013_add_notifications.py create mode 100644 tests/app/dao/test_notification_dao.py diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py new file mode 100644 index 000000000..be4e56ef6 --- /dev/null +++ b/app/dao/notifications_dao.py @@ -0,0 +1,22 @@ +from app import db +from app.models import Notification + + +def save_notification(notification, update_dict={}): + if update_dict: + update_dict.pop('id', None) + update_dict.pop('job', None) + update_dict.pop('service_id', None) + update_dict.pop('template_id', None) + Notification.query.filter_by(id=notification.id).update(update_dict) + else: + db.session.add(notification) + db.session.commit() + + +def get_notification(job_id, notification_id): + return Notification.query.filter_by(job_id=job_id, id=notification_id).one() + + +def get_notifications_by_job(job_id): + return Notification.query.filter_by(job_id=job_id).all() diff --git a/app/models.py b/app/models.py index dc260836b..22337a6a5 100644 --- a/app/models.py +++ b/app/models.py @@ -189,3 +189,32 @@ class VerifyCode(db.Model): def check_code(self, cde): return check_hash(cde, self._code) + + +NOTIFICATION_STATUS_TYPES = ['sent', 'failed'] + + +class Notification(db.Model): + + __tablename__ = 'notifications' + + id = db.Column(UUID(as_uuid=True), primary_key=True) + to = db.Column(db.String, nullable=False) + job_id = db.Column(UUID(as_uuid=True), db.ForeignKey('jobs.id'), index=True, unique=False, nullable=False) + job = db.relationship('Job', backref=db.backref('notifications', lazy='dynamic')) + service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False) + template_id = db.Column(db.BigInteger, db.ForeignKey('templates.id'), index=True, unique=False) + created_at = db.Column( + db.DateTime, + index=False, + unique=False, + nullable=False, + default=datetime.datetime.now) + updated_at = db.Column( + db.DateTime, + index=False, + unique=False, + nullable=True, + onupdate=datetime.datetime.now) + status = db.Column( + db.Enum(*NOTIFICATION_STATUS_TYPES, name='notification_status_types'), nullable=False, default='sent') diff --git a/migrations/versions/0013_add_notifications.py b/migrations/versions/0013_add_notifications.py new file mode 100644 index 000000000..61fd55a66 --- /dev/null +++ b/migrations/versions/0013_add_notifications.py @@ -0,0 +1,47 @@ +"""empty message + +Revision ID: 0013_add_notifications +Revises: 0012_add_status_to_job +Create Date: 2016-02-09 11:14:46.708551 + +""" + +# revision identifiers, used by Alembic. +revision = '0013_add_notifications' +down_revision = '0012_add_status_to_job' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('notifications', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('to', sa.String(), nullable=False), + sa.Column('job_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('service_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('template_id', sa.BigInteger(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('status', sa.Enum('sent', 'failed', name='notification_status_types'), nullable=False), + sa.ForeignKeyConstraint(['job_id'], ['jobs.id'], ), + sa.ForeignKeyConstraint(['service_id'], ['services.id'], ), + sa.ForeignKeyConstraint(['template_id'], ['templates.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_notifications_job_id'), 'notifications', ['job_id'], unique=False) + op.create_index(op.f('ix_notifications_service_id'), 'notifications', ['service_id'], unique=False) + op.create_index(op.f('ix_notifications_template_id'), 'notifications', ['template_id'], unique=False) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_notifications_template_id'), table_name='notifications') + op.drop_index(op.f('ix_notifications_service_id'), table_name='notifications') + op.drop_index(op.f('ix_notifications_job_id'), table_name='notifications') + op.drop_table('notifications') + op.get_bind() + op.execute("drop type notification_status_types") + ### end Alembic commands ### diff --git a/tests/app/conftest.py b/tests/app/conftest.py index e1abea888..741d896eb 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -1,12 +1,13 @@ import pytest from flask import jsonify -from app.models import (User, Service, Template, ApiKey, Job, VerifyCode) +from app.models import (User, Service, Template, ApiKey, Job, VerifyCode, Notification) from app.dao.users_dao import (save_model_user, create_user_code, create_secret_code) from app.dao.services_dao import save_model_service from app.dao.templates_dao import save_model_template from app.dao.api_key_dao import save_model_api_key from app.dao.jobs_dao import save_job +from app.dao.notifications_dao import save_notification import uuid @@ -180,3 +181,31 @@ def mock_secret_code(mocker): mock_class = mocker.patch('app.dao.users_dao.create_secret_code', side_effect=_create) return mock_class + + +@pytest.fixture(scope='function') +def sample_notification(notify_db, + notify_db_session, + service=None, + template=None, + job=None): + if service is None: + service = sample_service(notify_db, notify_db_session) + if template is None: + template = sample_template(notify_db, notify_db_session, service=service) + if job is None: + job = sample_job(notify_db, notify_db_session, service=service, template=template) + + notificaton_id = uuid.uuid4() + to = '+44709123456' + + data = { + 'id': notificaton_id, + 'to': to, + 'job_id': job.id, + 'service_id': service.id, + 'template_id': template.id + } + notification = Notification(**data) + save_notification(notification) + return notification diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py new file mode 100644 index 000000000..23ff6fe23 --- /dev/null +++ b/tests/app/dao/test_notification_dao.py @@ -0,0 +1,74 @@ +import uuid + +from app.models import Notification + +from app.dao.notifications_dao import ( + save_notification, + get_notification, + get_notifications_by_job +) + + +def test_save_notification(notify_db, notify_db_session, sample_template, sample_job): + + assert Notification.query.count() == 0 + + notification_id = uuid.uuid4() + to = '+44709123456' + job_id = sample_job.id + data = { + 'id': notification_id, + 'to': to, + 'job_id': job_id, + 'service_id': sample_template.service.id, + 'template_id': sample_template.id + } + + notification = Notification(**data) + save_notification(notification) + + assert Notification.query.count() == 1 + + notification_from_db = Notification.query.get(notification_id) + + assert data['id'] == notification_from_db.id + assert data['to'] == notification_from_db.to + assert data['job_id'] == notification_from_db.job_id + assert data['service_id'] == notification_from_db.service_id + assert data['template_id'] == notification_from_db.template_id + assert 'sent' == notification_from_db.status + + +def test_get_notification_for_job(notify_db, notify_db_session, sample_notification): + notifcation_from_db = get_notification(sample_notification.job_id, sample_notification.id) + assert sample_notification == notifcation_from_db + + +def test_get_all_notifications_for_job(notify_db, notify_db_session, sample_job): + + from tests.app.conftest import sample_notification + for i in range(0, 5): + sample_notification(notify_db, + notify_db_session, + service=sample_job.service, + template=sample_job.template, + job=sample_job) + + notifcations_from_db = get_notifications_by_job(sample_job.id) + assert len(notifcations_from_db) == 5 + + +def test_update_notification(notify_db, notify_db_session, sample_notification): + assert sample_notification.status == 'sent' + + update_dict = { + 'id': sample_notification.id, + 'service_id': sample_notification.service_id, + 'template_id': sample_notification.template_id, + 'job': sample_notification.job, + 'status': 'failed' + } + + save_notification(sample_notification, update_dict=update_dict) + notification_from_db = Notification.query.get(sample_notification.id) + assert notification_from_db.status == 'failed' From e5e049d73564a9035265ec6eb142da92a9e37ea9 Mon Sep 17 00:00:00 2001 From: Adam Shimali Date: Tue, 9 Feb 2016 12:48:27 +0000 Subject: [PATCH 2/6] Added service and template relationship to notification model. This makes it more consistent with other model classes with respect to marhmallow serialisation/deserialisation. --- app/dao/notifications_dao.py | 4 ++-- app/models.py | 2 ++ tests/app/conftest.py | 6 +++--- tests/app/dao/test_notification_dao.py | 17 ++++++++--------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index be4e56ef6..8c42ac6ca 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -6,8 +6,8 @@ def save_notification(notification, update_dict={}): if update_dict: update_dict.pop('id', None) update_dict.pop('job', None) - update_dict.pop('service_id', None) - update_dict.pop('template_id', None) + update_dict.pop('service', None) + update_dict.pop('template', None) Notification.query.filter_by(id=notification.id).update(update_dict) else: db.session.add(notification) diff --git a/app/models.py b/app/models.py index 22337a6a5..1ce4a7dbf 100644 --- a/app/models.py +++ b/app/models.py @@ -203,7 +203,9 @@ class Notification(db.Model): job_id = db.Column(UUID(as_uuid=True), db.ForeignKey('jobs.id'), index=True, unique=False, nullable=False) job = db.relationship('Job', backref=db.backref('notifications', lazy='dynamic')) service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False) + service = db.relationship('Service') template_id = db.Column(db.BigInteger, db.ForeignKey('templates.id'), index=True, unique=False) + template = db.relationship('Template') created_at = db.Column( db.DateTime, index=False, diff --git a/tests/app/conftest.py b/tests/app/conftest.py index 741d896eb..0f6a33461 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -202,9 +202,9 @@ def sample_notification(notify_db, data = { 'id': notificaton_id, 'to': to, - 'job_id': job.id, - 'service_id': service.id, - 'template_id': template.id + 'job': job, + 'service': service, + 'template': template } notification = Notification(**data) save_notification(notification) diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py index 23ff6fe23..7d1218e74 100644 --- a/tests/app/dao/test_notification_dao.py +++ b/tests/app/dao/test_notification_dao.py @@ -15,13 +15,12 @@ def test_save_notification(notify_db, notify_db_session, sample_template, sample notification_id = uuid.uuid4() to = '+44709123456' - job_id = sample_job.id data = { 'id': notification_id, 'to': to, - 'job_id': job_id, - 'service_id': sample_template.service.id, - 'template_id': sample_template.id + 'job': sample_job, + 'service': sample_template.service, + 'template': sample_template } notification = Notification(**data) @@ -33,9 +32,9 @@ def test_save_notification(notify_db, notify_db_session, sample_template, sample assert data['id'] == notification_from_db.id assert data['to'] == notification_from_db.to - assert data['job_id'] == notification_from_db.job_id - assert data['service_id'] == notification_from_db.service_id - assert data['template_id'] == notification_from_db.template_id + assert data['job'] == notification_from_db.job + assert data['service'] == notification_from_db.service + assert data['template'] == notification_from_db.template assert 'sent' == notification_from_db.status @@ -63,8 +62,8 @@ def test_update_notification(notify_db, notify_db_session, sample_notification): update_dict = { 'id': sample_notification.id, - 'service_id': sample_notification.service_id, - 'template_id': sample_notification.template_id, + 'service': sample_notification.service, + 'template': sample_notification.template, 'job': sample_notification.job, 'status': 'failed' } From c2424d650996f25ae8f3c05488cdb46f1c63f945 Mon Sep 17 00:00:00 2001 From: Martyn Inglis Date: Tue, 9 Feb 2016 13:41:20 +0000 Subject: [PATCH 3/6] Added code to read environemnt from a file If file does not exist default to live config. --- wsgi.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/wsgi.py b/wsgi.py index 138a48c6f..fd773b3e0 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,9 +1,17 @@ from app import create_app from credstash import getAllSecrets +import os + +config = 'live' +default_env_file = '/home/ubuntu/environment' + +if os.path.isfile(default_env_file): + environment = open(default_env_file, 'r') + config = environment.readline().strip() secrets = getAllSecrets(region="eu-west-1") -application = create_app('live', secrets) +application = create_app(config, secrets) if __name__ == "__main__": application.run() From 66763a061c18f4598cd04a5166b8137c92d4fcd8 Mon Sep 17 00:00:00 2001 From: Martyn Inglis Date: Tue, 9 Feb 2016 13:56:11 +0000 Subject: [PATCH 4/6] Added preview and staging config blocks --- config.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config.py b/config.py index 8f728f1e1..6ec03eac7 100644 --- a/config.py +++ b/config.py @@ -36,12 +36,22 @@ class Test(Development): SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/test_notification_api' +class Preview(Config): + pass + + +class Staging(Config): + pass + + class Live(Config): pass configs = { 'development': Development, + 'preview': Preview, + 'staging': Staging, 'test': Test, 'live': Live, } From 38e30034d1171203446438788683d8344d23755b Mon Sep 17 00:00:00 2001 From: Nicholas Staples Date: Tue, 9 Feb 2016 14:07:43 +0000 Subject: [PATCH 5/6] updated environment variables. --- config.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config.py b/config.py index 6ec03eac7..17639d51f 100644 --- a/config.py +++ b/config.py @@ -30,22 +30,24 @@ class Development(Config): ADMIN_CLIENT_SECRET = 'dev-notify-secret-key' DELIVERY_CLIENT_USER_NAME = 'dev-notify-delivery' DELIVERY_CLIENT_SECRET = 'dev-notify-secret-key' + NOTIFICATION_QUEUE_PREFIX = 'notification_development' class Test(Development): SQLALCHEMY_DATABASE_URI = 'postgresql://localhost/test_notification_api' + NOTIFICATION_QUEUE_PREFIX = 'notification_test' class Preview(Config): - pass + NOTIFICATION_QUEUE_PREFIX = 'notification_preview' class Staging(Config): - pass + NOTIFICATION_QUEUE_PREFIX = 'notification_staging' class Live(Config): - pass + NOTIFICATION_QUEUE_PREFIX = 'notification_live' configs = { From 17e5e70f6c746a4e81a2287b6137b9a748c9dce3 Mon Sep 17 00:00:00 2001 From: Adam Shimali Date: Tue, 9 Feb 2016 14:17:42 +0000 Subject: [PATCH 6/6] [WIP] Added endpoints under /job for creating, updating and reading notification status. --- app/dao/notifications_dao.py | 8 +- app/job/rest.py | 61 +++++++++++- app/schemas.py | 9 ++ tests/app/dao/test_notification_dao.py | 16 ++-- tests/app/job/test_job_rest.py | 124 +++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 13 deletions(-) diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 8c42ac6ca..ed3cd0f6d 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -14,9 +14,9 @@ def save_notification(notification, update_dict={}): db.session.commit() -def get_notification(job_id, notification_id): - return Notification.query.filter_by(job_id=job_id, id=notification_id).one() +def get_notification(service_id, job_id, notification_id): + return Notification.query.filter_by(service_id=service_id, job_id=job_id, id=notification_id).one() -def get_notifications_by_job(job_id): - return Notification.query.filter_by(job_id=job_id).all() +def get_notifications(service_id, job_id): + return Notification.query.filter_by(service_id=service_id, job_id=job_id).all() diff --git a/app/job/rest.py b/app/job/rest.py index 2caaa00d9..17f1e341c 100644 --- a/app/job/rest.py +++ b/app/job/rest.py @@ -8,7 +8,6 @@ from flask import ( current_app ) -from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import DataError from sqlalchemy.orm.exc import NoResultFound @@ -18,10 +17,19 @@ from app.dao.jobs_dao import ( get_jobs_by_service ) +from app.dao.notifications_dao import ( + save_notification, + get_notification, + get_notifications +) + from app.schemas import ( job_schema, jobs_schema, - job_schema_load_json + job_schema_load_json, + notification_status_schema, + notifications_status_schema, + notification_status_schema_load_json ) job = Blueprint('job', __name__, url_prefix='/service//job') @@ -72,6 +80,55 @@ def update_job(service_id, job_id): return jsonify(data=job_schema.dump(job).data), 200 +@job.route('//notification', methods=['POST']) +def create_notification_for_job(service_id, job_id): + + # TODO assert service_id == payload service id + # and same for job id + notification, errors = notification_status_schema.load(request.get_json()) + if errors: + return jsonify(result="error", message=errors), 400 + try: + save_notification(notification) + except Exception as e: + return jsonify(result="error", message=str(e)), 500 + return jsonify(data=notification_status_schema.dump(notification).data), 201 + + +@job.route('//notification', methods=['GET']) +@job.route('//notification/') +def get_notification_for_job(service_id, job_id, notification_id=None): + if notification_id: + try: + notification = get_notification(service_id, job_id, notification_id) + data, errors = notification_status_schema.dump(notification) + return jsonify(data=data) + except DataError: + return jsonify(result="error", message="Invalid notification id"), 400 + except NoResultFound: + return jsonify(result="error", message="Notification not found"), 404 + else: + notifications = get_notifications(service_id, job_id) + data, errors = notifications_status_schema.dump(notifications) + return jsonify(data=data) + + +@job.route('//notification/', methods=['PUT']) +def update_notification_for_job(service_id, job_id, notification_id): + + notification = get_notification(service_id, job_id, notification_id) + update_dict, errors = notification_status_schema_load_json.load(request.get_json()) + + if errors: + return jsonify(result="error", message=errors), 400 + try: + save_notification(notification, update_dict=update_dict) + except Exception as e: + return jsonify(result="error", message=str(e)), 400 + + return jsonify(data=job_schema.dump(notification).data), 200 + + def _enqueue_job(job): aws_region = current_app.config['AWS_REGION'] queue_name = current_app.config['NOTIFY_JOB_QUEUE'] diff --git a/app/schemas.py b/app/schemas.py index 7d4e329df..3a0ab41df 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -129,6 +129,12 @@ class EmailNotificationSchema(NotificationSchema): body = fields.Str(load_from="message", dump_to='message', required=True) +class NotificationStatusSchema(BaseSchema): + + class Meta: + model = models.Notification + + user_schema = UserSchema() user_schema_load_json = UserSchema(load_json=True) users_schema = UserSchema(many=True) @@ -148,3 +154,6 @@ request_verify_code_schema = RequestVerifyCodeSchema() sms_admin_notification_schema = SmsAdminNotificationSchema() sms_template_notification_schema = SmsTemplateNotificationSchema() email_notification_schema = EmailNotificationSchema() +notification_status_schema = NotificationStatusSchema() +notifications_status_schema = NotificationStatusSchema(many=True) +notification_status_schema_load_json = NotificationStatusSchema(load_json=True) diff --git a/tests/app/dao/test_notification_dao.py b/tests/app/dao/test_notification_dao.py index 7d1218e74..cf1e70a6f 100644 --- a/tests/app/dao/test_notification_dao.py +++ b/tests/app/dao/test_notification_dao.py @@ -5,7 +5,7 @@ from app.models import Notification from app.dao.notifications_dao import ( save_notification, get_notification, - get_notifications_by_job + get_notifications ) @@ -39,7 +39,9 @@ def test_save_notification(notify_db, notify_db_session, sample_template, sample def test_get_notification_for_job(notify_db, notify_db_session, sample_notification): - notifcation_from_db = get_notification(sample_notification.job_id, sample_notification.id) + notifcation_from_db = get_notification(sample_notification.service.id, + sample_notification.job_id, + sample_notification.id) assert sample_notification == notifcation_from_db @@ -53,7 +55,7 @@ def test_get_all_notifications_for_job(notify_db, notify_db_session, sample_job) template=sample_job.template, job=sample_job) - notifcations_from_db = get_notifications_by_job(sample_job.id) + notifcations_from_db = get_notifications(sample_job.service.id, sample_job.id) assert len(notifcations_from_db) == 5 @@ -61,10 +63,10 @@ def test_update_notification(notify_db, notify_db_session, sample_notification): assert sample_notification.status == 'sent' update_dict = { - 'id': sample_notification.id, - 'service': sample_notification.service, - 'template': sample_notification.template, - 'job': sample_notification.job, + 'id': str(sample_notification.id), + 'service': str(sample_notification.service.id), + 'template': sample_notification.template.id, + 'job': str(sample_notification.job.id), 'status': 'failed' } diff --git a/tests/app/job/test_job_rest.py b/tests/app/job/test_job_rest.py index 20b520e1b..d16e2ac8f 100644 --- a/tests/app/job/test_job_rest.py +++ b/tests/app/job/test_job_rest.py @@ -163,6 +163,130 @@ def test_get_update_job_status(notify_api, assert resp_json['data']['status'] == 'in progress' +def test_get_notification(notify_api, notify_db, notify_db_session, sample_notification): + + with notify_api.test_request_context(): + with notify_api.test_client() as client: + path = url_for('job.get_notification_for_job', + service_id=sample_notification.service.id, + job_id=sample_notification.job.id, + notification_id=sample_notification.id) + + auth_header = create_authorization_header(service_id=sample_notification.service.id, + path=path, + method='GET') + + headers = [('Content-Type', 'application/json'), auth_header] + response = client.get(path, headers=headers) + resp_json = json.loads(response.get_data(as_text=True)) + + assert str(sample_notification.id) == resp_json['data']['id'] + assert str(sample_notification.service.id) == resp_json['data']['service'] + assert sample_notification.template.id == resp_json['data']['template'] + assert str(sample_notification.job.id) == resp_json['data']['job'] + assert sample_notification.status == resp_json['data']['status'] + + +def test_get_notifications(notify_api, notify_db, notify_db_session, sample_job): + + from tests.app.conftest import sample_notification + for i in range(0, 5): + sample_notification(notify_db, + notify_db_session, + service=sample_job.service, + template=sample_job.template, + job=sample_job) + + service_id = str(sample_job.service.id) + job_id = str(sample_job.id) + + with notify_api.test_request_context(): + with notify_api.test_client() as client: + path = url_for('job.get_notification_for_job', + service_id=service_id, + job_id=job_id) + + auth_header = create_authorization_header(service_id=service_id, + path=path, + method='GET') + + headers = [('Content-Type', 'application/json'), auth_header] + response = client.get(path, headers=headers) + resp_json = json.loads(response.get_data(as_text=True)) + + assert len(resp_json['data']) == 5 + + +def test_add_notification(notify_api, notify_db, notify_db_session, sample_job): + + notificaton_id = uuid.uuid4() + to = '+44709123456' + data = { + 'id': str(notificaton_id), + 'to': to, + 'job': str(sample_job.id), + 'service': str(sample_job.service.id), + 'template': sample_job.template.id + } + with notify_api.test_request_context(): + with notify_api.test_client() as client: + path = url_for('job.create_notification_for_job', + service_id=sample_job.service.id, + job_id=sample_job.id) + + auth_header = create_authorization_header(service_id=sample_job.service.id, + path=path, + method='POST', + request_body=json.dumps(data)) + + headers = [('Content-Type', 'application/json'), auth_header] + + response = client.post(path, headers=headers, data=json.dumps(data)) + + resp_json = json.loads(response.get_data(as_text=True)) + + assert data['id'] == resp_json['data']['id'] + assert data['to'] == resp_json['data']['to'] + assert data['service'] == resp_json['data']['service'] + assert data['template'] == resp_json['data']['template'] + assert data['job'] == resp_json['data']['job'] + assert 'sent' == resp_json['data']['status'] + + +def test_update_notification(notify_api, notify_db, notify_db_session, sample_notification): + + assert sample_notification.status == 'sent' + + update_data = { + 'id': str(sample_notification.id), + 'to': sample_notification.to, + 'job': str(sample_notification.job.id), + 'service': str(sample_notification.service.id), + 'template': sample_notification.template.id, + 'status': 'failed' + } + with notify_api.test_request_context(): + with notify_api.test_client() as client: + path = url_for('job.update_notification_for_job', + service_id=sample_notification.service.id, + job_id=sample_notification.job.id, + notification_id=sample_notification.id) + + auth_header = create_authorization_header(service_id=sample_notification.service.id, + path=path, + method='PUT', + request_body=json.dumps(update_data)) + + headers = [('Content-Type', 'application/json'), auth_header] + + response = client.put(path, headers=headers, data=json.dumps(update_data)) + + resp_json = json.loads(response.get_data(as_text=True)) + + assert update_data['id'] == resp_json['data']['id'] + assert 'failed' == resp_json['data']['status'] + + def _setup_jobs(notify_db, notify_db_session, template, number_of_jobs=5): for i in range(number_of_jobs): create_job(notify_db, notify_db_session, service=template.service,