diff --git a/README.md b/README.md index 30d3f7d2a..2aa3d7217 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,10 @@ GOV.UK Notify admin application. ## First-time setup -Brew is a package manager for OSX. The following command installs brew: -```shell - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -``` - Languages needed - Python 3.4 - [Node](https://nodejs.org/) 5.0.0 or greater - [npm](https://www.npmjs.com/) 3.0.0 or greater -```shell - brew install node imagemagick ghostscript cairo pango -``` [NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing different versions of Node. The following installs `n` and uses the latest diff --git a/app/cloudfoundry_config.py b/app/cloudfoundry_config.py index 88f352212..5f3eaa025 100644 --- a/app/cloudfoundry_config.py +++ b/app/cloudfoundry_config.py @@ -27,6 +27,8 @@ def set_config_env_vars(vcap_services): extract_hosted_graphite_config(s) elif s['name'] == 'deskpro': extract_deskpro_config(s) + elif s['name'] == 'notify-template-preview': + extract_template_preview_config(s) def extract_notify_config(notify_config): @@ -49,3 +51,9 @@ def extract_hosted_graphite_config(hosted_graphite_config): def extract_deskpro_config(deskpro_config): os.environ['DESKPRO_API_HOST'] = deskpro_config['credentials']['api_host'] os.environ['DESKPRO_API_KEY'] = deskpro_config['credentials']['api_key'] + + + +def extract_template_preview_config(template_preview_config): + os.environ['TEMPLATE_PREVIEW_API_HOST'] = template_preview_config['credentials']['api_host'] + os.environ['TEMPLATE_PREVIEW_API_KEY'] = template_preview_config['credentials']['api_key'] diff --git a/app/config.py b/app/config.py index a7b54d2ce..53eb1e8ac 100644 --- a/app/config.py +++ b/app/config.py @@ -20,7 +20,8 @@ class Config(object): # if we're not on cloudfoundry, we can get to this app from localhost. but on cloudfoundry its different ADMIN_BASE_URL = os.environ.get('ADMIN_BASE_URL', 'http://localhost:6012') - TEMPLATE_PREVIEW_SERVICE_URL = os.environ.get('TEMPLATE_PREVIEW_SERVICE_URL', 'http://localhost:6013') + TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013') + TEMPLATE_PREVIEW_API_KEY = os.environ.get('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key') # Hosted graphite statsd prefix STATSD_PREFIX = os.getenv('STATSD_PREFIX') diff --git a/app/main/views/send.py b/app/main/views/send.py index 0dbfab8c2..1e4f388eb 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -299,6 +299,7 @@ def check_messages_preview(service_id, template_type, upload_id, filetype): )['template'] return TemplatePreview.from_utils_template(template, filetype) + @main.route("/services///check/", methods=['POST']) @login_required @user_has_permissions('send_texts', 'send_emails', 'send_letters') diff --git a/app/main/views/templates.py b/app/main/views/templates.py index e78371c2e..54826d5fb 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -87,10 +87,11 @@ def view_template(service_id, template_id): @main.route("/services//templates/.") @login_required @user_has_permissions('view_activity', admin_override=True) -def view_letter_template_as_filetype(service_id, template_id, filetype): +def view_letter_template_preview(service_id, template_id, filetype): db_template = service_api_client.get_service_template(service_id, template_id)['data'] return TemplatePreview.from_database_object(db_template, filetype) + def _view_template_version(service_id, template_id, version, letters_as_pdf=False): return dict(template=get_template( service_api_client.get_service_template(service_id, template_id, version=version)['data'], diff --git a/app/template_previews.py b/app/template_previews.py index 8b4ef6542..e3b5adf6c 100644 --- a/app/template_previews.py +++ b/app/template_previews.py @@ -8,15 +8,14 @@ class TemplatePreview: @classmethod def from_database_object(cls, template, filetype, values=None): data = { - "letter_contact_block": current_service['letter_contact_block'], - "admin_base_url": current_app.config['ADMIN_BASE_URL'], - "template": template, - "values": values + 'letter_contact_block': current_service['letter_contact_block'], + 'template': template, + 'values': values } resp = requests.post( - '{}/preview.{}'.format(current_app.config['TEMPLATE_PREVIEW_SERVICE_URL'], filetype), + '{}/preview.{}'.format(current_app.config['TEMPLATE_PREVIEW_API_HOST'], filetype), json=data, - headers={'Authorization': 'Token my-secret-key'} + headers={'Authorization': 'Token {}'.format(current_app.config['TEMPLATE_PREVIEW_API_KEY'])} ) return (resp.content, resp.status_code, resp.headers.items()) diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index f85470f4a..cea8680c7 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2,14 +2,13 @@ import uuid from io import BytesIO from os import path from glob import glob -import re from itertools import repeat from functools import partial -from unittest.mock import patch import pytest from bs4 import BeautifulSoup from flask import url_for +from notifications_utils.template import LetterPreviewTemplate from app.main.views.send import get_check_messages_back_url @@ -524,18 +523,9 @@ def test_can_start_letters_job( assert response.status_code == 302 -@pytest.mark.parametrize( - 'view, expected_content_type', - [ - ('.check_messages_as_pdf', 'application/pdf'), - ('.check_messages_as_png', 'image/png'), - ] -) -@patch('app.utils.LetterPreviewTemplate.jinja_template.render', return_value='') +@pytest.mark.parametrize('filetype', ['pdf', 'png']) def test_should_show_preview_letter_message( - mock_letter_preview, - view, - expected_content_type, + filetype, logged_in_platform_admin_client, mock_get_service_letter_template, mock_get_users_by_service, @@ -554,6 +544,10 @@ def test_should_show_preview_letter_message( ['123 street, abc123'] ) ) + mocked_preview = mocker.patch( + 'app.main.views.send.TemplatePreview.from_utils_template', + return_value='foo' + ) service_id = service_one['id'] template_id = fake_uuid @@ -565,18 +559,22 @@ def test_should_show_preview_letter_message( 'valid': True } response = logged_in_platform_admin_client.get( - url_for(view, service_id=service_id, template_type='letter', upload_id=fake_uuid) + url_for( + 'main.check_messages_preview', + service_id=service_id, + template_type='letter', + upload_id=fake_uuid, + filetype=filetype + ) ) - assert response.status_code == 200 - assert response.content_type == expected_content_type mock_get_service_letter_template.assert_called_with(service_id, template_id) - assert mock_letter_preview.call_args[0][0]['subject'] == ( - 'Subject' - ) - assert mock_letter_preview.call_args[0][0]['message'] == ( - '

