mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-23 07:46:23 -04:00
Merge branch 'master' into add-get-started-page
This commit is contained in:
@@ -38,19 +38,6 @@ from app.utils import (
|
||||
)
|
||||
|
||||
|
||||
# This is a placeholder view method to be replaced
|
||||
# when product team makes decision about how/what/when
|
||||
# to view history
|
||||
@main.route("/services/<service_id>/history")
|
||||
@user_has_permissions()
|
||||
def temp_service_history(service_id):
|
||||
data = service_api_client.get_service_history(service_id)['data']
|
||||
return render_template('views/temp-history.html',
|
||||
services=data['service_history'],
|
||||
api_keys=data['api_key_history'],
|
||||
events=data['events'])
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/dashboard")
|
||||
@user_has_permissions('view_activity', 'send_messages')
|
||||
def old_service_dashboard(service_id):
|
||||
|
||||
43
app/main/views/history.py
Normal file
43
app/main/views/history.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from collections import defaultdict
|
||||
from operator import attrgetter
|
||||
|
||||
from flask import render_template, request
|
||||
|
||||
from app import current_service, format_date_numeric
|
||||
from app.main import main
|
||||
from app.models.event import APIKeyEvent, APIKeyEvents, ServiceEvents
|
||||
from app.utils import user_has_permissions
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/history")
|
||||
@user_has_permissions('manage_service')
|
||||
def history(service_id):
|
||||
|
||||
events = _get_events(current_service.id, request.args.get('selected'))
|
||||
|
||||
return render_template(
|
||||
'views/temp-history.html',
|
||||
days=_chunk_events_by_day(events),
|
||||
show_navigation=request.args.get('selected') or any(
|
||||
isinstance(event, APIKeyEvent) for event in events
|
||||
),
|
||||
user_getter=current_service.active_users.get_name_from_id,
|
||||
)
|
||||
|
||||
|
||||
def _get_events(service_id, selected):
|
||||
if selected == 'api':
|
||||
return APIKeyEvents(service_id)
|
||||
if selected == 'service':
|
||||
return ServiceEvents(service_id)
|
||||
return APIKeyEvents(service_id) + ServiceEvents(service_id)
|
||||
|
||||
|
||||
def _chunk_events_by_day(events):
|
||||
|
||||
days = defaultdict(list)
|
||||
|
||||
for event in sorted(events, key=attrgetter('time'), reverse=True):
|
||||
days[format_date_numeric(event.time)].append(event)
|
||||
|
||||
return sorted(days.items(), reverse=True)
|
||||
@@ -15,8 +15,9 @@ from flask import (
|
||||
)
|
||||
from flask_login import current_user
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from notifications_utils import SMS_CHAR_COUNT_LIMIT
|
||||
from notifications_utils import LETTER_MAX_PAGE_COUNT, SMS_CHAR_COUNT_LIMIT
|
||||
from notifications_utils.columns import Columns
|
||||
from notifications_utils.pdf import is_letter_too_long
|
||||
from notifications_utils.recipients import (
|
||||
RecipientCSV,
|
||||
first_column_headings,
|
||||
@@ -522,6 +523,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
|
||||
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,
|
||||
@@ -567,6 +569,8 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
|
||||
elif preview_row > 2:
|
||||
abort(404)
|
||||
|
||||
page_count = get_page_count_for_letter(db_template, template.values)
|
||||
|
||||
return dict(
|
||||
recipients=recipients,
|
||||
template=template,
|
||||
@@ -589,7 +593,10 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_
|
||||
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', '')
|
||||
)
|
||||
),
|
||||
letter_too_long=is_letter_too_long(page_count),
|
||||
letter_max_pages=LETTER_MAX_PAGE_COUNT,
|
||||
page_count=page_count
|
||||
)
|
||||
|
||||
|
||||
@@ -601,12 +608,12 @@ def check_messages(service_id, template_id, upload_id, row_index=2):
|
||||
data = _check_messages(service_id, template_id, upload_id, row_index)
|
||||
|
||||
if (
|
||||
data['recipients'].too_many_rows or
|
||||
not data['count_of_recipients'] or
|
||||
not data['recipients'].has_recipient_columns or
|
||||
data['recipients'].duplicate_recipient_column_headers or
|
||||
data['recipients'].missing_column_headers or
|
||||
data['sent_previously']
|
||||
data['recipients'].too_many_rows
|
||||
or not data['count_of_recipients']
|
||||
or not data['recipients'].has_recipient_columns
|
||||
or data['recipients'].duplicate_recipient_column_headers
|
||||
or data['recipients'].missing_column_headers
|
||||
or data['sent_previously']
|
||||
):
|
||||
return render_template('views/check/column-errors.html', **data)
|
||||
|
||||
@@ -614,8 +621,8 @@ def check_messages(service_id, template_id, upload_id, row_index=2):
|
||||
return render_template('views/check/row-errors.html', **data)
|
||||
|
||||
if (
|
||||
data['errors'] or
|
||||
data['trying_to_send_letters_in_trial_mode']
|
||||
data['errors']
|
||||
or data['trying_to_send_letters_in_trial_mode']
|
||||
):
|
||||
return render_template('views/check/column-errors.html', **data)
|
||||
|
||||
@@ -877,10 +884,14 @@ def _check_notification(service_id, template_id, exception=None):
|
||||
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)
|
||||
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 {}),
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ from flask import abort, flash, redirect, render_template, request, url_for
|
||||
from flask_login import current_user
|
||||
from markupsafe import Markup
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from notifications_utils import LETTER_MAX_PAGE_COUNT
|
||||
from notifications_utils.formatters import nl2br
|
||||
from notifications_utils.pdf import is_letter_too_long
|
||||
from notifications_utils.recipients import first_column_headings
|
||||
|
||||
from app import (
|
||||
@@ -58,6 +60,8 @@ def view_template(service_id, template_id):
|
||||
'.send_one_off', service_id=service_id, template_id=template_id
|
||||
))
|
||||
|
||||
page_count = get_page_count_for_letter(template)
|
||||
|
||||
return render_template(
|
||||
'views/templates/template.html',
|
||||
template=get_template(
|
||||
@@ -74,6 +78,9 @@ def view_template(service_id, template_id):
|
||||
),
|
||||
template_postage=template["postage"],
|
||||
user_has_template_permission=user_has_template_permission,
|
||||
letter_too_long=is_letter_too_long(page_count),
|
||||
letter_max_pages=LETTER_MAX_PAGE_COUNT,
|
||||
page_count=page_count
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import base64
|
||||
import json
|
||||
import uuid
|
||||
from io import BytesIO
|
||||
|
||||
from flask import (
|
||||
abort,
|
||||
current_app,
|
||||
flash,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
@@ -19,6 +19,7 @@ from app import current_service, notification_api_client, service_api_client
|
||||
from app.extensions import antivirus_client
|
||||
from app.main import main
|
||||
from app.main.forms import PDFUploadForm
|
||||
from app.main.views.jobs import view_jobs
|
||||
from app.s3_client.s3_letter_upload_client import (
|
||||
get_letter_metadata,
|
||||
get_letter_pdf_and_metadata,
|
||||
@@ -26,21 +27,26 @@ from app.s3_client.s3_letter_upload_client import (
|
||||
upload_letter_to_s3,
|
||||
)
|
||||
from app.template_previews import TemplatePreview, sanitise_letter
|
||||
from app.utils import get_template, user_has_permissions
|
||||
from app.utils import (
|
||||
get_letter_validation_error,
|
||||
get_template,
|
||||
user_has_permissions,
|
||||
)
|
||||
|
||||
MAX_FILE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/uploads")
|
||||
@user_has_permissions('send_messages')
|
||||
@user_has_permissions()
|
||||
def uploads(service_id):
|
||||
return render_template('views/uploads/index.html')
|
||||
return view_jobs(service_id)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/upload-letter", methods=['GET', 'POST'])
|
||||
@user_has_permissions('send_messages')
|
||||
def upload_letter(service_id):
|
||||
form = PDFUploadForm()
|
||||
error = {}
|
||||
|
||||
if form.validate_on_submit():
|
||||
pdf_file_bytes = form.file.data.read()
|
||||
@@ -48,17 +54,20 @@ def upload_letter(service_id):
|
||||
|
||||
virus_free = antivirus_client.scan(BytesIO(pdf_file_bytes))
|
||||
if not virus_free:
|
||||
return invalid_upload_error('Your file has failed the virus check')
|
||||
return invalid_upload_error('Your file contains a virus')
|
||||
|
||||
if len(pdf_file_bytes) > MAX_FILE_UPLOAD_SIZE:
|
||||
return invalid_upload_error('Your file must be smaller than 2MB')
|
||||
return invalid_upload_error('Your file is too big', 'Files must be smaller than 2MB.')
|
||||
|
||||
try:
|
||||
# TODO: get page count from the sanitise response once template preview handles malformed files nicely
|
||||
page_count = pdf_page_count(BytesIO(pdf_file_bytes))
|
||||
except PdfReadError:
|
||||
current_app.logger.info('Invalid PDF uploaded for service_id: {}'.format(service_id))
|
||||
return invalid_upload_error('Your file must be a valid PDF')
|
||||
return invalid_upload_error(
|
||||
"There’s a problem with your file",
|
||||
'Notify cannot read this PDF.<br>Save a new copy of your file and try again.'
|
||||
)
|
||||
|
||||
upload_id = uuid.uuid4()
|
||||
file_location = get_transient_letter_file_location(service_id, upload_id)
|
||||
@@ -68,13 +77,18 @@ def upload_letter(service_id):
|
||||
response.raise_for_status()
|
||||
except RequestException as ex:
|
||||
if ex.response is not None and ex.response.status_code == 400:
|
||||
validation_failed_message = response.json().get('message')
|
||||
invalid_pages = response.json().get('invalid_pages')
|
||||
|
||||
status = 'invalid'
|
||||
upload_letter_to_s3(
|
||||
pdf_file_bytes,
|
||||
file_location=file_location,
|
||||
status=status,
|
||||
page_count=page_count,
|
||||
filename=original_filename)
|
||||
filename=original_filename,
|
||||
message=validation_failed_message,
|
||||
invalid_pages=invalid_pages)
|
||||
else:
|
||||
raise ex
|
||||
else:
|
||||
@@ -95,12 +109,33 @@ def upload_letter(service_id):
|
||||
)
|
||||
)
|
||||
|
||||
return render_template('views/uploads/choose-file.html', form=form)
|
||||
if form.file.errors:
|
||||
error = _get_error_from_upload_form(form.file.errors[0])
|
||||
|
||||
return render_template(
|
||||
'views/uploads/choose-file.html',
|
||||
error=error,
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
def invalid_upload_error(message):
|
||||
flash(message, 'dangerous')
|
||||
return render_template('views/uploads/choose-file.html', form=PDFUploadForm()), 400
|
||||
def invalid_upload_error(error_title, error_detail=None):
|
||||
return render_template(
|
||||
'views/uploads/choose-file.html',
|
||||
error={'title': error_title, 'detail': error_detail},
|
||||
form=PDFUploadForm()
|
||||
), 400
|
||||
|
||||
|
||||
def _get_error_from_upload_form(form_errors):
|
||||
error = {}
|
||||
if 'PDF' in form_errors:
|
||||
error['title'] = 'Wrong file type'
|
||||
error['detail'] = form_errors
|
||||
else: # No file was uploaded error
|
||||
error['title'] = form_errors
|
||||
|
||||
return error
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/preview-letter/<file_id>")
|
||||
@@ -110,7 +145,13 @@ def uploaded_letter_preview(service_id, file_id):
|
||||
original_filename = metadata.get('filename')
|
||||
page_count = metadata.get('page_count')
|
||||
status = metadata.get('status')
|
||||
error_message = metadata.get('message')
|
||||
invalid_pages = metadata.get('invalid_pages')
|
||||
|
||||
if invalid_pages:
|
||||
invalid_pages = json.loads(invalid_pages)
|
||||
|
||||
error = get_letter_validation_error(error_message, invalid_pages, page_count)
|
||||
template_dict = service_api_client.get_precompiled_template(service_id)
|
||||
|
||||
template = get_template(
|
||||
@@ -130,6 +171,7 @@ def uploaded_letter_preview(service_id, file_id):
|
||||
template=template,
|
||||
status=status,
|
||||
file_id=file_id,
|
||||
error=error,
|
||||
)
|
||||
|
||||
|
||||
@@ -140,7 +182,7 @@ def view_letter_upload_as_preview(service_id, file_id):
|
||||
|
||||
page = request.args.get('page')
|
||||
|
||||
if metadata['status'] == 'invalid':
|
||||
if metadata.get('message') == 'content-outside-printable-area':
|
||||
return TemplatePreview.from_invalid_pdf_file(pdf_file, page)
|
||||
else:
|
||||
return TemplatePreview.from_valid_pdf_file(pdf_file, page)
|
||||
|
||||
Reference in New Issue
Block a user