merge from main

This commit is contained in:
Kenneth Kehl
2023-12-20 10:26:50 -08:00
101 changed files with 457 additions and 5109 deletions

View File

@@ -1,133 +0,0 @@
from flask import current_app, redirect, render_template, session, url_for
from app import email_branding_client
from app.main import main
from app.main.forms import AdminEditEmailBrandingForm, SearchByNameForm
from app.s3_client.s3_logo_client import (
TEMP_TAG,
delete_email_temp_file,
delete_email_temp_files_created_by,
permanent_email_logo_name,
persist_logo,
upload_email_logo,
)
from app.utils.user import user_is_platform_admin
@main.route("/email-branding", methods=["GET", "POST"])
@user_is_platform_admin
def email_branding():
brandings = email_branding_client.get_all_email_branding(sort_key="name")
return render_template(
"views/email-branding/select-branding.html",
email_brandings=brandings,
search_form=SearchByNameForm(),
)
@main.route("/email-branding/<uuid:branding_id>/edit", methods=["GET", "POST"])
@main.route("/email-branding/<uuid:branding_id>/edit/<logo>", methods=["GET", "POST"])
@user_is_platform_admin
def update_email_branding(branding_id, logo=None):
email_branding = email_branding_client.get_email_branding(branding_id)[
"email_branding"
]
form = AdminEditEmailBrandingForm(
name=email_branding["name"],
text=email_branding["text"],
colour=email_branding["colour"],
brand_type=email_branding["brand_type"],
)
logo = logo if logo else email_branding.get("logo") if email_branding else None
if form.validate_on_submit():
if form.file.data:
upload_filename = upload_email_logo(
form.file.data.filename, form.file.data, user_id=session["user_id"]
)
if logo and logo.startswith(TEMP_TAG.format(user_id=session["user_id"])):
delete_email_temp_file(logo)
return redirect(
url_for(
".update_email_branding",
branding_id=branding_id,
logo=upload_filename,
)
)
updated_logo_name = (
permanent_email_logo_name(logo, session["user_id"]) if logo else None
)
email_branding_client.update_email_branding(
branding_id=branding_id,
logo=updated_logo_name,
name=form.name.data,
text=form.text.data,
colour=form.colour.data,
brand_type=form.brand_type.data,
)
if logo:
persist_logo(logo, updated_logo_name)
delete_email_temp_files_created_by(session["user_id"])
return redirect(url_for(".email_branding", branding_id=branding_id))
return render_template(
"views/email-branding/manage-branding.html",
form=form,
email_branding=email_branding,
cdn_url=current_app.config["LOGO_CDN_DOMAIN"],
logo=logo,
)
@main.route("/email-branding/create", methods=["GET", "POST"])
@main.route("/email-branding/create/<logo>", methods=["GET", "POST"])
@user_is_platform_admin
def create_email_branding(logo=None):
form = AdminEditEmailBrandingForm(brand_type="org")
if form.validate_on_submit():
if form.file.data:
upload_filename = upload_email_logo(
form.file.data.filename, form.file.data, user_id=session["user_id"]
)
if logo and logo.startswith(TEMP_TAG.format(user_id=session["user_id"])):
delete_email_temp_file(logo)
return redirect(url_for(".create_email_branding", logo=upload_filename))
updated_logo_name = (
permanent_email_logo_name(logo, session["user_id"]) if logo else None
)
email_branding_client.create_email_branding(
logo=updated_logo_name,
name=form.name.data,
text=form.text.data,
colour=form.colour.data,
brand_type=form.brand_type.data,
)
if logo:
persist_logo(logo, updated_logo_name)
delete_email_temp_files_created_by(session["user_id"])
return redirect(url_for(".email_branding"))
return render_template(
"views/email-branding/manage-branding.html",
form=form,
cdn_url=current_app.config["LOGO_CDN_DOMAIN"],
logo=logo,
)

View File

