Files
notifications-admin/app/main/views/letter_branding.py
Chris Hill-Scott ef335e7601 Require IDs to be UUIDs in URLS
We mostly rely on the API returning a 404 to generate 404s for trying
to get things with non-UUID IDs. This is fine, except our tests often
mock these API calls. So it could look like everything is working fine,
except the thing your passing in might never be a valid UUID, and thus
would 404 in a non-test environment.

So this commit:
1. uses the `uuid` URL converter everywhere there’s something that looks
   like an ID in a URL parameter
2.  adds a test which automates checking for 1.
2019-11-07 13:46:25 +00:00

208 lines
7.2 KiB
Python

from botocore.exceptions import ClientError as BotoClientError
from flask import (
current_app,
redirect,
render_template,
request,
session,
url_for,
)
from notifications_python_client.errors import HTTPError
from requests import get as requests_get
from app import letter_branding_client
from app.main import main
from app.main.forms import (
SearchByNameForm,
ServiceLetterBrandingDetails,
SVGFileUpload,
)
from app.s3_client.s3_logo_client import (
LETTER_TEMP_TAG,
delete_letter_temp_file,
delete_letter_temp_files_created_by,
get_letter_filename_with_no_path_or_extension,
letter_filename_for_db,
permanent_letter_logo_name,
persist_logo,
upload_letter_png_logo,
upload_letter_temp_logo,
)
from app.utils import get_logo_cdn_domain, user_is_platform_admin
@main.route("/letter-branding", methods=['GET'])
@user_is_platform_admin
def letter_branding():
brandings = letter_branding_client.get_all_letter_branding()
return render_template(
'views/letter-branding/select-letter-branding.html',
letter_brandings=brandings,
search_form=SearchByNameForm()
)
@main.route("/letter-branding/<uuid:branding_id>/edit", methods=['GET', 'POST'])
@main.route("/letter-branding/<uuid:branding_id>/edit/<path:logo>", methods=['GET', 'POST'])
@user_is_platform_admin
def update_letter_branding(branding_id, logo=None):
letter_branding = letter_branding_client.get_letter_branding(branding_id)
file_upload_form = SVGFileUpload()
letter_branding_details_form = ServiceLetterBrandingDetails(
name=letter_branding['name'],
)
file_upload_form_submitted = file_upload_form.file.data
details_form_submitted = request.form.get('operation') == 'branding-details'
logo = logo if logo else permanent_letter_logo_name(letter_branding['filename'], 'svg')
if file_upload_form_submitted and file_upload_form.validate_on_submit():
upload_filename = upload_letter_temp_logo(
file_upload_form.file.data.filename,
file_upload_form.file.data,
current_app.config['AWS_REGION'],
user_id=session["user_id"]
)
if logo.startswith(LETTER_TEMP_TAG.format(user_id=session['user_id'])):
delete_letter_temp_file(logo)
return redirect(url_for('.update_letter_branding', branding_id=branding_id, logo=upload_filename))
if details_form_submitted and letter_branding_details_form.validate_on_submit():
db_filename = letter_filename_for_db(logo, session['user_id'])
try:
if db_filename == letter_branding['filename']:
letter_branding_client.update_letter_branding(
branding_id=branding_id,
filename=db_filename,
name=letter_branding_details_form.name.data,
)
return redirect(url_for('main.letter_branding'))
else:
png_file = get_png_file_from_svg(logo)
letter_branding_client.update_letter_branding(
branding_id=branding_id,
filename=db_filename,
name=letter_branding_details_form.name.data,
)
upload_letter_logos(logo, db_filename, png_file, session['user_id'])
return redirect(url_for('main.letter_branding'))
except HTTPError as e:
if 'name' in e.message:
letter_branding_details_form.name.errors.append(e.message['name'][0])
else:
raise e
except BotoClientError:
# we had a problem saving the file - rollback the db changes
letter_branding_client.update_letter_branding(
branding_id=branding_id,
filename=letter_branding['filename'],
name=letter_branding['name'],
)
file_upload_form.file.errors = ['Error saving uploaded file - try uploading again']
return render_template(
'views/letter-branding/manage-letter-branding.html',
file_upload_form=file_upload_form,
letter_branding_details_form=letter_branding_details_form,
cdn_url=get_logo_cdn_domain(),
logo=logo,
is_update=True
)
@main.route("/letter-branding/create", methods=['GET', 'POST'])
@main.route("/letter-branding/create/<path:logo>", methods=['GET', 'POST'])
@user_is_platform_admin
def create_letter_branding(logo=None):
file_upload_form = SVGFileUpload()
letter_branding_details_form = ServiceLetterBrandingDetails()
file_upload_form_submitted = file_upload_form.file.data
details_form_submitted = request.form.get('operation') == 'branding-details'
if file_upload_form_submitted and file_upload_form.validate_on_submit():
upload_filename = upload_letter_temp_logo(
file_upload_form.file.data.filename,
file_upload_form.file.data,
current_app.config['AWS_REGION'],
user_id=session["user_id"]
)
if logo and logo.startswith(LETTER_TEMP_TAG.format(user_id=session['user_id'])):
delete_letter_temp_file(logo)
return redirect(url_for('.create_letter_branding', logo=upload_filename))
if details_form_submitted and letter_branding_details_form.validate_on_submit():
if logo:
db_filename = letter_filename_for_db(logo, session['user_id'])
png_file = get_png_file_from_svg(logo)
try:
letter_branding_client.create_letter_branding(
filename=db_filename,
name=letter_branding_details_form.name.data,
)
upload_letter_logos(logo, db_filename, png_file, session['user_id'])
return redirect(url_for('main.letter_branding'))
except HTTPError as e:
if 'name' in e.message:
letter_branding_details_form.name.errors.append(e.message['name'][0])
else:
raise e
else:
# Show error on upload form if trying to submit with no logo
file_upload_form.validate()
return render_template(
'views/letter-branding/manage-letter-branding.html',
file_upload_form=file_upload_form,
letter_branding_details_form=letter_branding_details_form,
cdn_url=get_logo_cdn_domain(),
logo=logo
)
def get_png_file_from_svg(filename):
filename_for_template_preview = get_letter_filename_with_no_path_or_extension(filename)
template_preview_svg_endpoint = '{}/{}.svg.png'.format(
current_app.config['TEMPLATE_PREVIEW_API_HOST'],
filename_for_template_preview
)
response = requests_get(
template_preview_svg_endpoint,
headers={'Authorization': 'Token {}'.format(current_app.config['TEMPLATE_PREVIEW_API_KEY'])}
)
return response.content
def upload_letter_logos(old_filename, new_filename, png_file, user_id):
persist_logo(old_filename, permanent_letter_logo_name(new_filename, 'svg'))
upload_letter_png_logo(
permanent_letter_logo_name(new_filename, 'png'),
png_file,
current_app.config['AWS_REGION'],
)
delete_letter_temp_files_created_by(user_id)