diff --git a/README.md b/README.md index 5abc197e7..30d3f7d2a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Languages needed - [Node](https://nodejs.org/) 5.0.0 or greater - [npm](https://www.npmjs.com/) 3.0.0 or greater ```shell - brew install node + brew install node imagemagick ghostscript cairo pango ``` [NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing diff --git a/app/assets/stylesheets/components/letter.scss b/app/assets/stylesheets/components/letter.scss index 009c53286..6af2a50cf 100644 --- a/app/assets/stylesheets/components/letter.scss +++ b/app/assets/stylesheets/components/letter.scss @@ -1,6 +1,7 @@ $outline-width: 5px; .letter { + font-family: Helvetica, Arial, sans-serif; box-shadow: 1px 1px 0 0 $panel-colour, @@ -8,6 +9,16 @@ $outline-width: 5px; -1px 1px 0 0 $panel-colour, -2px 2px 0 0 rgba($panel-colour, 0.5); outline: $outline-width solid rgba($text-colour, 0.1); - padding: 20px; + padding: 0; margin: $outline-width $outline-width $gutter; + + a { + display: block; + } + + img { + display: block; + max-width: 100%; + } + } diff --git a/app/main/views/index.py b/app/main/views/index.py index ca9cbe9cd..642876962 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -3,8 +3,7 @@ from app.main import main from app import convert_to_boolean from flask_login import (login_required, current_user) - -from notifications_utils.renderers import HTMLEmail +from notifications_utils.template import HTMLEmailTemplate @main.route('/') @@ -57,9 +56,7 @@ def terms(): @main.route('/_email') def email_template(): - return HTMLEmail( - govuk_banner=convert_to_boolean(request.args.get('govuk_banner', True)) - )( + return str(HTMLEmailTemplate({'subject': 'foo', 'content': ( 'Lorem Ipsum is simply dummy text of the printing and typesetting ' 'industry.\n\nLorem Ipsum has been the industry’s standard dummy ' 'text ever since the 1500s, when an unknown printer took a galley ' @@ -96,7 +93,8 @@ def email_template(): 'This is an example of an email sent using GOV.UK Notify.' '\n\n' 'https://www.notifications.service.gov.uk' - ) + )}, govuk_banner=convert_to_boolean(request.args.get('govuk_banner', True)) + )) @main.route('/documentation') diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index eed140221..f20978e6e 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -16,7 +16,6 @@ from flask import ( ) from flask_login import login_required from werkzeug.datastructures import MultiDict -from notifications_utils.template import Template from app import ( job_api_client, @@ -31,7 +30,8 @@ from app.utils import ( generate_previous_dict, user_has_permissions, generate_notifications_csv, - get_help_argument + get_help_argument, + get_template, ) from app.statistics_utils import add_rate_to_job @@ -108,14 +108,13 @@ def view_job(service_id, job_id): 'views/jobs/job.html', finished=(total_notifications == processed_notifications), uploaded_file_name=job['original_file_name'], - template=Template( + template=get_template( service_api_client.get_service_template( service_id=service_id, template_id=job['template'], version=job['template_version'] )['data'], - prefix=current_service['name'], - sms_sender=current_service['sms_sender'] + current_service, ), status=request.args.get('status', ''), updates_url=url_for( diff --git a/app/main/views/send.py b/app/main/views/send.py index 281ce0d46..b2aa846be 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -18,7 +18,6 @@ from flask import ( from flask_login import login_required, current_user from notifications_utils.columns import Columns -from notifications_utils.template import Template from notifications_utils.recipients import RecipientCSV, first_column_headings, validate_and_format_phone_number from app.main import main @@ -28,7 +27,7 @@ from app.main.uploader import ( s3download ) from app import job_api_client, service_api_client, current_service, user_api_client -from app.utils import user_has_permissions, get_errors_for_csv, Spreadsheet, get_help_argument, get_renderer +from app.utils import user_has_permissions, get_errors_for_csv, Spreadsheet, get_help_argument, get_template def get_page_headings(template_type): @@ -88,10 +87,8 @@ def choose_template(service_id, template_type): return render_template( 'views/templates/choose.html', templates=[ - Template( - template, - renderer=get_renderer(template_type, current_service, show_recipient=False) - ) for template in service_api_client.get_service_templates(service_id)['data'] + get_template(template, current_service) + for template in service_api_client.get_service_templates(service_id)['data'] if template['template_type'] == template_type ], template_type=template_type, @@ -103,10 +100,12 @@ def choose_template(service_id, template_type): @login_required @user_has_permissions('send_texts', 'send_emails', 'send_letters') def send_messages(service_id, template_id): - template = Template( - service_api_client.get_service_template(service_id, template_id)['data'] + + template = get_template( + service_api_client.get_service_template(service_id, template_id)['data'], + current_service, + show_recipient=True ) - template.renderer = get_renderer(template.template_type, current_service, show_recipient=True) form = CsvUploadForm() if form.validate_on_submit(): @@ -144,7 +143,9 @@ def send_messages(service_id, template_id): @login_required @user_has_permissions('send_texts', 'send_emails', 'send_letters', 'manage_templates', any_=True) def get_example_csv(service_id, template_id): - template = Template(service_api_client.get_service_template(service_id, template_id)['data']) + template = get_template( + service_api_client.get_service_template(service_id, template_id)['data'], current_service + ) return Spreadsheet.from_rows([ first_column_headings[template.template_type] + list(template.placeholders), get_example_csv_rows(template) @@ -161,14 +162,12 @@ def send_test(service_id, template_id): file_name = current_app.config['TEST_MESSAGE_FILENAME'] - template = Template( + template = get_template( service_api_client.get_service_template(service_id, template_id)['data'], - prefix=current_service['name'], - sms_sender=current_service['sms_sender'] + current_service, + show_recipient=True ) - template.renderer = get_renderer(template.template_type, current_service, show_recipient=True) - if len(template.placeholders) == 0 or request.method == 'POST': upload_id = s3upload( service_id, @@ -208,10 +207,8 @@ def send_test(service_id, template_id): def send_from_api(service_id, template_id): return render_template( 'views/send-from-api.html', - template=Template( - service_api_client.get_service_template(service_id, template_id)['data'], - prefix=current_service['name'], - sms_sender=current_service['sms_sender'] + template=get_template( + service_api_client.get_service_template(service_id, template_id)['data'], current_service ) ) @@ -233,15 +230,15 @@ def check_messages(service_id, template_type, upload_id): if not contents: flash('There was a problem reading your upload file') - template = Template( + template = get_template( service_api_client.get_service_template( service_id, session['upload_data'].get('template_id') - )['data'] + )['data'], + current_service, + show_recipient=True ) - template.renderer = get_renderer(template_type, current_service, show_recipient=True) - recipients = RecipientCSV( contents, template_type=template.template_type, diff --git a/app/main/views/templates.py b/app/main/views/templates.py index 3146cbec0..626ebf93e 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -1,16 +1,19 @@ from datetime import datetime, timedelta +from io import BytesIO from string import ascii_uppercase -from flask import request, render_template, redirect, url_for, flash, abort +from flask import request, render_template, redirect, url_for, flash, abort, send_file from flask_login import login_required +from flask_weasyprint import HTML, render_pdf from dateutil.parser import parse +from wand.image import Image -from notifications_utils.template import Template +from notifications_utils.template import LetterPreviewTemplate from notifications_utils.recipients import first_column_headings from notifications_python_client.errors import HTTPError from app.main import main -from app.utils import user_has_permissions, get_renderer +from app.utils import user_has_permissions, get_template from app.main.forms import SMSTemplateForm, EmailTemplateForm, LetterTemplateForm from app.main.views.send import get_example_csv_rows from app import service_api_client, current_service, template_statistics_client @@ -39,18 +42,41 @@ page_headings = { admin_override=True, any_=True ) def view_template(service_id, template_id): - template = Template( - service_api_client.get_service_template(service_id, template_id)['data'] - ) - template.renderer = get_renderer( - template.template_type, current_service, show_recipient=False, expand_emails=True - ) return render_template( 'views/templates/template.html', - template=template + template=get_template( + service_api_client.get_service_template(service_id, template_id)['data'], + current_service, + expand_emails=True + ) ) +@main.route("/services//templates/.pdf") +@login_required +@user_has_permissions('view_activity', admin_override=True) +def view_letter_template_as_pdf(service_id, template_id): + return render_pdf(HTML(string=str( + LetterPreviewTemplate( + service_api_client.get_service_template(service_id, template_id)['data'], + ) + ))) + + +@main.route("/services//templates/.png") +@login_required +@user_has_permissions('view_activity', admin_override=True) +def view_letter_template_as_image(service_id, template_id): + output = BytesIO() + with Image( + blob=view_letter_template_as_pdf(service_id, template_id).get_data() + ) as image: + with image.convert('png') as converted: + converted.save(file=output) + output.seek(0) + return send_file(output, mimetype='image/png') + + @main.route("/services//templates//version/") @login_required @user_has_permissions( @@ -63,15 +89,13 @@ def view_template(service_id, template_id): any_=True ) def view_template_version(service_id, template_id, version): - template = Template( - service_api_client.get_service_template(service_id, template_id, version)['data'] - ) - template.renderer = get_renderer( - template.template_type, current_service, show_recipient=False, expand_emails=True - ) return render_template( 'views/templates/template_history.html', - template=template + template=get_template( + service_api_client.get_service_template(service_id, template_id, version)['data'], + current_service, + expand_emails=True + ) ) @@ -125,19 +149,23 @@ def edit_service_template(service_id, template_id): if form.validate_on_submit(): subject = form.subject.data if hasattr(form, 'subject') else None - new_template = Template({ + new_template = get_template({ 'name': form.name.data, 'content': form.template_content.data, 'subject': subject, 'template_type': template['template_type'], 'id': template['id'] - }) - template_change = Template(template).compare_to(new_template) + }, current_service) + template_change = get_template(template, current_service).compare_to(new_template) if template_change.has_different_placeholders and not request.form.get('confirm'): return render_template( 'views/templates/breaking-change.html', template_change=template_change, - new_template=new_template, + new_template={ + 'name': form.name.data, + 'subject': subject, + 'content': form.template_content.data, + }, column_headings=list(ascii_uppercase[:len(new_template.placeholders) + 1]), example_rows=[ first_column_headings[new_template.template_type] + list(new_template.placeholders), @@ -231,18 +259,12 @@ def delete_service_template(service_id, template_id): any_=True ) def view_template_versions(service_id, template_id): - - versions = [] - for template in service_api_client.get_service_template_versions(service_id, template_id)['data']: - template = Template(template) - template.renderer = get_renderer( - template.template_type, current_service, show_recipient=False, expand_emails=True - ) - versions.append(template) - return render_template( 'views/templates/choose_history.html', - versions=versions + versions=[ + get_template(template, current_service, expand_emails=True) + for template in service_api_client.get_service_template_versions(service_id, template_id)['data'] + ] ) diff --git a/app/templates/views/check.html b/app/templates/views/check.html index 79b9527ca..0d013a4a2 100644 --- a/app/templates/views/check.html +++ b/app/templates/views/check.html @@ -127,7 +127,7 @@ {% endif %} - {{ template.rendered }} + {{ template|string }} {% if errors %} {% if request.args.from_test %} diff --git a/app/templates/views/jobs/job.html b/app/templates/views/jobs/job.html index 70388542d..4c40370b8 100644 --- a/app/templates/views/jobs/job.html +++ b/app/templates/views/jobs/job.html @@ -12,7 +12,7 @@ {{ uploaded_file_name }} - {{ template.rendered }} + {{ template|string }} {{ ajax_block(partials, updates_url, 'status', finished=finished) }} {{ ajax_block(partials, updates_url, 'counts', finished=finished) }} diff --git a/app/templates/views/send-from-api.html b/app/templates/views/send-from-api.html index 34bc0cd13..667316dcb 100644 --- a/app/templates/views/send-from-api.html +++ b/app/templates/views/send-from-api.html @@ -11,7 +11,7 @@ API info - {{ template.rendered }} + {{ template|string }}
{{ api_key(template.id, name="Template ID", thing='template ID') }} diff --git a/app/templates/views/send-test.html b/app/templates/views/send-test.html index 2c2820116..c801e08dc 100644 --- a/app/templates/views/send-test.html +++ b/app/templates/views/send-test.html @@ -19,7 +19,7 @@

Send yourself a test

{% endif %} - {{ template.rendered }} + {{ template|string }}
{% call(item, row_number) list_table( diff --git a/app/templates/views/send.html b/app/templates/views/send.html index e0a2eb9ba..847be9b0a 100644 --- a/app/templates/views/send.html +++ b/app/templates/views/send.html @@ -11,7 +11,7 @@

Upload recipients

- {{ template.rendered }} + {{ template|string }}