Template <em>content</em> with & entity

' - ) + + assert response.status_code == 200 + assert response.get_data(as_text=True) == 'foo' + assert mocked_preview.call_args[0][0].id == template_id + assert type(mocked_preview.call_args[0][0]) == LetterPreviewTemplate + assert mocked_preview.call_args[0][1] == filetype def test_check_messages_should_revalidate_file_when_uploading_file( diff --git a/tests/app/main/views/test_templates.py b/tests/app/main/views/test_templates.py index d4777468f..bc966ea54 100644 --- a/tests/app/main/views/test_templates.py +++ b/tests/app/main/views/test_templates.py @@ -1,6 +1,5 @@ -from itertools import repeat from datetime import datetime -from unittest.mock import Mock, patch, ANY +from unittest.mock import Mock, ANY import pytest from bs4 import BeautifulSoup @@ -148,44 +147,42 @@ def test_should_show_page_template_with_priority_select_if_platform_admin( mock_get_service_template.assert_called_with('1234', template_id) -@pytest.mark.parametrize('view_suffix, expected_content_type', [ - ('as_pdf', 'application/pdf'), - ('as_png', 'image/png'), -]) +@pytest.mark.parametrize('filetype', ['pdf', 'png']) @pytest.mark.parametrize('view, extra_view_args', [ - ('.view_letter_template', {}), - ('.view_template_version', {'version': 1}), + ('.view_letter_template_preview', {}), + ('.view_template_version_preview', {'version': 1}), ]) -@patch('app.main.views.templates.LetterPreviewTemplate.jinja_template.render', return_value='foo') def test_should_show_preview_letter_templates( - mock_letter_preview, view, extra_view_args, - view_suffix, - expected_content_type, + filetype, logged_in_client, mock_get_service_email_template, - mock_get_user_by_email, service_one, - fake_uuid + fake_uuid, + mocker ): + mocked_preview = mocker.patch( + 'app.main.views.templates.TemplatePreview.from_database_object', + return_value='foo' + ) + service_id, template_id = service_one['id'], fake_uuid + response = logged_in_client.get(url_for( - '{}_{}'.format(view, view_suffix), + view, service_id=service_id, template_id=template_id, + filetype=filetype, **extra_view_args )) assert response.status_code == 200 - assert response.content_type == expected_content_type + assert response.get_data(as_text=True) == 'foo' mock_get_service_email_template.assert_called_with(service_id, template_id, **extra_view_args) - assert mock_letter_preview.call_args[0][0]['subject'] == ( - "Your ((thing)) is due soon" - ) - assert mock_letter_preview.call_args[0][0]['message'] == ( - "

