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=get_template( service_api_client.get_service_template( service_id=service_id, template_id=job["template"], version=job["template_version"] )["data"], current_service, ), 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 get_back_link(service_id, template_id, step_index): if get_help_argument(): # if we're on the check page, redirect back to the beginning. anywhere else, don't return the back link if request.endpoint == 'main.check_notification': return url_for( 'main.send_test', service_id=service_id, template_id=template_id, help=get_help_argument() ) else: return None elif step_index == 0: return url_for( '.view_template', service_id=service_id, template_id=template_id, ) else: return url_for( request.endpoint, service_id=service_id, template_id=template_id, step_index=step_index - 1, )
def get_back_link(service_id, template_id, step_index): if get_help_argument(): # if we're on the check page, redirect back to the beginning. anywhere else, don't return the back link if request.endpoint == 'main.check_notification': return url_for('main.send_test', service_id=service_id, template_id=template_id, help=get_help_argument()) else: return None elif step_index == 0: if current_user.has_permissions('view_activity'): return url_for( '.view_template', service_id=service_id, template_id=template_id, ) else: return url_for( '.choose_template', service_id=service_id, ) else: return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template_id, step_index=step_index - 1, )
def view_job(service_id, job_id): job = job_api_client.get_job(service_id, job_id)['data'] filter_args = _parse_filter_args(request.args) filter_args['status'] = _set_status_filters(filter_args) return render_template( 'views/jobs/job.html', finished=job.get('notifications_sent', 0) and (( job.get('notifications_sent', 0) - job.get('notifications_delivered', 0) - job.get('notifications_failed', 0) ) == 0), 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'] ), 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 get_back_link(service_id, template, step_index): if get_help_argument(): # if we're on the check page, redirect back to the beginning. anywhere else, don't return the back link if request.endpoint == 'main.check_notification': return url_for( 'main.send_test', service_id=service_id, template_id=template.id, help=get_help_argument() ) else: if step_index == 0: return url_for( 'main.start_tour', service_id=service_id, template_id=template.id, ) elif step_index > 0: return url_for( 'main.send_test_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, help=2, ) elif step_index == 0: if should_skip_template_page(template.template_type): return url_for( '.choose_template', service_id=service_id, ) else: return url_for( '.view_template', service_id=service_id, template_id=template.id, ) elif is_current_user_the_recipient() and step_index > 1: return url_for( 'main.send_test_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, ) elif is_current_user_the_recipient() and step_index == 1: return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template.id, step_index=0, ) else: return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, )
def get_back_link(service_id, template, step_index): if get_help_argument(): if request.endpoint == "main.check_notification": return url_for( "main.send_test", service_id=service_id, template_id=template.id, help=get_help_argument(), ) else: if step_index == 0: return url_for( "main.start_tour", service_id=service_id, template_id=template.id, ) elif step_index > 0: return url_for( "main.send_test_step", service_id=service_id, template_id=template.id, step_index=step_index - 1, help=2, ) elif is_current_user_the_recipient() and step_index > 0: return url_for( "main.send_test_step", service_id=service_id, template_id=template.id, step_index=step_index - 1, ) elif is_current_user_the_recipient() and step_index == 0: return url_for( "main.view_template", service_id=service_id, template_id=template.id, ) elif step_index == 0: if should_skip_template_page(template.template_type): return url_for( ".choose_template", service_id=service_id, ) else: return url_for( ".view_template", service_id=service_id, template_id=template.id, ) else: return url_for( "main.send_one_off_step", service_id=service_id, template_id=template.id, step_index=step_index - 1, )
def view_notification(service_id, notification_id): notification = notification_api_client.get_notification( service_id, str(notification_id)) notification['template'].update( {'reply_to_text': notification['reply_to_text']}) if notification['template']['is_precompiled_letter']: file_contents = view_letter_notification_as_preview( service_id, notification_id, "pdf") page_count = pdf_page_count(io.BytesIO(file_contents)) else: page_count = get_page_count_for_letter(notification['template']) template = get_template( notification['template'], current_service, letter_preview_url=url_for( '.view_letter_notification_as_preview', service_id=service_id, notification_id=notification_id, filetype='png', ), page_count=page_count, show_recipient=True, redact_missing_personalisation=True, ) template.values = get_all_personalisation_from_notification(notification) if notification['job']: job = job_api_client.get_job(service_id, notification['job']['id'])['data'] else: job = None return render_template( 'views/notifications/notification.html', finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)), uploaded_file_name='Report', template=template, job=job, updates_url=url_for(".view_notification_updates", service_id=service_id, notification_id=notification['id'], status=request.args.get('status'), help=get_help_argument()), partials=get_single_notification_partials(notification), created_by=notification.get('created_by'), created_at=notification['created_at'], help=get_help_argument(), estimated_letter_delivery_date=get_letter_timings( notification['created_at']).earliest_delivery, notification_id=notification['id'], can_receive_inbound=(current_service.has_permission('inbound_sms')), is_precompiled_letter=notification['template'] ['is_precompiled_letter'])
def get_job_partials(job): filter_args = _parse_filter_args(request.args) filter_args['status'] = _set_status_filters(filter_args) notifications = notification_api_client.get_notifications_for_service( job['service'], job['id'], status=filter_args['status'] ) return { 'counts': render_template( 'partials/jobs/count.html', counts=_get_job_counts(job, request.args.get('help', 0)), status=filter_args['status'] ), 'notifications': render_template( 'partials/jobs/notifications.html', notifications=notifications['notifications'], more_than_one_page=bool(notifications.get('links', {}).get('next')), percentage_complete=(job['notifications_requested'] / job['notification_count'] * 100), download_link=url_for( '.view_job_csv', service_id=current_service['id'], job_id=job['id'], status=request.args.get('status') ), help=get_help_argument(), time_left=get_time_left(job['created_at']), job=job ), 'status': render_template( 'partials/jobs/status.html', job=job ), }
def send_test(service_id, template_id): session["recipient"] = None session["placeholders"] = {} session["send_test_letter_page_count"] = None db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) if db_template["template_type"] == "letter": session["sender_id"] = None if email_or_sms_not_enabled(db_template["template_type"], current_service.permissions): return redirect( url_for( ".action_blocked", service_id=service_id, notification_type=db_template["template_type"], return_to="view_template", template_id=template_id, )) return redirect( url_for( { "main.send_test": ".send_test_step", "main.send_one_off": ".send_one_off_step", }[request.endpoint], service_id=service_id, template_id=template_id, step_index=0, help=get_help_argument(), ))
def get_job_partials(job): filter_args = _parse_filter_args(request.args) filter_args["status"] = _set_status_filters(filter_args) notifications = notification_api_client.get_notifications_for_service( job["service"], job["id"], status=filter_args["status"] ) return { "counts": render_template( "partials/jobs/count.html", counts=_get_job_counts(job, request.args.get("help", 0)), status=filter_args["status"], ), "notifications": render_template( "partials/jobs/notifications.html", notifications=notifications["notifications"], more_than_one_page=bool(notifications.get("links", {}).get("next")), percentage_complete=(job["notifications_requested"] / job["notification_count"] * 100), download_link=url_for( ".view_job_csv", service_id=current_service["id"], job_id=job["id"], status=request.args.get("status") ), help=get_help_argument(), time_left=get_time_left(job["created_at"]), job=job, ), "status": render_template("partials/jobs/status.html", job=job), }
def send_test(service_id, template_id): session['recipient'] = None session['placeholders'] = {} session['send_test_letter_page_count'] = None db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) if db_template['template_type'] == 'letter': session['sender_id'] = None if email_or_sms_not_enabled(db_template['template_type'], current_service.permissions): return redirect( url_for('.action_blocked', service_id=service_id, notification_type=db_template['template_type'], return_to='view_template', template_id=template_id)) return redirect( url_for( { 'main.send_test': '.send_test_step', 'main.send_one_off': '.send_one_off_step', }[request.endpoint], service_id=service_id, template_id=template_id, step_index=0, help=get_help_argument(), ))
def _check_notification(service_id, template_id, exception=None): db_template = service_api_client.get_service_template(service_id, template_id)['data'] email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session(service_id) elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session(service_id) template = get_template( db_template, current_service, show_recipient=True, email_reply_to=email_reply_to, sms_sender=sms_sender ) # go back to start of process back_link = get_back_link(service_id, template_id, 0) if ( not session.get('recipient') or not all_placeholders_in_session(template.placeholders) ): return redirect(back_link) template.values = get_recipient_and_placeholders_from_session(template.template_type) return render_template( 'views/notifications/check.html', template=template, back_link=back_link, help=get_help_argument(), **(get_template_error_dict(exception) if exception else {}) )
def get_job_partials(job): filter_args = _parse_filter_args(request.args) filter_args['status'] = _set_status_filters(filter_args) notifications = notification_api_client.get_notifications_for_service( job['service'], job['id'], status=filter_args['status'] ) return { 'counts': render_template( 'partials/jobs/count.html', job=job, counts=_get_job_counts(job, request.args.get('help', 0)), status=filter_args['status'] ), 'notifications': render_template( 'partials/jobs/notifications.html', notifications=notifications['notifications'], more_than_one_page=bool(notifications.get('links', {}).get('next')), percentage_complete=(job['notifications_sent'] / job['notification_count'] * 100), download_link=url_for( '.view_job_csv', service_id=current_service['id'], job_id=job['id'], status=request.args.get('status') ), help=get_help_argument(), time_left=get_time_left(job['created_at']) ), 'status': render_template( 'partials/jobs/status.html', job=job ), }
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 make_and_upload_csv_file(service_id, template): upload_id = s3upload( service_id, Spreadsheet.from_dict( session['placeholders'], filename=current_app.config['TEST_MESSAGE_FILENAME']).as_dict, current_app.config['AWS_REGION'], ) return redirect( url_for('.check_messages', upload_id=upload_id, service_id=service_id, template_id=template.id, from_test=True, help=2 if get_help_argument() else 0))
def _check_notification(service_id, template_id, exception=None): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() template = get_template( db_template, current_service, show_recipient=True, email_reply_to=email_reply_to, sms_sender=sms_sender, letter_preview_url=url_for( 'no_cookie.check_notification_preview', service_id=service_id, template_id=template_id, filetype='png', ), page_count=get_page_count_for_letter(db_template), ) placeholders = fields_to_fill_in(template) back_link = get_back_link(service_id, template, len(placeholders), placeholders) if ((not session.get('recipient') and db_template['template_type'] != 'letter') or not all_placeholders_in_session(template.placeholders)): raise PermanentRedirect(back_link) template.values = get_recipient_and_placeholders_from_session( template.template_type) page_count = get_page_count_for_letter(db_template, template.values) template.page_count = page_count return dict( template=template, back_link=back_link, help=get_help_argument(), letter_too_long=is_letter_too_long(page_count), letter_max_pages=LETTER_MAX_PAGE_COUNT, page_count=page_count, **(get_template_error_dict(exception) if exception else {}), )
def _check_notification(service_id, template_id, exception=None): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template["template_type"] == "email": email_reply_to = get_email_reply_to_address_from_session() elif db_template["template_type"] == "sms": sms_sender = get_sms_sender_from_session() template = get_template( db_template, current_service, show_recipient=True, email_reply_to=email_reply_to, sms_sender=sms_sender, letter_preview_url=url_for( ".check_notification_preview", service_id=service_id, template_id=template_id, filetype="png", ), page_count=get_page_count_for_letter(db_template), ) step_index = len( fields_to_fill_in( template, prefill_current_user=( session.get("send_step") == "main.send_test_step"), )) back_link = get_back_link(service_id, template, step_index) if (not session.get("recipient") and db_template["template_type"] != "letter" ) or not all_placeholders_in_session(template.placeholders): raise PermanentRedirect(back_link) template.values = get_recipient_and_placeholders_from_session( template.template_type) return dict( template=template, back_link=back_link, help=get_help_argument(), **(get_template_error_dict(exception) if exception else {}), )
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 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'] ) 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 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 send_test_step(service_id, template_id, step_index): if {"recipient", "placeholders"} - set(session.keys()): return redirect( url_for( { "main.send_test_step": ".send_test", "main.send_one_off_step": ".send_one_off", }[request.endpoint], service_id=service_id, template_id=template_id, )) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) if not session.get("send_test_letter_page_count"): session["send_test_letter_page_count"] = get_page_count_for_letter( db_template) email_reply_to = None sms_sender = None if db_template["template_type"] == "email": email_reply_to = get_email_reply_to_address_from_session() elif db_template["template_type"] == "sms": sms_sender = get_sms_sender_from_session() template = get_template( db_template, current_service, show_recipient=True, letter_preview_url=url_for( ".send_test_preview", service_id=service_id, template_id=template_id, filetype="png", ), page_count=session["send_test_letter_page_count"], email_reply_to=email_reply_to, sms_sender=sms_sender, ) placeholders = fields_to_fill_in( template, prefill_current_user=(request.endpoint == "main.send_test_step"), ) # used to set the back link in the check_notification screen session["send_step"] = request.endpoint try: current_placeholder = placeholders[step_index] except IndexError: if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( { "main.send_test_step": ".send_test", "main.send_one_off_step": ".send_one_off", }[request.endpoint], service_id=service_id, template_id=template_id, )) optional_placeholder = current_placeholder in optional_address_columns form = get_placeholder_form_instance( current_placeholder, dict_to_populate_from=get_normalised_placeholders_from_session(), template_type=template.template_type, optional_placeholder=optional_placeholder, allow_international_phone_numbers=current_service.has_permission( "international_sms"), ) if form.validate_on_submit(): # if it's the first input (phone/email), we store against `recipient` as well, for easier extraction. # Only if it's not a letter. # And only if we're not on the test route, since that will already have the user's own number set if step_index == 0 and template.template_type != "letter" and request.endpoint != "main.send_test_step": session["recipient"] = form.placeholder_value.data session["placeholders"][ current_placeholder] = form.placeholder_value.data if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( request.endpoint, service_id=service_id, template_id=template_id, step_index=step_index + 1, help=get_help_argument(), )) back_link = get_back_link(service_id, template, step_index) template.values = get_recipient_and_placeholders_from_session( template.template_type) template.values[current_placeholder] = None return render_template( "views/send-test.html", page_title=get_send_test_page_title( template.template_type, get_help_argument(), entering_recipient=not session["recipient"], ), template=template, form=form, optional_placeholder=optional_placeholder, back_link=back_link, help=get_help_argument(), link_to_upload=(request.endpoint == "main.send_one_off_step" and step_index == 0), bulk_send_allowed=service_can_bulk_send(service_id), )
def get_back_link(service_id, template, step_index, placeholders=None): if get_help_argument(): # if we're on the check page, redirect back to the beginning. anywhere else, don't return the back link if request.endpoint == 'main.check_notification': return url_for('main.send_test', service_id=service_id, template_id=template.id, help=get_help_argument()) else: if step_index == 0: return url_for( 'main.start_tour', service_id=service_id, template_id=template.id, ) elif step_index > 0: return url_for( 'main.send_test_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, help=2, ) elif step_index == 0: if should_skip_template_page(template.template_type): return url_for( '.choose_template', service_id=service_id, ) else: return url_for( '.view_template', service_id=service_id, template_id=template.id, ) elif is_current_user_the_recipient() and step_index > 1: return url_for( 'main.send_test_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, ) elif is_current_user_the_recipient() and step_index == 1: return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template.id, step_index=0, ) if template.template_type == 'letter' and placeholders: # Make sure we’re not redirecting users to a page which will # just redirect them forwards again back_link_destination_step_index = next( (index for index, placeholder in reversed( list(enumerate(placeholders[:step_index]))) if placeholder not in Columns(PostalAddress('').as_personalisation)), 1) return get_back_link(service_id, template, back_link_destination_step_index + 1) return url_for( 'main.send_one_off_step', service_id=service_id, template_id=template.id, step_index=step_index - 1, )
def _check_messages(service_id, template_type, upload_id, preview_row, letters_as_pdf=False): if not session.get('upload_data'): # if we just return a `redirect` (302) object here, we'll get errors when we try and unpack in the # check_messages route - so raise a werkzeug.routing redirect to ensure that doesn't happen. # NOTE: this is a 301 MOVED PERMANENTLY (httpstatus.es/301), so the browser will cache this redirect, and it'll # *always* happen for that browser. _check_messages is only used by endpoints that contain `upload_id`, which # is a one-time-use id (that ties to a given file in S3 that is already deleted if it's not in the session) raise RequestRedirect(url_for('main.choose_template', service_id=service_id)) 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) email_reply_to = None sms_sender = None if template_type == 'email': email_reply_to = get_email_reply_to_address_from_session(service_id) elif template_type == 'sms': sms_sender = get_sms_sender_from_session(service_id) template = get_template( service_api_client.get_service_template( service_id, session['upload_data'].get('template_id') )['data'], current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_type=template_type, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=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.name, user.mobile_number, user.email_address] for user in users ) if current_service['restricted'] else None, remaining_messages=remaining_messages, international_sms='international_sms' in current_service['permissions'], ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() count_of_recipients = len(list(recipients.rows)) if preview_row < 2: abort(404) if preview_row < count_of_recipients + 2: template.values = recipients[preview_row - 2] elif preview_row > 2: abort(404) session['upload_data']['notification_count'] = count_of_recipients session['upload_data']['valid'] = not recipients.has_errors return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=count_of_recipients, 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(), trying_to_send_letters_in_trial_mode=all(( current_service['restricted'], template.template_type == 'letter', not request.args.get('from_test'), )), required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, )
def send_test_step(service_id, template_id, step_index): if {'recipient', 'placeholders'} - set(session.keys()): return redirect( url_for( { 'main.send_test_step': '.send_test', 'main.send_one_off_step': '.send_one_off', }[request.endpoint], service_id=service_id, template_id=template_id, )) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) if not session.get('send_test_letter_page_count'): session['send_test_letter_page_count'] = get_page_count_for_letter( db_template) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() template = get_template(db_template, current_service, show_recipient=True, letter_preview_url=url_for( '.send_test_preview', service_id=service_id, template_id=template_id, filetype='png', ), page_count=session['send_test_letter_page_count'], email_reply_to=email_reply_to, sms_sender=sms_sender) placeholders = fields_to_fill_in( template, prefill_current_user=(request.endpoint == 'main.send_test_step'), ) # used to set the back link in the check_notification screen session['send_step'] = request.endpoint try: current_placeholder = placeholders[step_index] except IndexError: if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( { 'main.send_test_step': '.send_test', 'main.send_one_off_step': '.send_one_off', }[request.endpoint], service_id=service_id, template_id=template_id, )) optional_placeholder = (current_placeholder in optional_address_columns) form = get_placeholder_form_instance( current_placeholder, dict_to_populate_from=get_normalised_placeholders_from_session(), template_type=template.template_type, optional_placeholder=optional_placeholder, allow_international_phone_numbers=current_service.has_permission( 'international_sms'), ) if form.validate_on_submit(): # if it's the first input (phone/email), we store against `recipient` as well, for easier extraction. # Only if it's not a letter. # And only if we're not on the test route, since that will already have the user's own number set if (step_index == 0 and template.template_type != 'letter' and request.endpoint != 'main.send_test_step'): session['recipient'] = form.placeholder_value.data session['placeholders'][ current_placeholder] = form.placeholder_value.data if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( request.endpoint, service_id=service_id, template_id=template_id, step_index=step_index + 1, help=get_help_argument(), )) back_link = get_back_link(service_id, template, step_index) template.values = get_recipient_and_placeholders_from_session( template.template_type) template.values[current_placeholder] = None if (request.endpoint == 'main.send_one_off_step' and step_index == 0 and template.template_type != 'letter' and not (template.template_type == 'sms' and current_user.mobile_number is None) and current_user.has_permissions('manage_templates', 'manage_service')): type = first_column_headings[template.template_type][0] if (type == "email address"): type = _l("email address") elif (type == "phone number"): type = _l("phone number") skip_link = ( '{} {}'.format(_l("Use my"), type), url_for('.send_test', service_id=service_id, template_id=template.id), ) else: skip_link = None return render_template( 'views/send-test.html', page_title=get_send_test_page_title( template.template_type, get_help_argument(), entering_recipient=not session['recipient'], name=template.name, ), template=template, form=form, skip_link=skip_link, optional_placeholder=optional_placeholder, back_link=back_link, help=get_help_argument(), link_to_upload=(request.endpoint == 'main.send_one_off_step' and step_index == 0), )
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() )
def view_notification(service_id, notification_id): notification = notification_api_client.get_notification( service_id, str(notification_id)) notification['template'].update( {'reply_to_text': notification['reply_to_text']}) personalisation = get_all_personalisation_from_notification(notification) if notification['template']['is_precompiled_letter']: try: file_contents = view_letter_notification_as_preview( service_id, notification_id, "pdf") page_count = pdf_page_count(io.BytesIO(file_contents)) except PdfReadError: return render_template( 'views/notifications/invalid_precompiled_letter.html', created_at=notification['created_at']) else: page_count = get_page_count_for_letter(notification['template'], values=personalisation) if notification.get('postage'): notification['template']['postage'] = notification['postage'] template = get_template( notification['template'], current_service, letter_preview_url=url_for( '.view_letter_notification_as_preview', service_id=service_id, notification_id=notification_id, filetype='png', ), page_count=page_count, show_recipient=True, redact_missing_personalisation=True, ) template.values = personalisation if notification['job']: job = job_api_client.get_job(service_id, notification['job']['id'])['data'] else: job = None letter_print_day = get_letter_printing_statement( notification['status'], notification['created_at']) notification_created = parser.parse( notification['created_at']).replace(tzinfo=None) show_cancel_button = notification['notification_type'] == 'letter' and \ letter_can_be_cancelled(notification['status'], notification_created) if get_help_argument() or request.args.get('help') == '0': # help=0 is set when you’ve just sent a notification. We # only want to show the back link when you’ve navigated to a # notification, not when you’ve just sent it. back_link = None elif request.args.get('from_job'): back_link = url_for( 'main.view_job', service_id=current_service.id, job_id=request.args.get('from_job'), ) else: back_link = url_for( 'main.view_notifications', service_id=current_service.id, message_type=template.template_type, status='sending,delivered,failed', ) return render_template( 'views/notifications/notification.html', finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)), notification_status=notification['status'], uploaded_file_name='Report', template=template, job=job, updates_url=url_for(".view_notification_updates", service_id=service_id, notification_id=notification['id'], status=request.args.get('status'), help=get_help_argument()), partials=get_single_notification_partials(notification), created_by=notification.get('created_by'), created_at=notification['created_at'], updated_at=notification['updated_at'], help=get_help_argument(), estimated_letter_delivery_date=get_letter_timings( notification['created_at'], postage=notification['postage']).earliest_delivery, notification_id=notification['id'], postage=notification['postage'], can_receive_inbound=(current_service.has_permission('inbound_sms')), is_precompiled_letter=notification['template'] ['is_precompiled_letter'], letter_print_day=letter_print_day, show_cancel_button=show_cancel_button, sent_with_test_key=(notification.get('key_type') == KEY_TYPE_TEST), back_link=back_link, )
def send_test_step(service_id, template_id, step_index): if {'recipient', 'placeholders'} - set(session.keys()): return redirect( url_for( { 'main.send_test_step': '.send_test', 'main.send_one_off_step': '.send_one_off', }[request.endpoint], service_id=service_id, template_id=template_id, )) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() template = get_template(db_template, current_service, show_recipient=True, letter_preview_url=url_for( 'no_cookie.send_test_preview', service_id=service_id, template_id=template_id, filetype='png', ), page_count=get_page_count_for_letter(db_template), email_reply_to=email_reply_to, sms_sender=sms_sender) placeholders = fields_to_fill_in( template, prefill_current_user=(request.endpoint == 'main.send_test_step'), ) try: current_placeholder = placeholders[step_index] except IndexError: if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( { 'main.send_test_step': '.send_test', 'main.send_one_off_step': '.send_one_off', }[request.endpoint], service_id=service_id, template_id=template_id, )) # if we're in a letter, we should show address block rather than "address line #" or "postcode" if template.template_type == 'letter': if step_index < len(address_lines_1_to_6_and_postcode_keys): return redirect( url_for( '.send_one_off_letter_address', service_id=service_id, template_id=template_id, )) if current_placeholder in Columns( PostalAddress('').as_personalisation): return redirect( url_for( request.endpoint, service_id=service_id, template_id=template_id, step_index=step_index + 1, help=get_help_argument(), )) form = get_placeholder_form_instance( current_placeholder, dict_to_populate_from=get_normalised_placeholders_from_session(), template_type=template.template_type, allow_international_phone_numbers=current_service.has_permission( 'international_sms'), ) if form.validate_on_submit(): # if it's the first input (phone/email), we store against `recipient` as well, for easier extraction. # Only if it's not a letter. # And only if we're not on the test route, since that will already have the user's own number set if (step_index == 0 and template.template_type != 'letter' and request.endpoint != 'main.send_test_step'): session['recipient'] = form.placeholder_value.data session['placeholders'][ current_placeholder] = form.placeholder_value.data if all_placeholders_in_session(placeholders): return get_notification_check_endpoint(service_id, template) return redirect( url_for( request.endpoint, service_id=service_id, template_id=template_id, step_index=step_index + 1, help=get_help_argument(), )) back_link = get_back_link(service_id, template, step_index, placeholders) template.values = get_recipient_and_placeholders_from_session( template.template_type) template.values[current_placeholder] = None return render_template( 'views/send-test.html', page_title=get_send_test_page_title( template.template_type, get_help_argument(), entering_recipient=not session['recipient'], name=template.name, ), template=template, form=form, skip_link=get_skip_link(step_index, template), back_link=back_link, help=get_help_argument(), link_to_upload=(request.endpoint == 'main.send_one_off_step' and step_index == 0), )
def view_notification(service_id, notification_id): notification = notification_api_client.get_notification(service_id, str(notification_id)) notification["template"].update({"reply_to_text": notification["reply_to_text"]}) personalisation = get_all_personalisation_from_notification(notification) if notification["template"]["is_precompiled_letter"]: try: file_contents = view_letter_notification_as_preview(service_id, notification_id, "pdf") page_count = pdf_page_count(io.BytesIO(file_contents)) except PdfReadError: return render_template( "views/notifications/invalid_precompiled_letter.html", created_at=notification["created_at"], ) else: page_count = get_page_count_for_letter(notification["template"], values=personalisation) if notification.get("postage"): notification["template"]["postage"] = notification["postage"] template = get_template( notification["template"], current_service, letter_preview_url=url_for( ".view_letter_notification_as_preview", service_id=service_id, notification_id=notification_id, filetype="png", ), page_count=page_count, show_recipient=True, redact_missing_personalisation=True, ) template.values = personalisation if notification["job"]: job = job_api_client.get_job(service_id, notification["job"]["id"])["data"] else: job = None letter_print_day = get_letter_printing_statement(notification["status"], notification["created_at"]) notification_created = parser.parse(notification["created_at"]).replace(tzinfo=None) show_cancel_button = notification["notification_type"] == "letter" and letter_can_be_cancelled( notification["status"], notification_created ) if get_help_argument() or request.args.get("help") == "0": # help=0 is set when you’ve just sent a notification. We # only want to show the back link when you’ve navigated to a # notification, not when you’ve just sent it. back_link = None elif request.args.get("from_job"): back_link = url_for( "main.view_job", service_id=current_service.id, job_id=request.args.get("from_job"), ) else: back_link = url_for( "main.view_notifications", service_id=current_service.id, message_type=template.template_type, status="sending,delivered,failed", ) return render_template( "views/notifications/notification.html", finished=(notification["status"] in (DELIVERED_STATUSES + FAILURE_STATUSES)), notification_status=notification["status"], uploaded_file_name="Report", template=template, job=job, updates_url=url_for( ".view_notification_updates", service_id=service_id, notification_id=notification["id"], status=request.args.get("status"), help=get_help_argument(), ), partials=get_single_notification_partials(notification), created_by=notification.get("created_by"), created_at=notification["created_at"], updated_at=notification["updated_at"], help=get_help_argument(), estimated_letter_delivery_date=get_letter_timings( notification["created_at"], postage=notification["postage"] ).earliest_delivery, notification_id=notification["id"], postage=notification["postage"], can_receive_inbound=(current_service.has_permission("inbound_sms")), is_precompiled_letter=notification["template"]["is_precompiled_letter"], letter_print_day=letter_print_day, show_cancel_button=show_cancel_button, sent_with_test_key=(notification.get("key_type") == KEY_TYPE_TEST), back_link=back_link, just_sent=request.args.get("just_sent"), attachments=get_attachments(notification, "attach").values(), )
def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_pdf=False): try: # The happy path is that the job doesn’t already exist, so the # API will return a 404 and the client will raise HTTPError. job_api_client.get_job(service_id, upload_id) # the job exists already - so go back to the templates page # If we just return a `redirect` (302) object here, we'll get # errors when we try and unpack in the check_messages route. # Rasing a werkzeug.routing redirect means that doesn't happen. raise PermanentRedirect( url_for('.send_messages', service_id=service_id, template_id=template_id)) except HTTPError as e: if e.status_code != 404: raise statistics = service_api_client.get_service_statistics(service_id, today_only=True) remaining_messages = (current_service.message_limit - sum(stat['requested'] for stat in statistics.values())) contents = s3download(service_id, upload_id) db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user) email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session() elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session() template = get_template( db_template, current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_id=template_id, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=sms_sender, page_count=get_page_count_for_letter(db_template), ) 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.name, user.mobile_number, user.email_address] for user in Users(service_id)) if current_service.trial_mode else None, remaining_messages=remaining_messages, international_sms=current_service.has_permission('international_sms'), ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() if preview_row < 2: abort(404) if preview_row < len(recipients) + 2: template.values = recipients[preview_row - 2].recipient_and_personalisation elif preview_row > 2: abort(404) return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=len(recipients), count_of_displayed_recipients=len(list(recipients.displayed_rows)), original_file_name=request.args.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(), trying_to_send_letters_in_trial_mode=all(( current_service.trial_mode, template.template_type == 'letter', )), required_recipient_columns=OrderedSet( recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, sent_previously=job_api_client.has_sent_previously( service_id, template.id, db_template['version'], request.args.get('original_file_name', '')))
def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_pdf=False): 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) db_template = service_api_client.get_service_template( service_id, str(template_id), )['data'] email_reply_to = None sms_sender = None if db_template['template_type'] == 'email': email_reply_to = get_email_reply_to_address_from_session(service_id) elif db_template['template_type'] == 'sms': sms_sender = get_sms_sender_from_session(service_id) template = get_template( service_api_client.get_service_template( service_id, str(template_id), )['data'], current_service, show_recipient=True, letter_preview_url=url_for( '.check_messages_preview', service_id=service_id, template_id=template_id, upload_id=upload_id, filetype='png', row_index=preview_row, ) if not letters_as_pdf else None, email_reply_to=email_reply_to, sms_sender=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.name, user.mobile_number, user.email_address] for user in users ) if current_service['restricted'] else None, remaining_messages=remaining_messages, international_sms='international_sms' in current_service['permissions'], ) if request.args.get('from_test'): # only happens if generating a letter preview test back_link = url_for('.send_test', service_id=service_id, template_id=template.id) choose_time_form = None else: back_link = url_for('.send_messages', service_id=service_id, template_id=template.id) choose_time_form = ChooseTimeForm() if preview_row < 2: abort(404) if preview_row < len(recipients) + 2: template.values = recipients[preview_row - 2].recipient_and_personalisation elif preview_row > 2: abort(404) if 'file_uploads' not in session: session['file_uploads'] = {} session['file_uploads'][upload_id] = {} if any(recipients) and not recipients.has_errors: session['file_uploads'][upload_id]['notification_count'] = len(recipients) session['file_uploads'][upload_id]['template_id'] = str(template_id) session['file_uploads'][upload_id]['valid'] = True else: session['file_uploads'].pop(upload_id) return dict( recipients=recipients, template=template, errors=recipients.has_errors, row_errors=get_errors_for_csv(recipients, template.template_type), count_of_recipients=len(recipients), count_of_displayed_recipients=len(list(recipients.displayed_rows)), original_file_name=request.args.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(), trying_to_send_letters_in_trial_mode=all(( current_service['restricted'], template.template_type == 'letter', not request.args.get('from_test'), )), required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns, preview_row=preview_row, )