From 6e1267826fc04301dd3035adeb2f2e681144c7ec Mon Sep 17 00:00:00 2001 From: Martyn Inglis Date: Wed, 24 Feb 2016 15:45:46 +0000 Subject: [PATCH 01/20] Removed print statement --- app/main/views/sms.py | 1 - app/notify_client/job_api_client.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/app/main/views/sms.py b/app/main/views/sms.py index a135643f7..0b4815d26 100644 --- a/app/main/views/sms.py +++ b/app/main/views/sms.py @@ -127,7 +127,6 @@ def check_sms(service_id, upload_id): template_id = upload_data.get('template_id') raw_template = templates_dao.get_service_template_or_404(service_id, template_id)['data'] upload_result = _get_rows(contents, raw_template) - print(upload_result) template = Template( raw_template, values=upload_result['rows'][0] if upload_result['valid'] else {}, diff --git a/app/notify_client/job_api_client.py b/app/notify_client/job_api_client.py index 7b7be15c9..17745a109 100644 --- a/app/notify_client/job_api_client.py +++ b/app/notify_client/job_api_client.py @@ -1,4 +1,3 @@ -import uuid from notifications_python_client.base import BaseAPIClient @@ -23,7 +22,6 @@ class JobApiClient(BaseAPIClient): def create_job(self, job_id, service_id, template_id, original_file_name): data = { "id": job_id, - "service": service_id, "template": template_id, "original_file_name": original_file_name, "bucket_name": "service-{}-notify".format(service_id), From 87391f2aa19919e3fcf5875189a75c093052f7aa Mon Sep 17 00:00:00 2001 From: Martyn Inglis Date: Thu, 25 Feb 2016 11:30:09 +0000 Subject: [PATCH 02/20] Renamed header of CSV to be 'to' - matches API --- app/main/views/send.py | 28 ++++++------------- app/templates/views/check-sms.html | 6 ++-- .../app/main/notify_client/test_job_client.py | 1 - 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 91a41fc5f..e9dfeea44 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -1,9 +1,6 @@ import csv import io import uuid -import botocore - -from datetime import date from flask import ( request, @@ -17,7 +14,6 @@ from flask import ( ) from flask_login import login_required, current_user -from werkzeug import secure_filename from notifications_python_client.errors import HTTPError from utils.template import Template, NeededByTemplateError, NoPlaceholderForDataError @@ -32,11 +28,6 @@ from app.main.dao import services_dao from app import job_api_client from app.utils import validate_recipient, InvalidPhoneError, InvalidEmailError -first_column_header = { - 'email': 'email', - 'sms': 'phone' -} - @main.route("/services//send/", methods=['GET']) def choose_template(service_id, template_type): @@ -91,7 +82,7 @@ def send_messages(service_id, template_id): return render_template( 'views/send.html', template=template, - column_headers=[first_column_header[template.template_type]] + template.placeholders_as_markup, + column_headers=['to'] + template.placeholders_as_markup, form=form, service=service, service_id=service_id @@ -105,10 +96,9 @@ def get_example_csv(service_id, template_id): placeholders = list(Template(template).placeholders) output = io.StringIO() writer = csv.writer(output) - writer.writerow([first_column_header[template['template_type']]] + placeholders) + writer.writerow(['to'] + placeholders) writer.writerow([current_user.mobile_number] + ["test {}".format(header) for header in placeholders]) - - return(output.getvalue(), 200, {'Content-Type': 'text/csv; charset=utf-8'}) + return output.getvalue(), 200, {'Content-Type': 'text/csv; charset=utf-8'} @main.route("/services//send//to-self", methods=['GET']) @@ -118,7 +108,7 @@ def send_message_to_self(service_id, template_id): placeholders = list(Template(template).placeholders) output = io.StringIO() writer = csv.writer(output) - writer.writerow([first_column_header[template['template_type']]] + placeholders) + writer.writerow(['to'] + placeholders) writer.writerow([current_user.mobile_number] + ["test {}".format(header) for header in placeholders]) filedata = { 'file_name': 'Test run', @@ -146,19 +136,18 @@ def check_messages(service_id, upload_id): if not contents: flash('There was a problem reading your upload file') raw_template = templates_dao.get_service_template_or_404(service_id, template_id)['data'] - recipient_type = first_column_header[raw_template['template_type']] upload_result = _get_rows(contents, raw_template) session['upload_data']['notification_count'] = len(upload_result['rows']) template = Template( raw_template, values=upload_result['rows'][0] if upload_result['valid'] else {}, - drop_values={recipient_type} + drop_values={'to'} ) return render_template( 'views/check-sms.html', upload_result=upload_result, template=template, - column_headers=[recipient_type] + list( + column_headers=['to'] + list( template.placeholders if upload_result['valid'] else template.placeholders_as_markup ), original_file_name=upload_data.get('original_file_name'), @@ -203,12 +192,11 @@ def _get_rows(contents, raw_template): for row in reader: rows.append(row) try: - recipient_column = first_column_header[raw_template['template_type']] validate_recipient( - row[recipient_column], + row['to'], template_type=raw_template['template_type'] ) - Template(raw_template, values=row, drop_values={recipient_column}).replaced + Template(raw_template, values=row, drop_values={'to'}).replaced except (InvalidEmailError, InvalidPhoneError, NeededByTemplateError, NoPlaceholderForDataError): valid = False return {"valid": valid, "rows": rows} diff --git a/app/templates/views/check-sms.html b/app/templates/views/check-sms.html index e0de38dca..38c793639 100644 --- a/app/templates/views/check-sms.html +++ b/app/templates/views/check-sms.html @@ -53,13 +53,13 @@ caption=original_file_name, field_headings=column_headers ) %} - {% if item.phone|valid_phone_number %} + {% if item.to|valid_phone_number %} {% call field() %} - {{ item.phone }} + {{ item.to }} {% endcall %} {% else %} {% call field(status='missing') %} - {{ item.phone }} + {{ item.to }} {% endcall %} {% endif %} {% for column in template.placeholders %} diff --git a/tests/app/main/notify_client/test_job_client.py b/tests/app/main/notify_client/test_job_client.py index e59b2927a..1eb2be38d 100644 --- a/tests/app/main/notify_client/test_job_client.py +++ b/tests/app/main/notify_client/test_job_client.py @@ -11,7 +11,6 @@ def test_client_creates_job_data_correctly(mocker): expected_data = { "id": job_id, - "service": service_id, "template": template_id, "original_file_name": original_file_name, "bucket_name": "service-{}-notify".format(service_id), From 8d81c4d9846a3ebcf82ea4758f73223203bdd0fc Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 25 Feb 2016 17:34:49 +0000 Subject: [PATCH 03/20] Stub out the send letters page --- app/main/views/send.py | 7 +++++++ app/templates/main_nav.html | 1 + app/templates/views/letters.html | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 app/templates/views/letters.html diff --git a/app/main/views/send.py b/app/main/views/send.py index e9dfeea44..e8631ce84 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -29,6 +29,13 @@ from app import job_api_client from app.utils import validate_recipient, InvalidPhoneError, InvalidEmailError +@main.route("/services//send/letters", methods=['GET']) +def letters_stub(service_id): + return render_template( + 'views/letters.html', service_id=service_id + ) + + @main.route("/services//send/", methods=['GET']) def choose_template(service_id, template_type): diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html index a08a24a4a..f6eef7ae6 100644 --- a/app/templates/main_nav.html +++ b/app/templates/main_nav.html @@ -5,6 +5,7 @@
  • Manage team
  • diff --git a/app/templates/views/letters.html b/app/templates/views/letters.html new file mode 100644 index 000000000..1086f1d50 --- /dev/null +++ b/app/templates/views/letters.html @@ -0,0 +1,17 @@ +{% extends "withnav_template.html" %} + +{% block page_title %} + Send letters – GOV.UK Notify +{% endblock %} + +{% block maincolumn_content %} + +

    + Send letters +

    + +

    + This page is where you would go to send letters. +

    + +{% endblock %} From d53dfec3fd474bbabdceb63eebf01155ea10f1b4 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Fri, 26 Feb 2016 11:46:52 +0000 Subject: [PATCH 04/20] Temporarily remove SASS linting Trying to install gulp-sass-lint fails because some of its dependencies are not met: > npm install gulp-sass-lint > npm ERR! Darwin 15.3.0 > npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "gulp-sass-lint" > npm ERR! node v5.7.0 > npm ERR! npm v3.7.5 > > npm ERR! No compatible version found: lodash.upperfirst@^3.0.0 > npm ERR! Valid install targets: > npm ERR! 4.1.2, 4.1.1, 4.1.0, 4.0.2, 4.0.1, 4.0.0 > npm ERR! This commit removes it until we can work out what the problem is. --- gulpfile.babel.js | 9 +++++---- package.json | 4 +--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 030c5eeb7..6f2356c80 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -103,10 +103,11 @@ gulp.task('watchForChanges', function() { }); gulp.task('lint:sass', () => gulp - .src(paths.src + 'stylesheets/**/*.scss') - .pipe(plugins.sassLint()) - .pipe(plugins.sassLint.format(stylish)) - .pipe(plugins.sassLint.failOnError()) +// Removed until gulp-sass-lint installs cleanly +// .src(paths.src + 'stylesheets/**/*.scss') +// .pipe(plugins.sassLint()) +// .pipe(plugins.sassLint.format(stylish)) +// .pipe(plugins.sassLint.failOnError()) ); gulp.task('lint:js', () => gulp diff --git a/package.json b/package.json index 267f7d7a7..a15a60448 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,8 @@ "gulp-base64": "0.1.3", "gulp-concat": "2.6.0", "gulp-include": "2.1.0", - "gulp-jquery": "1.1.1", "gulp-load-plugins": "1.1.0", - "gulp-sass": "2.1.1", + "gulp-sass": "2.2.0", "gulp-uglify": "1.5.1", "jquery": "1.11.2", "query-command-supported": "1.0.0" @@ -39,7 +38,6 @@ "devDependencies": { "gulp-css-url-adjuster": "0.2.3", "gulp-jshint": "2.0.0", - "gulp-sass-lint": "1.1.1", "jshint": "2.9.1", "jshint-stylish": "2.1.0" } From a51d92c87a7f0d18f1223cefd111b06e47e4a902 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 25 Feb 2016 16:37:39 +0000 Subject: [PATCH 05/20] Consolidate page templates for emails + texts Use one page template for each of: - choosing a message template - adding recipients - checking an email message - looking at a job This commit consolidates the two templates into one, and adds logic to show the SMS message pattern or the email message pattern depending on the type of template. It also gives email templates a bit more width, because the body and the from address tend to be quite long. --- app/main/views/jobs.py | 5 ++- app/main/views/send.py | 19 +++++++--- app/templates/views/check-email.html | 18 ---------- .../views/{check-sms.html => check.html} | 28 +++++++++------ .../views/choose-email-template.html | 36 ------------------- ...sms-template.html => choose-template.html} | 17 ++++++--- app/templates/views/job.html | 21 +++++++---- app/templates/views/send.html | 25 +++++++------ tests/app/main/views/test_jobs.py | 1 + 9 files changed, 80 insertions(+), 90 deletions(-) delete mode 100644 app/templates/views/check-email.html rename app/templates/views/{check-sms.html => check.html} (74%) delete mode 100644 app/templates/views/choose-email-template.html rename app/templates/views/{choose-sms-template.html => choose-template.html} (69%) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index dd5e45e04..15c21e65c 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -13,6 +13,7 @@ from utils.template import Template from app import job_api_client from app.main import main from app.main.dao import templates_dao +from app.main.dao import services_dao now = time.strftime('%H:%M') @@ -37,6 +38,7 @@ def view_jobs(service_id): @main.route("/services//jobs/") @login_required def view_job(service_id, job_id): + service = services_dao.get_service_by_id_or_404(service_id) try: job = job_api_client.get_job(service_id, job_id)['data'] messages = [] @@ -58,7 +60,8 @@ def view_job(service_id, job_id): template=Template( templates_dao.get_service_template_or_404(service_id, job['template'])['data'] ), - service_id=service_id + service_id=service_id, + service=service ) except HTTPError as e: if e.status_code == 404: diff --git a/app/main/views/send.py b/app/main/views/send.py index e9dfeea44..67947df2b 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -28,11 +28,16 @@ from app.main.dao import services_dao from app import job_api_client from app.utils import validate_recipient, InvalidPhoneError, InvalidEmailError +page_headings = { + 'email': 'Send emails', + 'sms': 'Send text messages' +} + @main.route("/services//send/", methods=['GET']) def choose_template(service_id, template_type): - services_dao.get_service_by_id_or_404(service_id) + service = services_dao.get_service_by_id_or_404(service_id) if template_type not in ['email', 'sms']: abort(404) @@ -44,11 +49,14 @@ def choose_template(service_id, template_type): else: raise e return render_template( - 'views/choose-{}-template.html'.format(template_type), + 'views/choose-template.html', templates=[ Template(template) for template in templates_dao.get_service_templates(service_id)['data'] if template['template_type'] == template_type ], + template_type=template_type, + page_heading=page_headings[template_type], + service=service, has_jobs=len(jobs), service_id=service_id ) @@ -130,6 +138,7 @@ def check_messages(service_id, upload_id): upload_data = session['upload_data'] template_id = upload_data.get('template_id') + service = services_dao.get_service_by_id_or_404(service_id) if request.method == 'GET': contents = s3download(service_id, upload_id) @@ -144,14 +153,16 @@ def check_messages(service_id, upload_id): drop_values={'to'} ) return render_template( - 'views/check-sms.html', + 'views/check.html', upload_result=upload_result, template=template, + page_heading=page_headings[template.template_type], column_headers=['to'] + list( template.placeholders if upload_result['valid'] else template.placeholders_as_markup ), original_file_name=upload_data.get('original_file_name'), service_id=service_id, + service=service, form=CsvUploadForm() ) elif request.method == 'POST': @@ -193,7 +204,7 @@ def _get_rows(contents, raw_template): rows.append(row) try: validate_recipient( - row['to'], + row.get('to', ''), template_type=raw_template['template_type'] ) Template(raw_template, values=row, drop_values={'to'}).replaced diff --git a/app/templates/views/check-email.html b/app/templates/views/check-email.html deleted file mode 100644 index 3ca4830bf..000000000 --- a/app/templates/views/check-email.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "withnav_template.html" %} - -{% block page_title %} - Send email – GOV.UK Notify -{% endblock %} - -{% block maincolumn_content %} - -

    Send email

    - -

    This page will be where we check the email messages we're about to send

    - -

    - Send email messages -

    - - -{% endblock %} diff --git a/app/templates/views/check-sms.html b/app/templates/views/check.html similarity index 74% rename from app/templates/views/check-sms.html rename to app/templates/views/check.html index 38c793639..48967ca7a 100644 --- a/app/templates/views/check-sms.html +++ b/app/templates/views/check.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/email-message.html" import email_message %} {% from "components/sms-message.html" import sms_message %} {% from "components/table.html" import list_table, field %} {% from "components/placeholder.html" import placeholder %} @@ -6,7 +7,7 @@ {% from "components/page-footer.html" import page_footer %} {% block page_title %} - Check and confirm – GOV.UK Notify + {{ "Check and confirm" if upload_result.valid else page_heading }} – GOV.UK Notify {% endblock %} {% block maincolumn_content %} @@ -25,18 +26,23 @@ {% endif %}

    - {{ "Check and confirm" if upload_result.valid else "Send text messages" }} + {{ "Check and confirm" if upload_result.valid else page_heading }}

    -
    -
    - {% if template.missing_data or template.additional_data %} - {{ sms_message(template.formatted_as_markup)}} - {% else %} - {{ sms_message(template.replaced)}} - {% endif %} + {% if 'email' == template.template_type %} + {{ email_message( + template.subject, + template, + from_address='{}@notifications.service.gov.uk'.format(service.email_from), + from_name=service.name + )}} + {% elif 'sms' == template.template_type %} +
    +
    + {{ sms_message(template)}} +
    -
    + {% endif %} {% if upload_result.valid %}
    @@ -53,7 +59,7 @@ caption=original_file_name, field_headings=column_headers ) %} - {% if item.to|valid_phone_number %} + {% if item.to or ''|valid_phone_number %} {% call field() %} {{ item.to }} {% endcall %} diff --git a/app/templates/views/choose-email-template.html b/app/templates/views/choose-email-template.html deleted file mode 100644 index 5452a5da8..000000000 --- a/app/templates/views/choose-email-template.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/email-message.html" import email_message %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/textbox.html" import textbox %} - -{% block page_title %} - Send emails – GOV.UK Notify -{% endblock %} - -{% block maincolumn_content %} - -

    Send emails

    - - - - {% if templates %} -
    - {% for template in templates %} -
    - {{ email_message(template.subject, template.formatted_as_markup, name=template.name) }} -
    -
    - -
    - {% endfor %} -
    - {% endif %} - -

    - Add a new template -

    - -
    -{% endblock %} diff --git a/app/templates/views/choose-sms-template.html b/app/templates/views/choose-template.html similarity index 69% rename from app/templates/views/choose-sms-template.html rename to app/templates/views/choose-template.html index 5508ca4fb..7fb87b827 100644 --- a/app/templates/views/choose-sms-template.html +++ b/app/templates/views/choose-template.html @@ -1,15 +1,16 @@ {% extends "withnav_template.html" %} +{% from "components/email-message.html" import email_message %} {% from "components/sms-message.html" import sms_message %} {% from "components/page-footer.html" import page_footer %} {% from "components/textbox.html" import textbox %} {% block page_title %} - Send text messages – GOV.UK Notify + {{ page_heading }} – GOV.UK Notify {% endblock %} {% block maincolumn_content %} -

    Send text messages

    +

    {{ page_heading }}

    @@ -26,7 +27,15 @@
    {% for template in templates %}
    - {{ sms_message(template.formatted_as_markup, name=template.name) }} + {% if 'email' == template_type %} + {{ email_message( + template.subject, + template.formatted_as_markup, + name=template.name + ) }} + {% elif 'sms' == template_type %} + {{ sms_message(template.formatted_as_markup, name=template.name) }} + {% endif %}