def test_compare_template(): with patch('notifications_utils.template_change.TemplateChange.__init__', return_value=None) as mocked: old_template = Template({'content': 'faked', 'template_type': 'sms'}) new_template = Template({'content': 'faked', 'template_type': 'sms'}) template_changes = old_template.compare_to(new_template) mocked.assert_called_once_with(old_template, new_template)
def test_include_placeholder_in_missing_data_if_placeholder_is_conditional( personalisation): template = Template({"content": "((has_name??hello!))"}) template.values = personalisation assert template.missing_data == ['has_name']
def edit_service_template(service_id, template_id): template = service_api_client.get_service_template(service_id, template_id)['data'] template['template_content'] = template['content'] form = form_objects[template['template_type']](**template) if form.validate_on_submit(): subject = form.subject.data if hasattr(form, 'subject') else None new_template = 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) 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, column_headings=list( ascii_uppercase[:len(new_template.placeholders) + 1]), example_rows=[ [first_column_heading[new_template.template_type]] + list(new_template.placeholders), get_example_csv_rows(new_template), get_example_csv_rows(new_template) ], form=form) try: service_api_client.update_service_template( template_id, form.name.data, template['template_type'], form.template_content.data, service_id, subject) except HTTPError as e: if e.status_code == 400: if 'content' in e.message and any([ 'character count greater than' in x for x in e.message['content'] ]): form.template_content.errors.extend(e.message['content']) else: raise e else: raise e else: return redirect( url_for('.view_template', service_id=service_id, template_id=template_id)) return render_template('views/edit-{}-template.html'.format( template['template_type']), form=form, template_id=template_id, template_type=template['template_type'], heading_action='Edit')
def test_random_variable_retrieve(): template = Template({ 'content': 'content', 'template_type': 'sms', 'created_by': "now" }) assert template.get_raw('created_by') == "now" assert template.get_raw('missing', default='random') == 'random' assert template.get_raw('missing') is None
def view_template_versions(service_id, template_id): return render_template( 'views/templates/choose_history.html', template=Template(service_api_client.get_service_template( service_id, template_id)['data'], prefix=current_service['name']), versions=[ Template(template, prefix=current_service['name']) for template in service_api_client.get_service_template_versions( service_id, template_id)['data'] ])
def test_matches_keys_to_placeholder_names(): template = Template({"content": "hello ((name))"}) template.values = {'NAME': 'Chris'} assert template.values == {'name': 'Chris'} template.values = {'NAME': 'Chris', 'Town': 'London'} assert template.values == {'name': 'Chris', 'Town': 'London'} assert template.additional_data == {'Town'} template.values = None assert template.missing_data == ['name']
def add_preview_of_content_to_notifications(notifications): for notification in notifications: if notification['template'].get('redact_personalisation'): notification['personalisation'] = {} if notification['template']['template_type'] == 'sms': yield dict(preview_of_content=str( Template( notification['template'], notification['personalisation'], redact_missing_personalisation=True, )), **notification) else: if notification['template']['is_precompiled_letter']: notification['template']['subject'] = notification[ 'client_reference'] yield dict(preview_of_content=(WithSubjectTemplate( notification['template'], notification['personalisation'], redact_missing_personalisation=True, ).subject), **notification)
def add_preview_of_content_to_notifications(notifications): for notification in notifications: if notification["template"].get("redact_personalisation"): notification["personalisation"] = {} if notification["template"]["template_type"] == "sms": yield dict( preview_of_content=str( Template( notification["template"], notification["personalisation"], redact_missing_personalisation=True, )), **notification, ) else: if notification["template"]["is_precompiled_letter"]: notification["template"]["subject"] = "Provided as PDF" yield dict( preview_of_content=(WithSubjectTemplate( notification["template"], notification["personalisation"], redact_missing_personalisation=True, ).subject), **notification, )
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']))
def styleguide(): if not current_app.config['SHOW_STYLEGUIDE']: abort(404) class FormExamples(Form): username = StringField(u'Username') password = PasswordField(u'Password', [validators.required()]) code = StringField('Enter code') message = TextAreaField(u'Message') file_upload = FileField('Upload a CSV file to add your recipients’ details') sms = "Your vehicle tax for ((registration number)) is due on ((date)). Renew online at www.gov.au/vehicle-tax" form = FormExamples() form.message.data = sms form.validate() template = Template({'content': sms}) return render_template( 'views/styleguide.html', form=form, template=template )
def test_pass_through_renderer(): message = ''' the quick brown fox ''' assert str(Template({'content': message})) == message
def test_passes_through_template_attributes(): assert Template({"content": ''}).name is None assert Template({"content": '', 'name': 'Two week reminder'}).name == 'Two week reminder' assert Template({"content": ''}).id is None assert Template({"content": '', 'id': '1234'}).id == '1234' assert Template({"content": ''}).template_type is None assert Template({"content": '', 'template_type': 'sms'}).template_type is 'sms' assert not hasattr(Template({"content": ''}), 'subject')
def test_basic_templates_return_markup(): template_dict = {'content': 'content', 'subject': 'subject'} for output in [ str(Template(template_dict)), str(WithSubjectTemplate(template_dict)), WithSubjectTemplate(template_dict).subject, ]: assert isinstance(output, Markup)
def get_example_csv(service_id, template_id): template = Template( service_api_client.get_service_template(service_id, template_id)['data']) return Spreadsheet.from_rows( [[first_column_heading[template.template_type]] + list(template.placeholders), get_example_csv_rows(template)]).as_csv_data, 200, { 'Content-Type': 'text/csv; charset=utf-8', 'Content-Disposition': 'inline; filename="{}.csv"'.format(template.name) }
def choose_template(service_id, template_type): if template_type not in ['email', 'sms']: abort(404) return render_template( 'views/templates/choose.html', templates=[ Template(template, prefix=current_service['name'], sms_sender=current_service['sms_sender']) for template in service_api_client.get_service_templates(service_id)['data'] if template['template_type'] == template_type ], template_type=template_type, page_heading=get_page_headings(template_type))
def send_test(service_id, template_id): file_name = current_app.config['TEST_MESSAGE_FILENAME'] template = Template(service_api_client.get_service_template( service_id, template_id)['data'], prefix=current_service['name'], sms_sender=current_service['sms_sender']) if len(template.placeholders) == 0 or request.method == 'POST': upload_id = s3upload( service_id, { 'file_name': file_name, 'data': Spreadsheet.from_rows([ [first_column_heading[template.template_type]] + list(template.placeholders), get_example_csv_rows(template, use_example_as_example=False, submitted_fields=request.form) ]).as_csv_data }, current_app.config['AWS_REGION']) session['upload_data'] = { "template_id": template_id, "original_file_name": file_name } return redirect( url_for('.check_messages', upload_id=upload_id, service_id=service_id, template_type=template.template_type, from_test=True, help=2 if request.args.get('help') else 0)) return render_template( 'views/send-test.html', template=template, recipient_column=first_column_heading[template.template_type], example=[get_example_csv_rows(template, use_example_as_example=False)], help=get_help_argument())
def view_job(service_id, job_id): job = job_api_client.get_job(service_id, job_id)['data'] if job['job_status'] == 'cancelled': abort(404) filter_args = _parse_filter_args(request.args) filter_args['status'] = _set_status_filters(filter_args) total_notifications = job.get('notification_count', 0) processed_notifications = job.get('notifications_delivered', 0) + job.get('notifications_failed', 0) return render_template( 'views/jobs/job.html', finished=(total_notifications == processed_notifications), uploaded_file_name=job['original_file_name'], template=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'] ), status=request.args.get('status', ''), updates_url=url_for( ".view_job_updates", service_id=service_id, job_id=job['id'], status=request.args.get('status', ''), help=get_help_argument() ), partials=get_job_partials(job), help=get_help_argument() )
def send_messages(service_id, template_id): template = Template(service_api_client.get_service_template( service_id, template_id)['data'], prefix=current_service['name'], sms_sender=current_service['sms_sender']) form = CsvUploadForm() if form.validate_on_submit(): try: upload_id = s3upload( service_id, Spreadsheet.from_file( form.file.data, filename=form.file.data.filename).as_dict, current_app.config['AWS_REGION']) session['upload_data'] = { "template_id": template_id, "original_file_name": form.file.data.filename } return redirect( url_for('.check_messages', service_id=service_id, upload_id=upload_id, template_type=template.template_type)) except (UnicodeDecodeError, BadZipFile, XLRDError): flash( 'Couldn’t read {}. Try using a different file format.'.format( form.file.data.filename)) return render_template( 'views/send.html', template=template, column_headings=list(ascii_uppercase[:len(template.placeholders) + 1]), example=[[first_column_heading[template.template_type]] + list(template.placeholders), get_example_csv_rows(template)], form=form)
def styleguide(): if not current_app.config["SHOW_STYLEGUIDE"]: abort(404) class FormExamples(Form): username = StringField("Username") password = PasswordField("Password", [validators.required()]) code = StringField("Enter code") message = TextAreaField("Message") file_upload = FileField( "Upload a CSV file to add your recipients’ details") sms = "Your vehicle tax for ((registration number)) is due on ((date)). Renew online at www.gov.uk/vehicle-tax" form = FormExamples() form.message.data = sms form.validate() template = Template({"content": sms}) return render_template("views/styleguide.html", form=form, template=template)
import pytest from notifications_utils.template import Template from notifications_utils.template_change import TemplateChange @pytest.mark.parametrize("old_template, new_template, should_differ", [ (Template({'content': '((1)) ((2)) ((3))' }), Template({'content': '((1)) ((2)) ((3))'}), False), (Template({'content': '((1)) ((2)) ((3))' }), Template({'content': '((3)) ((2)) ((1))'}), False), (Template({'content': '((1)) ((2)) ((3))'}), Template({'content': '((1)) ((1)) ((2)) ((2)) ((3)) ((3))'}), False), (Template({'content': '((1))'}), Template({'content': '((1)) ((2))' }), True), (Template({'content': '((1)) ((2))'}), Template({'content': '((1))' }), True), (Template({'content': '((a)) ((b))' }), Template({'content': '((A)) (( B_ ))'}), False), ]) def test_checking_for_difference_between_templates(old_template, new_template, should_differ): assert TemplateChange( old_template, new_template).has_different_placeholders == should_differ @pytest.mark.parametrize("old_template, new_template, placeholders_added", [ (Template({'content': '((1)) ((2)) ((3))' }), Template({'content': '((1)) ((2)) ((3))'}), set()), (Template({'content': '((1)) ((2)) ((3))'}), Template({'content': '((1)) ((1)) ((2)) ((2)) ((3)) ((3))'}), set()), (Template({'content': '((1)) ((2)) ((3))'}), Template({'content': '((1))'
def test_errors_for_missing_template_content(): with pytest.raises(KeyError): Template({})
def test_errors_for_invalid_template_types(template): with pytest.raises(TypeError): Template(template)
def check_messages(service_id, template_type, upload_id): if not session.get('upload_data'): return redirect( url_for('main.choose_template', service_id=service_id, template_type=template_type)) users = user_api_client.get_users_for_service(service_id=service_id) statistics = service_api_client.get_detailed_service_for_today( service_id)['data']['statistics'] remaining_messages = (current_service['message_limit'] - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) if not contents: flash('There was a problem reading your upload file') template = Template(service_api_client.get_service_template( service_id, session['upload_data'].get('template_id'))['data'], prefix=current_service['name'], sms_sender=current_service['sms_sender']) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.mobile_number, user.email_address] for user in users) if current_service['restricted'] else None, remaining_messages=remaining_messages) if request.args.get('from_test'): extra_args = { 'help': 1 } if request.args.get('help', '0') != '0' else {} if len(template.placeholders): back_link = url_for('.send_test', service_id=service_id, template_id=template.id, **extra_args) else: back_link = url_for('.choose_template', service_id=service_id, template_type=template.template_type, **extra_args) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() with suppress(StopIteration): template.values = next(recipients.rows) first_recipient = template.values.get( recipients.recipient_column_header, '') session['upload_data']['notification_count'] = len(list(recipients.rows)) session['upload_data']['valid'] = not recipients.has_errors return render_template( 'views/check.html', recipients=recipients, first_recipient=first_recipient, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=session['upload_data']['notification_count'], count_of_displayed_recipients=( len(list(recipients.initial_annotated_rows_with_errors)) if any(recipients.rows_with_errors) and not recipients.missing_column_headers else len( list(recipients.initial_annotated_rows))), original_file_name=session['upload_data'].get('original_file_name'), upload_id=upload_id, form=CsvUploadForm(), remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, help=get_help_argument())
def test_errors_for_invalid_values(values): with pytest.raises(TypeError): Template({"content": ''}, values)
def test_class(): assert repr(Template({"content": "hello ((name))" })) == 'Template("hello ((name))", {})'
def __call__(self, form, field): if ',' in ''.join(Template({'content': field.data}).placeholders): raise ValidationError(self.message)
def test_random_variable_retrieve(): template = Template({"content": "content", "template_type": "sms", "created_by": "now"}) assert template.get_raw("created_by") == "now" assert template.get_raw("missing", default="random") == "random" assert template.get_raw("missing") is None
def test_compare_template(): with patch("notifications_utils.template.TemplateChange.__init__", return_value=None) as mocked: old_template = Template({"content": "faked", "template_type": "sms"}) new_template = Template({"content": "faked", "template_type": "sms"}) template_changes = old_template.compare_to(new_template) mocked.assert_called_once_with(old_template, new_template)
def view_template_version(service_id, template_id, version): return render_template('views/templates/template_history.html', template=Template( service_api_client.get_service_template( service_id, template_id, version)['data'], prefix=current_service['name']))
def view_template(service_id, template_id): return render_template('views/templates/template.html', template=Template( service_api_client.get_service_template( service_id, template_id)['data'], prefix=current_service['name']))
def check_messages(service_id, template_type, upload_id): if not session.get('upload_data'): return redirect(url_for('main.choose_template', service_id=service_id, template_type=template_type)) users = user_api_client.get_users_for_service(service_id=service_id) today = datetime.utcnow().date().strftime('%Y-%m-%d') statistics = statistics_api_client.get_statistics_for_service_for_day(service_id, today) if not statistics: statistics = {} contents = s3download(service_id, upload_id) if not contents: flash('There was a problem reading your upload file') template = service_api_client.get_service_template( service_id, session['upload_data'].get('template_id') )['data'] template = Template( template, prefix=current_service['name'] ) recipients = RecipientCSV( contents, template_type=template.template_type, placeholders=template.placeholders, max_initial_rows_shown=50, max_errors_shown=50, whitelist=itertools.chain.from_iterable( [user.mobile_number, user.email_address] for user in users ) if current_service['restricted'] else None ) if request.args.get('from_test'): extra_args = {'help': 1} if request.args.get('help', '0') != '0' else {} if len(template.placeholders): back_link = url_for( '.send_test', service_id=service_id, template_id=template.id, **extra_args ) else: back_link = url_for( '.choose_template', service_id=service_id, template_type=template.template_type, **extra_args ) else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) with suppress(StopIteration): template.values = next(recipients.rows) first_recipient = template.values.get(recipients.recipient_column_header, '') session['upload_data']['notification_count'] = len(list(recipients.rows)) session['upload_data']['valid'] = not recipients.has_errors return render_template( 'views/check.html', recipients=recipients, first_recipient=first_recipient, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=session['upload_data']['notification_count'], count_of_displayed_recipients=( len(list(recipients.initial_annotated_rows_with_errors)) if any(recipients.rows_with_errors) and not recipients.missing_column_headers else len(list(recipients.initial_annotated_rows)) ), original_file_name=session['upload_data'].get('original_file_name'), upload_id=upload_id, form=CsvUploadForm(), statistics=statistics, back_link=back_link, help=get_help_argument() )