mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-04 05:31:44 -04:00
Merge branch 'master' into features-content-updates
This commit is contained in:
@@ -36,10 +36,8 @@ from wtforms.widgets import CheckboxInput, ListWidget
|
||||
|
||||
from app.main.validators import (
|
||||
Blacklist,
|
||||
CanonicalGovernmentDomain,
|
||||
CsvFileValidator,
|
||||
DoesNotStartWithDoubleZero,
|
||||
KnownGovernmentDomain,
|
||||
LettersNumbersAndFullStopsOnly,
|
||||
NoCommasInPlaceHolders,
|
||||
OnlyGSMCharacters,
|
||||
@@ -47,7 +45,7 @@ from app.main.validators import (
|
||||
ValidGovEmail,
|
||||
)
|
||||
from app.models.user import permissions, roles
|
||||
from app.utils import AgreementInfo, guess_name_from_email_address
|
||||
from app.utils import guess_name_from_email_address
|
||||
|
||||
|
||||
def get_time_value_and_label(future_time):
|
||||
@@ -990,23 +988,9 @@ class PreviewBranding(StripWhitespaceForm):
|
||||
branding_style = HiddenFieldWithNoneOption('branding_style')
|
||||
|
||||
|
||||
class GovernmentDomainField(StringField):
|
||||
validators = [
|
||||
KnownGovernmentDomain(),
|
||||
CanonicalGovernmentDomain(),
|
||||
]
|
||||
|
||||
def post_validate(self, form, validation_stopped):
|
||||
if self.data == '':
|
||||
self.data = None
|
||||
if self.data and not self.errors:
|
||||
self.data = AgreementInfo(self.data).canonical_domain
|
||||
|
||||
|
||||
class ServiceUpdateEmailBranding(StripWhitespaceForm):
|
||||
name = StringField('Name of brand')
|
||||
text = StringField('Text')
|
||||
domain = GovernmentDomainField('Domain')
|
||||
colour = StringField(
|
||||
'Colour',
|
||||
validators=[
|
||||
@@ -1041,7 +1025,6 @@ class SVGFileUpload(StripWhitespaceForm):
|
||||
|
||||
class ServiceLetterBrandingDetails(StripWhitespaceForm):
|
||||
name = StringField('Name of brand', validators=[DataRequired()])
|
||||
domain = GovernmentDomainField('Domain')
|
||||
|
||||
|
||||
class PDFUploadForm(StripWhitespaceForm):
|
||||
|
||||
@@ -11,7 +11,7 @@ from wtforms.validators import Email
|
||||
|
||||
from app import formatted_list
|
||||
from app.main._blacklisted_passwords import blacklisted_passwords
|
||||
from app.utils import AgreementInfo, Spreadsheet, is_gov_user
|
||||
from app.utils import Spreadsheet, is_gov_user
|
||||
|
||||
|
||||
class Blacklist:
|
||||
@@ -111,34 +111,3 @@ class DoesNotStartWithDoubleZero:
|
||||
def __call__(self, form, field):
|
||||
if field.data and field.data.startswith("00"):
|
||||
raise ValidationError(self.message)
|
||||
|
||||
|
||||
class KnownGovernmentDomain:
|
||||
|
||||
message = 'Not a known government domain (you might need to update domains.yml)'
|
||||
|
||||
def __call__(self, form, field):
|
||||
if field.data and AgreementInfo(field.data).owner is None:
|
||||
raise ValidationError(self.message)
|
||||
|
||||
|
||||
class CanonicalGovernmentDomain:
|
||||
|
||||
message = 'Not {} domain (use {} if appropriate)'
|
||||
|
||||
def __call__(self, form, field):
|
||||
|
||||
if not field.data:
|
||||
return
|
||||
|
||||
domain = AgreementInfo(field.data)
|
||||
|
||||
if not domain.is_canonical:
|
||||
raise ValidationError(
|
||||
self.message.format('a canonical', domain.canonical_domain)
|
||||
)
|
||||
|
||||
if field.data != domain.canonical_domain:
|
||||
raise ValidationError(
|
||||
self.message.format('an organisation-level', domain.canonical_domain)
|
||||
)
|
||||
|
||||
@@ -2,17 +2,15 @@ from flask import current_app, redirect, render_template, session, url_for
|
||||
from flask_login import login_required
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app import billing_api_client, email_branding_client, service_api_client
|
||||
from app import billing_api_client, service_api_client
|
||||
from app.main import main
|
||||
from app.main.forms import CreateServiceForm
|
||||
from app.utils import AgreementInfo, email_safe, user_is_gov_user
|
||||
from app.utils import email_safe, user_is_gov_user
|
||||
|
||||
|
||||
def _create_service(service_name, organisation_type, email_from, form):
|
||||
free_sms_fragment_limit = current_app.config['DEFAULT_FREE_SMS_FRAGMENT_LIMITS'].get(organisation_type)
|
||||
|
||||
domain = 'nhs.uk' if organisation_type == 'nhs' else AgreementInfo.from_current_user().canonical_domain
|
||||
email_branding = email_branding_client.get_email_branding_id_for_domain(domain)
|
||||
try:
|
||||
service_id = service_api_client.create_service(
|
||||
service_name=service_name,
|
||||
@@ -21,13 +19,9 @@ def _create_service(service_name, organisation_type, email_from, form):
|
||||
restricted=True,
|
||||
user_id=session['user_id'],
|
||||
email_from=email_from,
|
||||
service_domain=domain
|
||||
)
|
||||
session['service_id'] = service_id
|
||||
|
||||
if email_branding:
|
||||
service_api_client.update_service(service_id, email_branding=email_branding)
|
||||
|
||||
billing_api_client.create_or_update_free_sms_fragment_limit(service_id, free_sms_fragment_limit)
|
||||
|
||||
return service_id, None
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
from flask import abort, render_template, request, send_file, url_for
|
||||
from flask_login import login_required
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
from app.main import main
|
||||
from app.main.views.sub_navigation_dictionaries import features_nav
|
||||
from app.s3_client.s3_mou_client import get_mou
|
||||
from app.utils import AgreementInfo
|
||||
|
||||
|
||||
@main.route('/agreement')
|
||||
@login_required
|
||||
def agreement():
|
||||
|
||||
agreement_info = AgreementInfo.from_current_user()
|
||||
|
||||
return render_template(
|
||||
'views/{}.html'.format(agreement_info.as_jinja_template),
|
||||
owner=agreement_info.owner,
|
||||
'views/{}.html'.format(current_user.default_organisation.as_jinja_template),
|
||||
owner=current_user.default_organisation.name,
|
||||
navigation_links=features_nav(),
|
||||
)
|
||||
|
||||
@@ -24,7 +20,7 @@ def agreement():
|
||||
@login_required
|
||||
def download_agreement():
|
||||
return send_file(**get_mou(
|
||||
AgreementInfo.from_current_user().crown_status_or_404
|
||||
current_user.default_organisation.crown_status_or_404
|
||||
))
|
||||
|
||||
|
||||
@@ -40,10 +36,8 @@ def public_agreement(variant):
|
||||
organisation_is_crown=(variant == 'crown')
|
||||
))
|
||||
|
||||
agreement_info = AgreementInfo.from_current_user()
|
||||
|
||||
return render_template(
|
||||
'views/agreement-public.html',
|
||||
owner=agreement_info.owner,
|
||||
owner=current_user.default_organisation.name,
|
||||
download_link=url_for('.public_download_agreement', variant=variant),
|
||||
)
|
||||
|
||||
@@ -39,7 +39,6 @@ def update_email_branding(branding_id, logo=None):
|
||||
name=email_branding['name'],
|
||||
text=email_branding['text'],
|
||||
colour=email_branding['colour'],
|
||||
domain=email_branding['domain'],
|
||||
brand_type=email_branding['brand_type']
|
||||
)
|
||||
|
||||
@@ -67,7 +66,6 @@ def update_email_branding(branding_id, logo=None):
|
||||
name=form.name.data,
|
||||
text=form.text.data,
|
||||
colour=form.colour.data,
|
||||
domain=form.domain.data,
|
||||
brand_type=form.brand_type.data,
|
||||
)
|
||||
|
||||
@@ -115,7 +113,6 @@ def create_email_branding(logo=None):
|
||||
name=form.name.data,
|
||||
text=form.text.data,
|
||||
colour=form.colour.data,
|
||||
domain=form.domain.data,
|
||||
brand_type=form.brand_type.data,
|
||||
)
|
||||
|
||||
|
||||
@@ -12,18 +12,23 @@ from notifications_utils.international_billing_rates import (
|
||||
)
|
||||
from notifications_utils.template import HTMLEmailTemplate, LetterImageTemplate
|
||||
|
||||
from app import email_branding_client, letter_branding_client
|
||||
from app import email_branding_client, letter_branding_client, status_api_client
|
||||
from app.main import main
|
||||
from app.main.forms import FieldWithNoneOption, SearchByNameForm
|
||||
from app.main.views.sub_navigation_dictionaries import features_nav
|
||||
from app.utils import AgreementInfo, get_logo_cdn_domain
|
||||
from app.utils import get_logo_cdn_domain
|
||||
|
||||
|
||||
@main.route('/')
|
||||
def index():
|
||||
|
||||
if current_user and current_user.is_authenticated:
|
||||
return redirect(url_for('main.choose_account'))
|
||||
return render_template('views/signedout.html')
|
||||
|
||||
return render_template(
|
||||
'views/signedout.html',
|
||||
counts=status_api_client.get_count_of_live_services_and_organisations(),
|
||||
)
|
||||
|
||||
|
||||
@main.route('/robots.txt')
|
||||
@@ -70,7 +75,6 @@ def pricing():
|
||||
for cc, country in INTERNATIONAL_BILLING_RATES.items()
|
||||
], key=lambda x: x[0]),
|
||||
search_form=SearchByNameForm(),
|
||||
agreement_info=AgreementInfo.from_current_user(),
|
||||
)
|
||||
|
||||
|
||||
@@ -268,7 +272,6 @@ def terms():
|
||||
return render_template(
|
||||
'views/terms-of-use.html',
|
||||
navigation_links=features_nav(),
|
||||
agreement_info=AgreementInfo.from_current_user(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ def update_letter_branding(branding_id, logo=None):
|
||||
file_upload_form = SVGFileUpload()
|
||||
letter_branding_details_form = ServiceLetterBrandingDetails(
|
||||
name=letter_branding['name'],
|
||||
domain=letter_branding['domain']
|
||||
)
|
||||
|
||||
file_upload_form_submitted = file_upload_form.file.data
|
||||
@@ -87,7 +86,6 @@ def update_letter_branding(branding_id, logo=None):
|
||||
branding_id=branding_id,
|
||||
filename=db_filename,
|
||||
name=letter_branding_details_form.name.data,
|
||||
domain=letter_branding_details_form.domain.data
|
||||
)
|
||||
|
||||
return redirect(url_for('main.letter_branding'))
|
||||
@@ -98,7 +96,6 @@ def update_letter_branding(branding_id, logo=None):
|
||||
branding_id=branding_id,
|
||||
filename=db_filename,
|
||||
name=letter_branding_details_form.name.data,
|
||||
domain=letter_branding_details_form.domain.data
|
||||
)
|
||||
|
||||
upload_letter_logos(logo, db_filename, png_file, session['user_id'])
|
||||
@@ -106,9 +103,7 @@ def update_letter_branding(branding_id, logo=None):
|
||||
return redirect(url_for('main.letter_branding'))
|
||||
|
||||
except HTTPError as e:
|
||||
if 'domain' in e.message:
|
||||
letter_branding_details_form.domain.errors.append(e.message['domain'][0])
|
||||
elif 'name' in e.message:
|
||||
if 'name' in e.message:
|
||||
letter_branding_details_form.name.errors.append(e.message['name'][0])
|
||||
else:
|
||||
raise e
|
||||
@@ -118,7 +113,6 @@ def update_letter_branding(branding_id, logo=None):
|
||||
branding_id=branding_id,
|
||||
filename=letter_branding['filename'],
|
||||
name=letter_branding['name'],
|
||||
domain=letter_branding['domain']
|
||||
)
|
||||
file_upload_form.file.errors = ['Error saving uploaded file - try uploading again']
|
||||
|
||||
@@ -165,7 +159,6 @@ def create_letter_branding(logo=None):
|
||||
letter_branding_client.create_letter_branding(
|
||||
filename=db_filename,
|
||||
name=letter_branding_details_form.name.data,
|
||||
domain=letter_branding_details_form.domain.data,
|
||||
)
|
||||
|
||||
upload_letter_logos(logo, db_filename, png_file, session['user_id'])
|
||||
@@ -173,9 +166,7 @@ def create_letter_branding(logo=None):
|
||||
return redirect(url_for('main.letter_branding'))
|
||||
|
||||
except HTTPError as e:
|
||||
if 'domain' in e.message:
|
||||
letter_branding_details_form.domain.errors.append(e.message['domain'][0])
|
||||
elif 'name' in e.message:
|
||||
if 'name' in e.message:
|
||||
letter_branding_details_form.name.errors.append(e.message['name'][0])
|
||||
else:
|
||||
raise e
|
||||
|
||||
@@ -60,7 +60,9 @@ def view_notification(service_id, notification_id):
|
||||
|
||||
if notification['template']['is_precompiled_letter']:
|
||||
try:
|
||||
file_contents = view_letter_notification_as_preview(service_id, notification_id, "pdf")
|
||||
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(
|
||||
@@ -72,7 +74,6 @@ def view_notification(service_id, notification_id):
|
||||
|
||||
if notification.get('postage'):
|
||||
notification['template']['postage'] = notification['postage']
|
||||
|
||||
template = get_template(
|
||||
notification['template'],
|
||||
current_service,
|
||||
@@ -173,14 +174,22 @@ def view_letter_notification_as_preview(service_id, notification_id, filetype):
|
||||
|
||||
if filetype not in ('pdf', 'png'):
|
||||
abort(404)
|
||||
|
||||
notification = notification_api_client.get_notification(service_id, str(notification_id))
|
||||
try:
|
||||
preview = notification_api_client.get_notification_letter_preview(
|
||||
service_id,
|
||||
notification_id,
|
||||
filetype,
|
||||
page=request.args.get('page')
|
||||
)
|
||||
if notification['status'] == "validation-failed":
|
||||
preview = notification_api_client.get_notification_letter_preview_with_overlay(
|
||||
service_id,
|
||||
notification_id,
|
||||
filetype,
|
||||
page=request.args.get('page')
|
||||
)
|
||||
else:
|
||||
preview = notification_api_client.get_notification_letter_preview(
|
||||
service_id,
|
||||
notification_id,
|
||||
filetype,
|
||||
page=request.args.get('page')
|
||||
)
|
||||
|
||||
display_file = base64.b64decode(preview['content'])
|
||||
except APIError:
|
||||
|
||||
@@ -54,7 +54,6 @@ from app.main.forms import (
|
||||
branding_options_dict,
|
||||
)
|
||||
from app.utils import (
|
||||
AgreementInfo,
|
||||
email_safe,
|
||||
user_has_permissions,
|
||||
user_is_gov_user,
|
||||
@@ -180,7 +179,7 @@ def estimate_usage(service_id):
|
||||
@user_has_permissions('manage_service')
|
||||
def request_to_go_live(service_id):
|
||||
|
||||
agreement_signed = AgreementInfo.from_current_user().agreement_signed
|
||||
agreement_signed = current_service.organisation.agreement_signed
|
||||
|
||||
return render_template(
|
||||
'views/service-settings/request-to-go-live.html',
|
||||
@@ -226,7 +225,7 @@ def submit_request_to_go_live(service_id):
|
||||
service_name=current_service.name,
|
||||
service_dashboard=url_for('main.service_dashboard', service_id=current_service.id, _external=True),
|
||||
organisation_type=str(current_service.organisation_type).title(),
|
||||
agreement=AgreementInfo.from_current_user().as_human_readable,
|
||||
agreement=current_service.organisation.as_human_readable(current_user.email_domain),
|
||||
checklist=current_service.go_live_checklist_completed_as_yes_no,
|
||||
volume_email=print_if_number(current_service.volume_email),
|
||||
volume_email_formatted=format_if_number(current_service.volume_email),
|
||||
@@ -237,7 +236,7 @@ def submit_request_to_go_live(service_id):
|
||||
research_consent='Yes' if current_service.consent_to_research else 'No',
|
||||
existing_live='Yes' if user_api_client.user_has_live_services(current_user) else 'No',
|
||||
service_id=current_service.id,
|
||||
organisation=AgreementInfo.from_current_user().owner,
|
||||
organisation=current_service.organisation.name,
|
||||
user_name=current_user.name,
|
||||
user_email=current_user.email_address,
|
||||
date=datetime.now(tz=pytz.timezone('Europe/London')).strftime('%d/%m/%Y'),
|
||||
@@ -245,7 +244,7 @@ def submit_request_to_go_live(service_id):
|
||||
ticket_type=zendesk_client.TYPE_QUESTION,
|
||||
user_email=current_user.email_address,
|
||||
user_name=current_user.name,
|
||||
tags=get_request_to_go_live_tags(current_service, current_user),
|
||||
tags=current_service.request_to_go_live_tags,
|
||||
)
|
||||
|
||||
flash('Thanks for your request to go live. We’ll get back to you within one working day.', 'default')
|
||||
@@ -262,12 +261,7 @@ def service_switch_live(service_id):
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
current_service.update(
|
||||
# TODO This limit should be set depending on the agreement signed by
|
||||
# with Notify.
|
||||
message_limit=250000 if form.enabled.data else 50,
|
||||
restricted=(not form.enabled.data)
|
||||
)
|
||||
current_service.update_status(live=form.enabled.data)
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
|
||||
return render_template(
|
||||
@@ -985,7 +979,7 @@ def branding_request(service_id):
|
||||
'\nCurrent branding: {current_branding}'
|
||||
'\nBranding requested: {branding_requested}'
|
||||
).format(
|
||||
organisation=AgreementInfo.from_current_user().as_info_for_branding_request,
|
||||
organisation=current_service.organisation.as_info_for_branding_request(current_user.email_domain),
|
||||
service_name=current_service.name,
|
||||
dashboard_url=url_for('main.service_dashboard', service_id=current_service.id, _external=True),
|
||||
current_branding=current_service.email_branding_name,
|
||||
@@ -1073,37 +1067,6 @@ def check_contact_details_type(contact_details):
|
||||
return 'phone_number'
|
||||
|
||||
|
||||
def get_request_to_go_live_tags(service, user):
|
||||
return list(_get_request_to_go_live_tags(
|
||||
service,
|
||||
AgreementInfo.from_user(user).agreement_signed,
|
||||
))
|
||||
|
||||
|
||||
def _get_request_to_go_live_tags(service, agreement_signed):
|
||||
|
||||
BASE = 'notify_request_to_go_live'
|
||||
|
||||
yield BASE
|
||||
|
||||
if service.go_live_checklist_completed and agreement_signed:
|
||||
yield BASE + '_complete'
|
||||
return
|
||||
|
||||
for test, tag in (
|
||||
(True, ''),
|
||||
(not service.volumes, '_volumes'),
|
||||
(not service.go_live_checklist_completed, '_checklist'),
|
||||
(not agreement_signed, '_mou'),
|
||||
(service.needs_to_add_email_reply_to_address, '_email_reply_to'),
|
||||
(not service.has_team_members, '_team_member'),
|
||||
(not service.has_templates, '_template_content'),
|
||||
(service.needs_to_change_sms_sender, '_sms_sender'),
|
||||
):
|
||||
if test:
|
||||
yield BASE + '_incomplete' + tag
|
||||
|
||||
|
||||
def print_if_number(value):
|
||||
return value if isinstance(value, int) else ''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user