Your vehicle tax expires on ((date))

" - ) + assert mocked_preview.call_args[0][0]['id'] == template_id + assert mocked_preview.call_args[0][0]['service'] == service_id + assert mocked_preview.call_args[0][1] == filetype def test_should_redirect_when_saving_a_template( diff --git a/tests/app/test_cloudfoundry_config.py b/tests/app/test_cloudfoundry_config.py index 5af028ca7..62e8a64da 100644 --- a/tests/app/test_cloudfoundry_config.py +++ b/tests/app/test_cloudfoundry_config.py @@ -52,12 +52,24 @@ def deskpro_config(): } +@pytest.fixture +def template_preview_config(): + return { + 'name': 'notify-template-preview', + 'credentials': { + 'api_host': 'template-preview api host', + 'api_key': 'template-preview api key' + } + } + + @pytest.fixture def cloudfoundry_config( notify_config, aws_config, hosted_graphite_config, deskpro_config, + template_preview_config, ): return { 'user-provided': [ @@ -65,6 +77,7 @@ def cloudfoundry_config( aws_config, hosted_graphite_config, deskpro_config, + template_preview_config, ] } @@ -128,3 +141,11 @@ def test_deskpro_config(): assert os.environ['DESKPRO_API_HOST'] == 'deskpro api host' assert os.environ['DESKPRO_API_KEY'] == 'deskpro api key' + + +@pytest.mark.usefixtures('os_environ', 'cloudfoundry_environ') +def test_template-preview_config(): + extract_cloudfoundry_config() + + assert os.environ['TEMPLATE_PREVIEW_API_HOST'] == 'template-preview api host' + assert os.environ['TEMPLATE_PREVIEW_API_KEY'] == 'template-preview api key' diff --git a/tests/app/test_template_previews.py b/tests/app/test_template_previews.py new file mode 100644 index 000000000..be50e642b --- /dev/null +++ b/tests/app/test_template_previews.py @@ -0,0 +1,35 @@ +from unittest.mock import Mock +from notifications_utils.template import LetterPreviewTemplate + +from app.template_previews import TemplatePreview + + +def test_from_utils_template_calls_through(mocker, mock_get_service_letter_template): + mock_from_db = mocker.patch('app.template_previews.TemplatePreview.from_database_object') + template = LetterPreviewTemplate(mock_get_service_letter_template(None, None)['data']) + + ret = TemplatePreview.from_utils_template(template, 'foo') + + assert ret == mock_from_db.return_value + mock_from_db.assert_called_once_with(template._template, 'foo', template.values) + + +def test_from_database_object_makes_request(mocker, client): + resp = Mock(content='a', status_code='b', headers={'c': 'd'}) + request_mock = mocker.patch('app.template_previews.requests.post', return_value=resp) + mocker.patch('app.template_previews.current_service', __getitem__=Mock(return_value='123')) + + ret = TemplatePreview.from_database_object(template='foo', filetype='bar') + + assert ret[0] == 'a' + assert ret[1] == 'b' + assert list(ret[2]) == [('c', 'd')] + url = 'http://localhost:6013/preview.bar' + data = { + 'letter_contact_block': '123', + 'template': 'foo', + 'values': None + } + headers = {'Authorization': 'Token my-secret-key'} + + request_mock.assert_called_once_with(url, json=data, headers=headers)