diff --git a/app/dao/templates_dao.py b/app/dao/templates_dao.py index bb42be1cb..9efee89b9 100644 --- a/app/dao/templates_dao.py +++ b/app/dao/templates_dao.py @@ -22,11 +22,20 @@ def dao_update_template(template): db.session.add(template) -def dao_get_template_by_id_and_service_id(template_id, service_id): +def dao_get_template_by_id_and_service_id(template_id, service_id, version=None): + if version is not None: + return Template.get_history_model().query.filter_by( + id=template_id, + service_id=service_id, + version=version).one() return Template.query.filter_by(id=template_id, service_id=service_id).one() -def dao_get_template_by_id(template_id): +def dao_get_template_by_id(template_id, version=None): + if version is not None: + return Template.get_history_model().query.filter_by( + id=template_id, + version=version).one() return Template.query.filter_by(id=template_id).one() diff --git a/app/schemas.py b/app/schemas.py index 9f18393c5..4cca7b66c 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -1,5 +1,6 @@ from datetime import date from flask_marshmallow.fields import fields +from sqlalchemy.orm import load_only from marshmallow import ( post_load, @@ -93,6 +94,11 @@ class BaseTemplateSchema(BaseSchema): class TemplateSchema(BaseTemplateSchema): created_by = field_for(models.Template, 'created_by', required=True) + versions = fields.Method("template_versions", dump_only=True) + + def template_versions(self, template): + return [x.version for x in models.Template.get_history_model().query.filter_by( + id=template.id).options(load_only("version"))] @validates_schema def validate_type(self, data): @@ -103,6 +109,11 @@ class TemplateSchema(BaseTemplateSchema): raise ValidationError('Invalid template subject', 'subject') +class TemplateHistorySchema(BaseTemplateSchema): + + created_by = field_for(models.Template, 'created_by', required=True) + + class NotificationsStatisticsSchema(BaseSchema): class Meta: model = models.NotificationStatistics @@ -302,18 +313,6 @@ class ApiKeyHistorySchema(ma.Schema): created_by_id = fields.UUID() -class TemplateHistorySchema(ma.Schema): - id = fields.UUID() - name = fields.String() - template_type = fields.String() - created_at = fields.DateTime() - updated_at = fields.DateTime() - content = fields.String() - service_id = fields.UUID() - subject = fields.String() - created_by_id = fields.UUID() - - class EventSchema(BaseSchema): class Meta: model = models.Event diff --git a/app/template/rest.py b/app/template/rest.py index b04513356..69d668577 100644 --- a/app/template/rest.py +++ b/app/template/rest.py @@ -15,7 +15,7 @@ from app.dao.templates_dao import ( ) from notifications_utils.template import Template from app.dao.services_dao import dao_fetch_service_by_id -from app.schemas import template_schema +from app.schemas import (template_schema, template_history_schema) template = Blueprint('template', __name__, url_prefix='/service//template') @@ -96,5 +96,18 @@ def get_template_by_id_and_service_id(service_id, template_id): return jsonify(data=data) +@template.route('//version/') +def get_template_version(service_id, template_id, version): + fetched_template = dao_get_template_by_id_and_service_id( + template_id=template_id, + service_id=service_id, + version=version + ) + data, errors = template_history_schema.dump(fetched_template) + if errors: + return json_resp(result=error, message=errors), 400 + return jsonify(data=data) + + def _strip_html(content): return bleach.clean(content, tags=[], strip=True) diff --git a/tests/app/dao/test_templates_dao.py b/tests/app/dao/test_templates_dao.py index dbd163820..cf5591606 100644 --- a/tests/app/dao/test_templates_dao.py +++ b/tests/app/dao/test_templates_dao.py @@ -218,3 +218,15 @@ def test_update_template_creates_a_history_record_with_current_data(sample_servi assert Template.get_history_model().query.filter_by(name='Sample Template').one().version == 1 assert Template.get_history_model().query.filter_by(name='new name').one().version == 2 + + +def test_get_template_history_version(sample_user, sample_service, sample_template): + old_content = sample_template.content + sample_template.content = "New content" + dao_update_template(sample_template) + old_template = dao_get_template_by_id_and_service_id( + sample_template.id, + sample_service.id, + '1' + ) + assert old_template.content == old_content diff --git a/tests/app/template/test_rest.py b/tests/app/template/test_rest.py index a9bc7bf92..ac47ad6d7 100644 --- a/tests/app/template/test_rest.py +++ b/tests/app/template/test_rest.py @@ -30,6 +30,7 @@ def test_should_create_a_new_sms_template_for_a_service(notify_api, sample_user, assert json_resp['data']['content'] == 'template content' assert json_resp['data']['service'] == str(sample_service.id) assert json_resp['data']['id'] + assert json_resp['data']['versions'] == [1] assert not json_resp['data']['subject'] @@ -59,6 +60,7 @@ def test_should_create_a_new_email_template_for_a_service(notify_api, sample_use assert json_resp['data']['content'] == 'template content' assert json_resp['data']['service'] == str(sample_service.id) assert json_resp['data']['subject'] == 'subject' + assert json_resp['data']['versions'] == [1] assert json_resp['data']['id'] @@ -234,6 +236,7 @@ def test_should_be_able_to_update_a_template(notify_api, sample_user, sample_ser assert update_response.status_code == 200 update_json_resp = json.loads(update_response.get_data(as_text=True)) assert update_json_resp['data']['content'] == 'my template has new content alert("foo")' + assert update_json_resp['data']['versions'] == [1, 2] def test_should_be_able_to_archive_template(notify_api, sample_user, sample_service, sample_template): @@ -307,7 +310,9 @@ def test_should_be_able_to_get_all_templates_for_a_service(notify_api, sample_us assert response.status_code == 200 update_json_resp = json.loads(response.get_data(as_text=True)) assert update_json_resp['data'][0]['name'] == 'my template 1' + assert update_json_resp['data'][0]['versions'] == [1] assert update_json_resp['data'][1]['name'] == 'my template 2' + assert update_json_resp['data'][1]['versions'] == [1] def test_should_get_only_templates_for_that_service(notify_api, sample_user, service_factory): diff --git a/tests/app/template/test_rest_history.py b/tests/app/template/test_rest_history.py new file mode 100644 index 000000000..8375859c5 --- /dev/null +++ b/tests/app/template/test_rest_history.py @@ -0,0 +1,64 @@ +import json +from flask import url_for +from app.models import Template +from app.dao.templates_dao import dao_update_template +from tests import create_authorization_header + + +def test_template_history_version(notify_api, sample_template): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + auth_header = create_authorization_header() + endpoint = url_for( + 'template.get_template_version', + service_id=sample_template.service.id, + template_id=sample_template.id, + version=1) + resp = client.get( + endpoint, + headers=[('Content-Type', 'application/json'), auth_header] + ) + assert resp.status_code == 200 + json_resp = json.loads(resp.get_data(as_text=True)) + assert json_resp['data']['id'] == str(sample_template.id) + assert json_resp['data']['content'] == sample_template.content + assert json_resp['data']['version'] == 1 + + +def test_previous_template_history_version(notify_api, sample_template): + old_content = sample_template.content + sample_template.content = "New content" + dao_update_template(sample_template) + with notify_api.test_request_context(): + with notify_api.test_client() as client: + auth_header = create_authorization_header() + endpoint = url_for( + 'template.get_template_version', + service_id=sample_template.service.id, + template_id=sample_template.id, + version=1) + resp = client.get( + endpoint, + headers=[('Content-Type', 'application/json'), auth_header] + ) + assert resp.status_code == 200 + json_resp = json.loads(resp.get_data(as_text=True)) + assert json_resp['data']['id'] == str(sample_template.id) + assert json_resp['data']['version'] == 1 + assert json_resp['data']['content'] == old_content + + +def test_404_missing_template_version(notify_api, sample_template): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + auth_header = create_authorization_header() + endpoint = url_for( + 'template.get_template_version', + service_id=sample_template.service.id, + template_id=sample_template.id, + version=2) + resp = client.get( + endpoint, + headers=[('Content-Type', 'application/json'), auth_header] + ) + assert resp.status_code == 404