@@ -1,18 +1,8 @@
from flask import (
abort,
current_app,
make_response,
redirect,
render_template,
request,
url_for,
)
from flask import abort, redirect, render_template, request, url_for
from flask_login import current_user
from notifications_utils.template import HTMLEmailTemplate
from app import email_branding_client, status_api_client
from app import status_api_client
from app.main import main
from app.main.forms import FieldWithNoneOption
from app.main.views.pricing import CURRENT_SMS_RATE
from app.main.views.sub_navigation_dictionaries import features_nav, using_notify_nav
from app.utils.user import user_is_logged_in
@@ -63,105 +53,6 @@ def design_content():
)
@main.route("/_email")
@user_is_logged_in
def email_template():
branding_type = "govuk"
branding_style = request.args.get("branding_style", None)
if branding_style == FieldWithNoneOption.NONE_OPTION_VALUE:
branding_style = None
if branding_style is not None:
email_branding = email_branding_client.get_email_branding(branding_style)[
"email_branding"
]
branding_type = email_branding["brand_type"]
if branding_type == "govuk":
brand_text = None
brand_colour = None
brand_logo = None
govuk_banner = True
brand_banner = False
brand_name = None
else:
colour = email_branding["colour"]
brand_text = email_branding["text"]
brand_colour = colour
brand_logo = (
f"https://{current_app.config['LOGO_CDN_DOMAIN']}/{email_branding['logo']}"
if email_branding["logo"]
else None
)
govuk_banner = branding_type in ["govuk", "both"]
brand_banner = branding_type == "org_banner"
brand_name = email_branding["name"]
template = {
"template_type": "email",
"subject": "Email branding preview",
"content": (
"Lorem Ipsum is simply dummy text of the printing and typesetting "
"industry.\n\nLorem Ipsum has been the industrys standard dummy "
"text ever since the 1500s, when an unknown printer took a galley "
"of type and scrambled it to make a type specimen book. "
"\n\n"
"# History"
"\n\n"
"It has "
"survived not only"
"\n\n"
"* five centuries"
"\n"
"* but also the leap into electronic typesetting"
"\n\n"
"It was "
"popularised in the 1960s with the release of Letraset sheets "
"containing Lorem Ipsum passages, and more recently with desktop "
"publishing software like Aldus PageMaker including versions of "
"Lorem Ipsum."
"\n\n"
"^ It is a long established fact that a reader will be distracted "
"by the readable content of a page when looking at its layout."
"\n\n"
"The point of using Lorem Ipsum is that it has a more-or-less "
"normal distribution of letters, as opposed to using Content "
"here, content here, making it look like readable English."
"\n\n\n"
"1. One"
"\n"
"2. Two"
"\n"
"10. Three"
"\n\n"
"This is an example of an email sent using Notify.gov."
"\n\n"
"https://www.notifications.service.gov.uk"
),
}
if not bool(request.args):
resp = make_response(str(HTMLEmailTemplate(template)))
else:
resp = make_response(
str(
HTMLEmailTemplate(
template,
govuk_banner=govuk_banner,
brand_text=brand_text,
brand_colour=brand_colour,
brand_logo=brand_logo,
brand_banner=brand_banner,
brand_name=brand_name,
)
)
)
resp.headers["X-Frame-Options"] = "SAMEORIGIN"
return resp
@main.route("/documentation")
@user_is_logged_in
def documentation():
@@ -196,14 +87,6 @@ def roadmap():
return render_template("views/roadmap.html", navigation_links=features_nav())
@main.route("/features/email")
@user_is_logged_in
def features_email():
return render_template(
"views/features/emails.html", navigation_links=features_nav()
)
@main.route("/features/sms")
@user_is_logged_in
def features_sms():
@@ -288,15 +171,6 @@ def guidance_index():
)
@main.route("/using-notify/guidance/branding-and-customisation")
@user_is_logged_in
def branding_and_customisation():
return render_template(
"views/guidance/branding-and-customisation.html",
navigation_links=using_notify_nav(),
)
@main.route("/using-notify/guidance/create-and-send-messages")
@user_is_logged_in
def create_and_send_messages():

View File

