def view_job_csv(service_id, job_id): job = job_api_client.get_job(service_id, job_id)['data'] template = service_api_client.get_service_template( service_id=service_id, template_id=job['template'], version=job['template_version'] )['data'] filter_args = _parse_filter_args(request.args) filter_args['status'] = _set_status_filters(filter_args) return ( generate_notifications_csv( notification_api_client.get_notifications_for_service( service_id, job_id, status=filter_args.get('status'), page_size=job['notification_count'] )['notifications'] ), 200, { 'Content-Type': 'text/csv; charset=utf-8', 'Content-Disposition': 'inline; filename="{} - {}.csv"'.format( template['name'], format_datetime_short(job['created_at']) ) } )
def cancel_letter_job(service_id, job_id): if request.method == "POST": job = job_api_client.get_job(service_id, job_id)["data"] notifications = notification_api_client.get_notifications_for_service( job["service"], job["id"])["notifications"] if job["job_status"] != "finished" or len( notifications) < job["notification_count"]: flash( "We are still processing these letters, please try again in a minute.", "try again", ) return view_job(service_id, job_id) try: number_of_letters = job_api_client.cancel_letter_job( current_service.id, job_id) except HTTPError as e: flash(e.message, "dangerous") return redirect( url_for("main.view_job", service_id=service_id, job_id=job_id)) flash( "Cancelled {} letters from {}".format( format_thousands(number_of_letters), job["original_file_name"]), "default_with_tick", ) return redirect( url_for("main.service_dashboard", service_id=service_id)) flash("Are you sure you want to cancel sending these letters?", "cancel") return view_job(service_id, job_id)
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) template = service_api_client.get_service_template( service_id=service_id, template_id=job['template'], version=job['template_version'])['data'] return render_template( 'views/jobs/job.html', finished=(total_notifications == processed_notifications), uploaded_file_name=job['original_file_name'], template_id=job['template'], 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', ''), ), partials=get_job_partials(job, template), just_sent=bool( request.args.get('just_sent') == 'yes' and template['template_type'] == 'letter'))
def view_job_csv(service_id, job_id): job = job_api_client.get_job(service_id, job_id)["data"] template = service_api_client.get_service_template( service_id=service_id, template_id=job["template"], version=job["template_version"], )["data"] filter_args = parse_filter_args(request.args) filter_args["status"] = set_status_filters(filter_args) return Response( stream_with_context( generate_notifications_csv( service_id=service_id, job_id=job_id, status=filter_args.get("status"), page=request.args.get("page", 1), page_size=5000, format_for_csv=True, template_type=template["template_type"], )), mimetype="text/csv", headers={ "Content-Disposition": 'inline; filename="{} - {}.csv"'.format( template["name"], format_datetime_short(job["created_at"])) }, )
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 view_job_csv(service_id, job_id): job = job_api_client.get_job(service_id, job_id)['data'] template = service_api_client.get_service_template( service_id=service_id, template_id=job['template'], version=job['template_version'])['data'] filter_args = parse_filter_args(request.args) filter_args['status'] = set_status_filters(filter_args) return Response(stream_with_context( generate_notifications_csv( service_id=service_id, job_id=job_id, status=filter_args.get('status'), page=request.args.get('page', 1), page_size=5000, format_for_csv=True, template_type=template['template_type'], )), mimetype='text/csv', headers={ 'Content-Disposition': 'inline; filename="{} - {}.csv"'.format( template['name'], format_datetime_short(job['created_at'])) })
def cancel_letter_job(service_id, job_id): if request.method == 'POST': job = job_api_client.get_job(service_id, job_id)['data'] notification_count = notification_api_client.get_notification_count_for_job_id( service_id=service_id, job_id=job_id) if job['job_status'] != 'finished' or notification_count < job[ 'notification_count']: flash( "We are still processing these letters, please try again in a minute.", 'try again') return view_job(service_id, job_id) try: number_of_letters = job_api_client.cancel_letter_job( current_service.id, job_id) except HTTPError as e: flash(e.message, 'dangerous') return redirect( url_for('main.view_job', service_id=service_id, job_id=job_id)) flash( "Cancelled {} letters from {}".format( format_thousands(number_of_letters), job['original_file_name']), 'default_with_tick') return redirect( url_for('main.service_dashboard', service_id=service_id)) flash("Are you sure you want to cancel sending these letters?", 'cancel') return view_job(service_id, job_id)
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 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 view_job_updates(service_id, job_id): job = job_api_client.get_job(service_id, job_id)['data'] return jsonify(**get_job_partials( job, service_api_client.get_service_template( service_id=current_service.id, template_id=job['template'], version=job['template_version'])['data'], ))
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) template = service_api_client.get_service_template( service_id=service_id, template_id=job["template"], version=job["template_version"], )["data"] just_sent_message = "Your {} been sent. Printing starts {} at 5:30pm.".format( "letter has" if job["notification_count"] == 1 else "letters have", printing_today_or_tomorrow(), ) partials = get_job_partials(job, template) can_cancel_letter_job = partials["can_letter_job_be_cancelled"] return render_template( "views/jobs/job.html", finished=(total_notifications == processed_notifications), uploaded_file_name=job["original_file_name"], template_id=job["template"], job_id=job_id, 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", ""), ), partials=partials, just_sent=bool( request.args.get("just_sent") == "yes" and template["template_type"] == "letter"), just_sent_message=just_sent_message, can_cancel_letter_job=can_cancel_letter_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) template = service_api_client.get_service_template( service_id=service_id, template_id=job['template'], version=job['template_version'] )['data'] just_sent_message = 'Your {} been sent. Printing starts {} at 5:30pm.'.format( 'letter has' if job['notification_count'] == 1 else 'letters have', printing_today_or_tomorrow() ) partials = get_job_partials(job, template) can_cancel_letter_job = partials["can_letter_job_be_cancelled"] return render_template( 'views/jobs/job.html', finished=(total_notifications == processed_notifications), uploaded_file_name=job['original_file_name'], template_id=job['template'], job_id=job_id, 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', ''), ), partials=partials, just_sent=bool( request.args.get('just_sent') == 'yes' and template['template_type'] == 'letter' ), just_sent_message=just_sent_message, can_cancel_letter_job=can_cancel_letter_job, )
def view_job_csv(service_id, job_id): job = job_api_client.get_job(service_id, job_id)["data"] template = service_api_client.get_service_template( service_id=service_id, template_id=job["template"], version=job["template_version"] )["data"] filter_args = _parse_filter_args(request.args) filter_args["status"] = _set_status_filters(filter_args) return ( generate_notifications_csv( notification_api_client.get_notifications_for_service( service_id, job_id, status=filter_args.get("status"), page_size=job["notification_count"] )["notifications"] ), 200, { "Content-Type": "text/csv; charset=utf-8", "Content-Disposition": 'inline; filename="{} - {}.csv"'.format( template["name"], format_datetime_short(job["created_at"]) ), }, )
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 get_dashboard_partials(service_id): template_statistics = aggregate_usage( template_statistics_client.get_template_statistics_for_service(service_id, limit_days=7) ) jobs = add_rate_to_jobs(filter( lambda job: job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'], job_api_client.get_job(service_id, limit_days=7)['data'] )) service = service_api_client.get_detailed_service(service_id) return { 'totals': render_template( 'views/dashboard/_totals.html', service_id=service_id, statistics=get_dashboard_totals(service['data']['statistics']) ), 'template-statistics': render_template( 'views/dashboard/template-statistics.html', template_statistics=template_statistics, most_used_template_count=max( [row['usage_count'] for row in template_statistics] or [0] ), ), 'has_template_statistics': bool(template_statistics), 'jobs': render_template( 'views/dashboard/_jobs.html', jobs=jobs ), 'has_jobs': bool(jobs), 'usage': render_template( 'views/dashboard/_usage.html', **calculate_usage(service_api_client.get_service_usage(service_id)['data']) ), }
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 view_job_updates(service_id, job_id): return jsonify(**get_job_partials( job_api_client.get_job(service_id, job_id)['data'] ))
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 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 view_jobs(service_id): return render_template( 'views/jobs/jobs.html', jobs=add_rate_to_jobs(job_api_client.get_job(service_id)['data']) )