@@ -6,12 +6,7 @@ from flask import flash, redirect, render_template, request, url_for
from flask_login import current_user
from notifications_python_client.errors import HTTPError
from app import (
current_organization,
email_branding_client,
org_invite_api_client,
organizations_client,
)
from app import current_organization, org_invite_api_client, organizations_client
from app.main import main
from app.main.forms import (
AdminBillingDetailsForm,
@@ -19,8 +14,6 @@ from app.main.forms import (
AdminNotesForm,
AdminOrganizationDomainsForm,
AdminOrganizationGoLiveNotesForm,
AdminPreviewBrandingForm,
AdminSetEmailBrandingForm,
InviteOrgUserForm,
OrganizationOrganizationTypeForm,
RenameOrganizationForm,
@@ -31,7 +24,6 @@ from app.main.views.dashboard import (
get_tuples_of_financial_years,
requested_and_current_financial_year,
)
from app.main.views.service_settings import get_branding_as_value_and_label
from app.models.organization import AllOrganizations, Organization
from app.models.user import InvitedOrgUser, User
from app.utils.csv import Spreadsheet
@@ -283,58 +275,6 @@ def edit_organization_type(org_id):
)
@main.route(
"/organizations/<uuid:org_id>/settings/set-email-branding", methods=["GET", "POST"]
)
@user_is_platform_admin
def edit_organization_email_branding(org_id):
email_branding = email_branding_client.get_all_email_branding()
form = AdminSetEmailBrandingForm(
all_branding_options=get_branding_as_value_and_label(email_branding),
current_branding=current_organization.email_branding_id,
)
if form.validate_on_submit():
return redirect(
url_for(
".organization_preview_email_branding",
org_id=org_id,
branding_style=form.branding_style.data,
)
)
return render_template(
"views/organizations/organization/settings/set-email-branding.html",
form=form,
search_form=SearchByNameForm(),
)
@main.route(
"/organizations/<uuid:org_id>/settings/preview-email-branding",
methods=["GET", "POST"],
)
@user_is_platform_admin
def organization_preview_email_branding(org_id):
branding_style = request.args.get("branding_style", None)
form = AdminPreviewBrandingForm(branding_style=branding_style)
if form.validate_on_submit():
current_organization.update(
email_branding_id=form.branding_style.data,
delete_services_cache=True,
)
return redirect(url_for(".organization_settings", org_id=org_id))
return render_template(
"views/organizations/organization/settings/preview-email-branding.html",
form=form,
action=url_for("main.organization_preview_email_branding", org_id=org_id),
)
@main.route(
"/organizations/<uuid:org_id>/settings/edit-organization-domains",
methods=["GET", "POST"],

View File

@@ -596,13 +596,6 @@ def clear_cache():
"service-????????-????-????-????-????????????-template-????????-????-????-????-????????????-versions", # noqa
],
),
(
"email_branding",
[
"email_branding",
"email_branding-????????-????-????-????-????????????",
],
),
(
"organization",
[

View File

@@ -18,7 +18,6 @@ from notifications_utils.clients.zendesk.zendesk_client import NotifySupportTick
from app import (
billing_api_client,
current_service,
email_branding_client,
inbound_number_client,
notification_api_client,
organizations_client,
@@ -35,16 +34,13 @@ from app.main import main
from app.main.forms import (
AdminBillingDetailsForm,
AdminNotesForm,
AdminPreviewBrandingForm,
AdminServiceAddDataRetentionForm,
AdminServiceEditDataRetentionForm,
AdminServiceInboundNumberForm,
AdminServiceMessageLimitForm,
AdminServiceRateLimitForm,
AdminServiceSMSAllowanceForm,
AdminSetEmailBrandingForm,
AdminSetOrganizationForm,
ChooseEmailBrandingForm,
EstimateUsageForm,
RenameServiceForm,
SearchByNameForm,
@@ -55,10 +51,8 @@ from app.main.forms import (
ServiceSmsSenderForm,
ServiceSwitchChannelForm,
SMSPrefixForm,
SomethingElseBrandingForm,
)
from app.utils import DELIVERED_STATUSES, FAILURE_STATUSES, SENDING_STATUSES
from app.utils.branding import get_email_choices as get_email_branding_choices
from app.utils.time import parse_naive_dt
from app.utils.user import (
user_has_permissions,
@@ -87,7 +81,6 @@ def service_settings(service_id):
return render_template(
"views/service-settings.html",
service_permissions=PLATFORM_ADMIN_SERVICE_PERMISSIONS,
email_branding_options=ChooseEmailBrandingForm(current_service),
)
@@ -876,57 +869,6 @@ def set_rate_limit(service_id):
)
@main.route(
"/services/<uuid:service_id>/service-settings/set-email-branding",
methods=["GET", "POST"],
)
@user_is_platform_admin
def service_set_email_branding(service_id):
email_branding = email_branding_client.get_all_email_branding()
form = AdminSetEmailBrandingForm(
all_branding_options=get_branding_as_value_and_label(email_branding),
current_branding=current_service.email_branding_id,
)
if form.validate_on_submit():
return redirect(
url_for(
".service_preview_email_branding",
service_id=service_id,
branding_style=form.branding_style.data,
)
)
return render_template(
"views/service-settings/set-email-branding.html",
form=form,
search_form=SearchByNameForm(),
)
@main.route(
"/services/<uuid:service_id>/service-settings/preview-email-branding",
methods=["GET", "POST"],
)
@user_is_platform_admin
def service_preview_email_branding(service_id):
branding_style = request.args.get("branding_style", None)
form = AdminPreviewBrandingForm(branding_style=branding_style)
if form.validate_on_submit():
current_service.update(email_branding=form.branding_style.data)
return redirect(url_for(".service_settings", service_id=service_id))
return render_template(
"views/service-settings/preview-email-branding.html",
form=form,
service_id=service_id,
action=url_for("main.service_preview_email_branding", service_id=service_id),
)
@main.route(
"/services/<uuid:service_id>/service-settings/link-service-to-organization",
methods=["GET", "POST"],
@@ -957,145 +899,6 @@ def link_service_to_organization(service_id):
)
def create_email_branding_zendesk_ticket(form_option_selected, detail=None):
form = ChooseEmailBrandingForm(current_service)
ticket_message = render_template(
"support-tickets/branding-request.txt",
current_branding=current_service.email_branding_name,
branding_requested=dict(form.options.choices)[form_option_selected],
detail=detail,
)
ticket = NotifySupportTicket(
subject=f"Email branding request - {current_service.name}",
message=ticket_message,
ticket_type=NotifySupportTicket.TYPE_QUESTION,
user_name=current_user.name,
user_email=current_user.email_address,
org_id=current_service.organization_id,
org_type=current_service.organization_type,
service_id=current_service.id,
)
zendesk_client.send_ticket_to_zendesk(ticket)
@main.route(
"/services/<uuid:service_id>/service-settings/email-branding",
methods=["GET", "POST"],
)
@user_has_permissions("manage_service")
def email_branding_request(service_id):
form = ChooseEmailBrandingForm(current_service)
branding_name = current_service.email_branding_name
if form.validate_on_submit():
return redirect(
url_for(
f".email_branding_{form.options.data}",
service_id=current_service.id,
)
)
return render_template(
"views/service-settings/branding/email-branding-options.html",
form=form,
branding_name=branding_name,
)
def check_email_branding_allowed_for_service(branding):
allowed_branding_for_service = dict(get_email_branding_choices(current_service))
if branding not in allowed_branding_for_service:
abort(404)
@main.route(
"/services/<uuid:service_id>/service-settings/email-branding/govuk",
methods=["GET", "POST"],
)
@user_has_permissions("manage_service")
def email_branding_govuk(service_id):
check_email_branding_allowed_for_service("govuk")
if request.method == "POST":
current_service.update(email_branding=None)
flash("Youve updated your email branding", "default")
return redirect(url_for(".service_settings", service_id=current_service.id))
return render_template("views/service-settings/branding/email-branding-govuk.html")
@main.route(
"/services/<uuid:service_id>/service-settings/email-branding/govuk-and-org",
methods=["GET", "POST"],
)
@user_has_permissions("manage_service")
def email_branding_govuk_and_org(service_id):
check_email_branding_allowed_for_service("govuk_and_org")
if request.method == "POST":
create_email_branding_zendesk_ticket("govuk_and_org")
flash(
"Thanks for your branding request. Well get back to you within one working day.",
"default",
)
return redirect(url_for(".service_settings", service_id=current_service.id))
return render_template(
"views/service-settings/branding/email-branding-govuk-org.html"
)
@main.route(
"/services/<uuid:service_id>/service-settings/email-branding/organization",
methods=["GET", "POST"],
)
@user_has_permissions("manage_service")
def email_branding_organization(service_id):
check_email_branding_allowed_for_service("organization")
if request.method == "POST":
create_email_branding_zendesk_ticket("organization")
flash(
"Thanks for your branding request. Well get back to you within one working day.",
"default",
)
return redirect(url_for(".service_settings", service_id=current_service.id))
return render_template(
"views/service-settings/branding/email-branding-organization.html"
)
@main.route(
"/services/<uuid:service_id>/service-settings/email-branding/something-else",
methods=["GET", "POST"],
)
@user_has_permissions("manage_service")
def email_branding_something_else(service_id):
form = SomethingElseBrandingForm()
if form.validate_on_submit():
create_email_branding_zendesk_ticket(
"something_else", detail=form.something_else.data
)
flash(
"Thanks for your branding request. Well get back to you within one working day.",
"default",
)
return redirect(url_for(".service_settings", service_id=current_service.id))
return render_template(
"views/service-settings/branding/email-branding-something-else.html",
form=form,
branding_options=ChooseEmailBrandingForm(current_service),
)
@main.route("/services/<uuid:service_id>/data-retention", methods=["GET"])
@user_is_platform_admin
def data_retention(service_id):
@@ -1184,10 +987,6 @@ def edit_service_billing_details(service_id):
)
def get_branding_as_value_and_label(email_branding):
return [(branding["id"], branding["name"]) for branding in email_branding]
def convert_dictionary_to_wtforms_choices_format(dictionary, value, label):
return [(item[value], item[label]) for item in dictionary]

View File

@@ -26,10 +26,24 @@ from app.utils import hide_from_search_engines
from app.utils.login import is_safe_redirect_url
def _reformat_keystring(orig):
new_keystring = orig.replace("-----BEGIN PRIVATE KEY-----", "")
new_keystring = new_keystring.replace("-----END PRIVATE KEY-----", "")
new_keystring = new_keystring.strip()
new_keystring = "\n".join(
["-----BEGIN PRIVATE KEY-----", new_keystring, "-----END PRIVATE KEY-----"]
)
new_keystring = f"{new_keystring}\n"
return new_keystring
def _get_access_token(code, state):
client_id = os.getenv("LOGIN_DOT_GOV_CLIENT_ID")
access_token_url = os.getenv("LOGIN_DOT_GOV_ACCESS_TOKEN_URL")
keystring = os.getenv("LOGIN_PEM")
if " " in keystring:
keystring = _reformat_keystring(keystring)
payload = {
"iss": client_id,
"sub": client_id,
@@ -38,13 +52,14 @@ def _get_access_token(code, state):
# JWT expiration time (10 minute maximum)
"exp": int(time.time()) + (10 * 60),
}
current_app.logger.warning(f"Here is the raw payload {payload}")
token = jwt.encode(payload, keystring, algorithm="RS256")
base_url = f"{access_token_url}?"
cli_assert = f"client_assertion={token}"
cli_assert_type = "client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer"
code_param = f"code={code}"
url = f"{base_url}{cli_assert}&{cli_assert_type}&{code_param}&grant_type=authorization_code"
current_app.logger.info(f"This is the url we use to get the access token: {url}")
headers = {"Authorization": "Bearer %s" % token}
response = requests.post(url, headers=headers)
current_app.logger.info(f"GOT A RESPONSE {response.json()}")

View File

@@ -4,10 +4,6 @@ def features_nav():
"name": "Features",
"link": "main.features",
"sub_navigation_items": [
# {
# "name": "Emails",
# "link": "main.features_email",
# },
# {
# "name": "Text messages",
# "link": "main.features_sms",
@@ -56,10 +52,6 @@ def using_notify_nav():
# "link": "main.edit_and_format_messages",
# },
# {
# "name": "Branding",
# "link": "main.branding_and_customisation",
# },
# {
# "name": "Send files by email",
# "link": "main.send_files_by_email",
# },