diff --git a/app/__init__.py b/app/__init__.py index 217075ac2..bd2c03387 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -100,8 +100,6 @@ from app.notify_client.events_api_client import events_api_client from app.notify_client.inbound_number_client import inbound_number_client from app.notify_client.invite_api_client import invite_api_client from app.notify_client.job_api_client import job_api_client -from app.notify_client.letter_branding_client import letter_branding_client -from app.notify_client.letter_jobs_client import letter_jobs_client from app.notify_client.notification_api_client import notification_api_client from app.notify_client.org_invite_api_client import org_invite_api_client from app.notify_client.organisations_api_client import organisations_client @@ -123,7 +121,6 @@ from app.notify_client.template_statistics_api_client import ( from app.notify_client.upload_api_client import upload_api_client from app.notify_client.user_api_client import user_api_client from app.url_converters import ( - LetterFileExtensionConverter, SimpleDateTypeConverter, TemplateTypeConverter, TicketTypeConverter, @@ -188,8 +185,6 @@ def create_app(application): inbound_number_client, invite_api_client, job_api_client, - letter_branding_client, - letter_jobs_client, notification_api_client, org_invite_api_client, organisations_client, @@ -278,7 +273,6 @@ def init_app(application): application.url_map.converters['uuid'].to_python = lambda self, value: value application.url_map.converters['template_type'] = TemplateTypeConverter application.url_map.converters['ticket_type'] = TicketTypeConverter - application.url_map.converters['letter_file_extension'] = LetterFileExtensionConverter application.url_map.converters['simple_date'] = SimpleDateTypeConverter @@ -501,8 +495,8 @@ def setup_blueprints(application): no_cookie_blueprint is for subresources (things loaded asynchronously) that we might be concerned are setting cookies unnecessarily and potentially getting in to strange race conditions and overwriting other cookies, as we've - seen in the send message flow. Currently, this includes letter template previews, and the iframe from the platform - admin email branding preview pages. + seen in the send message flow. Currently, this includes the iframe from the platform admin email branding + preview pages. This notably doesn't include the *.json ajax endpoints. If we included them in this, the cookies wouldn't be updated, including the expiration date. If you have a dashboard open and in focus it'll refresh the expiration timer diff --git a/app/assets/stylesheets/components/letter.scss b/app/assets/stylesheets/components/letter.scss deleted file mode 100644 index d23408248..000000000 --- a/app/assets/stylesheets/components/letter.scss +++ /dev/null @@ -1,100 +0,0 @@ -$iso-paper-ratio: 141.42135624%; - -@keyframes ellipsis { - to { - width: 1.25em; - } -} - -.letter { - - padding: $iso-paper-ratio 0 0 0; - margin: 0 0 govuk-spacing(6) 0; - position: relative; - background: $panel-colour; - - &:before { - position: absolute; - top: 10%; - left: 50%; - margin-left: -0.5em; - font-size: 96px; - color: $white; - overflow: hidden; - display: block; - vertical-align: bottom; - animation: ellipsis steps(4,end) 1.3s infinite; - content: "\2026"; // ellipsis - width: 0px; - } - - &:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - box-shadow: inset 0 0 0 1px $border-colour; - } - - &-postage { - - $art-width: 97.83; - $art-height: 82.27; - $fold-height: 124px; - $envelope-colour: #C4B186; - - position: absolute; - top: 0; - right: 0; - z-index: 10; - width: $fold-height * ($art-width / $art-height); - height: $fold-height; - margin: 0; - background-color: mix($envelope-colour, $grey-1); - background-size: auto $fold-height; - background-position: right 0; - background-repeat: no-repeat; - background-origin: border-box; - text-indent: -1000em; - border-bottom: 1px solid $border-colour; - border-left: 1px solid $border-colour; - box-shadow: 0 2px 0 0 rgba($border-colour, 0.2); - - &-first { - background-image: file-url('envelope-1st-class.svg'); - } - - &-second { - background-image: file-url('envelope-2nd-class.svg'); - } - - &-international { - background-image: file-url('envelope-international.svg'); - } - - .letter-sent &:hover { - background-color: transparent; - border-color: transparent; - box-shadow: none; - background-image: file-url('envelope-fold.svg'); - } - - } - - img { - display: block; - width: 100%; - background: $white; - position: absolute; - top: 0; - left: 0; - } - -} - -.letter-recipient-summary { - line-height: 28px; - margin-bottom: 0; -} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 1dce511ad..6b09332c5 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -60,7 +60,6 @@ $path: '/static/images/'; @import 'components/research-mode'; @import 'components/tick-cross'; @import 'components/list-entry'; -@import 'components/letter'; @import 'components/live-search'; @import 'components/stick-at-top-when-scrolling'; @import 'components/fullscreen-table'; diff --git a/app/assets/stylesheets/views/template.scss b/app/assets/stylesheets/views/template.scss index 4978281e3..90f574333 100644 --- a/app/assets/stylesheets/views/template.scss +++ b/app/assets/stylesheets/views/template.scss @@ -26,36 +26,6 @@ } -.edit-template-link-letter-contact { - @extend %edit-template-link; - right: -25px; - top: 232px; // align to bottom of contact block -} - -.edit-template-link-letter-address { - @extend %edit-template-link; - top: 14.65%; // align bottom edge to bottom of address - left: -5px; -} - -.edit-template-link-letter-body { - @extend %edit-template-link; - top: 400px; // aligns to top of subject - left: -5px; -} - -.edit-template-link-letter-postage { - @extend %edit-template-link; - top: 51px; // aligns bottom edge to bottom of postmark - right: 145px; // Aligns right edge to midpoint of postmark and fold -} - -.edit-template-link-letter-branding { - @extend %edit-template-link; - top: 51px; // aligns with ‘change postage’ link - left: 66px; // Aligns to left of logo area -} - .template-content-count { @include core-19($tabular-numbers: true); color: $secondary-text-colour; diff --git a/app/formatters.py b/app/formatters.py index c00f6d85c..90d71db2d 100644 --- a/app/formatters.py +++ b/app/formatters.py @@ -202,7 +202,6 @@ def format_notification_type(notification_type): return { 'email': 'Email', 'sms': 'Text message', - 'letter': 'Letter' }[notification_type] @@ -229,23 +228,6 @@ def format_notification_status(status, template_type): 'pending': 'Sending', 'sent': 'Sent to an international number' }, - 'letter': { - 'failed': '', - 'technical-failure': 'Technical failure', - 'temporary-failure': '', - 'permanent-failure': 'Permanent failure', - 'delivered': '', - 'received': '', - 'accepted': '', - 'sending': '', - 'created': '', - 'sent': '', - 'pending-virus-check': '', - 'virus-scan-failed': 'Virus detected', - 'returned-letter': '', - 'cancelled': '', - 'validation-failed': 'Validation failed', - } }[template_type].get(status, status) @@ -256,23 +238,7 @@ def format_notification_status_as_time(status, created, updated): def format_notification_status_as_field_status(status, notification_type): - return { - 'letter': { - 'failed': 'error', - 'technical-failure': 'error', - 'temporary-failure': 'error', - 'permanent-failure': 'error', - 'delivered': None, - 'sent': None, - 'sending': None, - 'created': None, - 'accepted': None, - 'pending-virus-check': None, - 'virus-scan-failed': 'error', - 'returned-letter': None, - 'cancelled': 'error', - }, - }.get( + return {}.get( notification_type, { 'failed': 'error', @@ -314,6 +280,7 @@ def nl2br(value): # this formatter appears to only be used in the letter module +# TODO: use more widely, or delete? currency symbol could be set in config def format_number_in_pounds_as_currency(number): if number >= 1: return f"£{number:,.2f}" @@ -455,12 +422,6 @@ def message_count_noun(count, template_type): else: return 'emails' - elif template_type == 'letter': - if count == 1: - return 'letter' - else: - return 'letters' - def message_count(count, template_type): return ( @@ -489,12 +450,6 @@ def recipient_count_label(count, template_type): else: return 'email addresses' - elif template_type == 'letter': - if count == 1: - return 'address' - else: - return 'addresses' - def recipient_count(count, template_type): return ( diff --git a/app/main/__init__.py b/app/main/__init__.py index e470b3520..97ec7a815 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -21,7 +21,6 @@ from app.main.views import ( # noqa isort:skip index, invites, jobs, - letter_branding, manage_users, new_password, notifications, @@ -31,7 +30,6 @@ from app.main.views import ( # noqa isort:skip pricing, providers, register, - returned_letters, security_policy, send, service_settings, diff --git a/app/main/forms.py b/app/main/forms.py index 65f40f218..6a7984023 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -10,7 +10,6 @@ from flask_wtf import FlaskForm as Form from flask_wtf.file import FileAllowed from flask_wtf.file import FileField as FileField_wtf from flask_wtf.file import FileSize -from notifications_utils.countries.data import Postage from notifications_utils.formatters import strip_all_whitespace from notifications_utils.insensitive_dict import InsensitiveDict from notifications_utils.postal_address import PostalAddress @@ -1294,110 +1293,12 @@ class SMSTemplateForm(BaseTemplateForm): OnlySMSCharacters(template_type='sms')(None, field) -class LetterAddressForm(StripWhitespaceForm): - - def __init__(self, *args, allow_international_letters=False, **kwargs): - self.allow_international_letters = allow_international_letters - super().__init__(*args, **kwargs) - - address = PostalAddressField( - 'Address', - validators=[DataRequired(message="Cannot be empty")] - ) - - def validate_address(self, field): - - address = PostalAddress( - field.data, - allow_international_letters=self.allow_international_letters, - ) - - if not address.has_enough_lines: - raise ValidationError( - f'Address must be at least {PostalAddress.MIN_LINES} lines long' - ) - - if address.has_too_many_lines: - raise ValidationError( - f'Address must be no more than {PostalAddress.MAX_LINES} lines long' - ) - - if not address.has_valid_last_line: - if self.allow_international_letters: - raise ValidationError( - 'Last line of the address must be a UK postcode or another country' - ) - if address.international: - raise ValidationError( - 'You do not have permission to send letters to other countries' - ) - raise ValidationError( - 'Last line of the address must be a real UK postcode' - ) - - if address.has_invalid_characters: - raise ValidationError( - 'Address lines must not start with any of the following characters: @ ( ) = [ ] ” \\ / , < > ~' - ) - - class EmailTemplateForm(BaseTemplateForm): subject = TextAreaField( u'Subject', validators=[DataRequired(message="Cannot be empty")]) -class LetterTemplateForm(EmailTemplateForm): - subject = TextAreaField( - u'Main heading', - validators=[DataRequired(message="Cannot be empty")]) - - template_content = TextAreaField( - u'Body', - validators=[ - DataRequired(message="Cannot be empty"), - NoCommasInPlaceHolders() - ] - ) - - -class LetterTemplatePostageForm(StripWhitespaceForm): - postage = GovukRadiosField( - 'Choose the postage for this letter template', - choices=[ - ('first', 'First class'), - ('second', 'Second class'), - ], - thing='first class or second class', - validators=[DataRequired()] - ) - - -class LetterUploadPostageForm(StripWhitespaceForm): - - def __init__(self, *args, postage_zone, **kwargs): - - super().__init__(*args, **kwargs) - - if postage_zone != Postage.UK: - self.postage.choices = [(postage_zone, '')] - self.postage.data = postage_zone - - @property - def show_postage(self): - return len(self.postage.choices) > 1 - - postage = GovukRadiosField( - 'Choose the postage for this letter', - choices=[ - ('first', 'First class post'), - ('second', 'Second class post'), - ], - default='second', - validators=[DataRequired()] - ) - - class ForgotPasswordForm(StripWhitespaceForm): email_address = email_address(gov_user=False) @@ -1552,11 +1453,6 @@ class EstimateUsageForm(StripWhitespaceForm): things='text messages', format_error_suffix='you expect to send', ) - volume_letter = ForgivingIntegerField( - 'How many letters do you expect to send in the next year?', - things='letters', - format_error_suffix='you expect to send', - ) consent_to_research = GovukRadiosField( 'Can we contact you when we’re doing user research?', choices=[ @@ -1573,7 +1469,7 @@ class EstimateUsageForm(StripWhitespaceForm): def validate(self, *args, **kwargs): - if self.volume_email.data == self.volume_sms.data == self.volume_letter.data == 0: + if self.volume_email.data == self.volume_sms.data == 0: self.at_least_one_volume_filled = False return False @@ -1696,23 +1592,6 @@ class AdminBillingDetailsForm(StripWhitespaceForm): notes = TextAreaField(validators=[]) -class ServiceLetterContactBlockForm(StripWhitespaceForm): - letter_contact_block = TextAreaField( - validators=[ - DataRequired(message="Cannot be empty"), - NoCommasInPlaceHolders() - ] - ) - is_default = GovukCheckboxField("Set as your default address") - - def validate_letter_contact_block(self, field): - line_count = field.data.strip().count('\n') - if line_count >= 10: - raise ValidationError( - 'Contains {} lines, maximum is 10'.format(line_count + 1) - ) - - class ServiceOnOffSettingForm(StripWhitespaceForm): def __init__(self, name, *args, truthy='On', falsey='Off', **kwargs): @@ -1731,7 +1610,6 @@ class ServiceSwitchChannelForm(ServiceOnOffSettingForm): name = 'Send {}'.format({ 'email': 'emails', 'sms': 'text messages', - 'letter': 'letters', }.get(channel)) super().__init__(name, *args, **kwargs) @@ -1761,11 +1639,6 @@ class AdminSetEmailBrandingForm(StripWhitespaceForm): ) -class AdminSetLetterBrandingForm(AdminSetEmailBrandingForm): - # form is the same, but instead of GOV.UK we have None as a valid option - DEFAULT = (FieldWithNoneOption.NONE_OPTION_VALUE, 'None') - - class AdminPreviewBrandingForm(StripWhitespaceForm): branding_style = HiddenFieldWithNoneOption('branding_style') @@ -1800,10 +1673,6 @@ class AdminEditEmailBrandingForm(StripWhitespaceForm): raise ValidationError('This field is required') -class AdminEditLetterBrandingForm(StripWhitespaceForm): - name = GovukTextInputField('Name of brand', validators=[DataRequired()]) - - class SVGFileUpload(StripWhitespaceForm): file = FileField_wtf( 'Upload an SVG logo', @@ -1816,16 +1685,6 @@ class SVGFileUpload(StripWhitespaceForm): ) -class PDFUploadForm(StripWhitespaceForm): - file = FileField_wtf( - 'Upload a letter in PDF format', - validators=[ - FileAllowed(['pdf'], 'Save your letter as a PDF and try again.'), - DataRequired(message="You need to choose a file to upload") - ] - ) - - class EmailFieldInGuestList(GovukEmailField, StripWhitespaceStringField): pass @@ -2062,32 +1921,6 @@ class ChooseEmailBrandingForm(ChooseBrandingForm): ) -class ChooseLetterBrandingForm(ChooseBrandingForm): - options = RadioField('Choose your new letter branding') - something_else = TextAreaField('Describe the branding you want') - - def __init__(self, service): - super().__init__() - - self.options.choices = tuple( - list(branding.get_letter_choices(service)) + - [self.FALLBACK_OPTION] - ) - - if self.something_else_is_only_option: - self.options.data = self.FALLBACK_OPTION_VALUE - - def validate_something_else(self, field): - if ( - self.something_else_is_only_option - or self.options.data == self.FALLBACK_OPTION_VALUE - ) and not field.data: - raise ValidationError('Cannot be empty') - - if self.options.data != self.FALLBACK_OPTION_VALUE: - field.data = '' - - class SomethingElseBrandingForm(StripWhitespaceForm): something_else = GovukTextareaField( 'Describe the branding you want', @@ -2111,7 +1944,6 @@ class AdminServiceAddDataRetentionForm(StripWhitespaceForm): choices=[ ('email', 'Email'), ('sms', 'SMS'), - ('letter', 'Letter'), ], thing='notification type', ) @@ -2128,15 +1960,6 @@ class AdminServiceEditDataRetentionForm(StripWhitespaceForm): ) -class AdminReturnedLettersForm(StripWhitespaceForm): - references = TextAreaField( - u'Letter references', - validators=[ - DataRequired(message="Cannot be empty"), - ] - ) - - class TemplateFolderForm(StripWhitespaceForm): def __init__(self, all_service_users=None, *args, **kwargs): super().__init__(*args, **kwargs) @@ -2214,7 +2037,6 @@ class TemplateAndFoldersSelectionForm(Form): self.add_template_by_template_type.choices = list(filter(None, [ # ('email', 'Email') if 'email' in available_template_types else None, ('sms', 'Text message') if 'sms' in available_template_types else None, - # ('letter', 'Letter') if 'letter' in available_template_types else None, ('copy-existing', 'Copy an existing template') if allow_adding_copy_of_template else None, ])) diff --git a/app/main/views/api_keys.py b/app/main/views/api_keys.py index 0c1c4daff..d0f6d3c85 100644 --- a/app/main/views/api_keys.py +++ b/app/main/views/api_keys.py @@ -96,8 +96,6 @@ def create_api_key(service_id): 'trial mode') } } - if current_service.has_permission('letter'): - form.key_type.param_extensions['items'][1]['hint'] = {'text': 'Cannot be used to send letters'} if form.validate_on_submit(): if current_service.trial_mode and form.key_type.data == KEY_TYPE_NORMAL: abort(400) diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 24b853f0f..60404d781 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -258,7 +258,6 @@ def aggregate_template_usage(template_statistics, sort_key='count'): "template_id": k, "template_name": template_stats[0]['template_name'], "template_type": template_stats[0]['template_type'], - "is_precompiled_letter": template_stats[0]['is_precompiled_letter'], "count": sum(s['count'] for s in template_stats) }) @@ -270,7 +269,7 @@ def aggregate_notifications_stats(template_statistics): notifications = { template_type: { status: 0 for status in ('requested', 'delivered', 'failed') - } for template_type in ["sms", "email", "letter"] + } for template_type in ["sms", "email"] } for stat in template_statistics: notifications[stat["template_type"]]["requested"] += stat["count"] diff --git a/app/main/views/index.py b/app/main/views/index.py index 836adf39d..44719f274 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -8,9 +8,9 @@ from flask import ( url_for, ) from flask_login import current_user -from notifications_utils.template import HTMLEmailTemplate, LetterImageTemplate +from notifications_utils.template import HTMLEmailTemplate -from app import email_branding_client, letter_branding_client, status_api_client +from app import email_branding_client, status_api_client from app.main import main from app.main.forms import FieldWithNoneOption from app.main.views.pricing import CURRENT_SMS_RATE @@ -156,35 +156,6 @@ def email_template(): return resp -@main.route('/_letter') -def letter_template(): - branding_style = request.args.get('branding_style') - - if branding_style == FieldWithNoneOption.NONE_OPTION_VALUE: - branding_style = None - - if branding_style: - filename = letter_branding_client.get_letter_branding(branding_style)['filename'] - else: - filename = 'no-branding' - - template = {'subject': '', 'content': '', 'template_type': 'letter'} - image_url = url_for('no_cookie.letter_branding_preview_image', filename=filename) - - template_image = str(LetterImageTemplate( - template, - image_url=image_url, - page_count=1, - )) - - resp = make_response( - render_template('views/service-settings/letter-preview.html', template=template_image) - ) - - resp.headers['X-Frame-Options'] = 'SAMEORIGIN' - return resp - - @main.route('/documentation') def documentation(): return render_template( @@ -238,14 +209,6 @@ def features_sms(): ) -@main.route('/features/letters') -def features_letters(): - return render_template( - 'views/features/letters.html', - navigation_links=features_nav() - ) - - @main.route('/features/security', endpoint='security') def security(): return render_template( @@ -350,22 +313,6 @@ def send_files_by_email(): ) -@main.route('/using-notify/guidance/upload-a-letter') -def upload_a_letter(): - return render_template( - 'views/guidance/upload-a-letter.html', - navigation_links=using_notify_nav(), - ) - - -@main.route('/using-notify/guidance/letter-specification') -def letter_specification(): - return render_template( - 'views/guidance/letter-specification.html', - navigation_links=using_notify_nav(), - ) - - # --- Redirects --- # @main.route('/roadmap', endpoint='old_roadmap') @@ -384,11 +331,3 @@ def old_page_redirects(): 'main.old_integration_testing': 'main.integration_testing', } return redirect(url_for(redirects[request.endpoint]), code=301) - - -@main.route('/docs/notify-pdf-letter-spec-latest.pdf') -def letter_spec(): - return redirect( - 'https://docs.notifications.service.gov.uk' - '/documentation/images/notify-pdf-letter-spec-v2.4.pdf' - ) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index 54e292fe5..e716e7694 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -16,7 +16,6 @@ from flask import ( from flask_login import current_user from notifications_utils.template import ( EmailPreviewTemplate, - LetterPreviewTemplate, SMSBodyPreviewTemplate, ) @@ -135,7 +134,6 @@ def view_notifications(service_id, message_type=None): things_you_can_search_by={ 'email': ['email address'], 'sms': ['phone number'], - 'letter': ['postal address', 'file name'], # We say recipient here because combining all 3 types, plus # reference gets too long for the hint text None: ['recipient'], @@ -266,7 +264,7 @@ def get_status_filters(service, message_type, statistics): stats = { key: sum( statistics[message_type][key] - for message_type in {'email', 'sms', 'letter'} + for message_type in {'email', 'sms'} ) for key in {'requested', 'delivered', 'failed'} } @@ -401,9 +399,6 @@ def get_preview_of_content(notification): if notification['template'].get('redact_personalisation'): notification['personalisation'] = {} - if notification['template']['is_precompiled_letter']: - return notification['client_reference'] - if notification['template']['template_type'] == 'sms': return str(SMSBodyPreviewTemplate( notification['template'], @@ -416,9 +411,3 @@ def get_preview_of_content(notification): notification['personalisation'], redact_missing_personalisation=True, ).subject) - - if notification['template']['template_type'] == 'letter': - return Markup(LetterPreviewTemplate( - notification['template'], - notification['personalisation'], - ).subject) diff --git a/app/main/views/letter_branding.py b/app/main/views/letter_branding.py deleted file mode 100644 index 4723d27cf..000000000 --- a/app/main/views/letter_branding.py +++ /dev/null @@ -1,177 +0,0 @@ -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 app import letter_branding_client -from app.main import main -from app.main.forms import ( - AdminEditLetterBrandingForm, - SearchByNameForm, - SVGFileUpload, -) -from app.s3_client.s3_logo_client import ( - LETTER_TEMP_TAG, - delete_letter_temp_file, - delete_letter_temp_files_created_by, - letter_filename_for_db, - permanent_letter_logo_name, - persist_logo, - upload_letter_temp_logo, -) -from app.utils.user import 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//edit", methods=['GET', 'POST']) -@main.route("/letter-branding//edit/", 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 = AdminEditLetterBrandingForm( - 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, - 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: - letter_branding_client.update_letter_branding( - branding_id=branding_id, - filename=db_filename, - name=letter_branding_details_form.name.data, - ) - - upload_letter_svg_logo(logo, db_filename, 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=current_app.config['LOGO_CDN_DOMAIN'], - logo=logo, - is_update=True - ) - - -@main.route("/letter-branding/create", methods=['GET', 'POST']) -@main.route("/letter-branding/create/", methods=['GET', 'POST']) -@user_is_platform_admin -def create_letter_branding(logo=None): - file_upload_form = SVGFileUpload() - letter_branding_details_form = AdminEditLetterBrandingForm() - - 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, - 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']) - - try: - letter_branding_client.create_letter_branding( - filename=db_filename, - name=letter_branding_details_form.name.data, - ) - - upload_letter_svg_logo(logo, db_filename, 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=current_app.config['LOGO_CDN_DOMAIN'], - logo=logo - ) - - -def upload_letter_svg_logo(old_filename, new_filename, user_id): - persist_logo(old_filename, permanent_letter_logo_name(new_filename, 'svg')) - - delete_letter_temp_files_created_by(user_id) diff --git a/app/main/views/notifications.py b/app/main/views/notifications.py index 600e735f2..3b3d2b1fb 100644 --- a/app/main/views/notifications.py +++ b/app/main/views/notifications.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from datetime import datetime -from dateutil import parser from flask import ( Response, jsonify, @@ -10,11 +9,6 @@ from flask import ( stream_with_context, url_for, ) -from notifications_utils import LETTER_MAX_PAGE_COUNT -from notifications_utils.letter_timings import ( - get_letter_timings, - letter_can_be_cancelled, -) from app import ( current_service, @@ -24,7 +18,6 @@ from app import ( ) from app.main import main from app.notify_client.api_key_api_client import KEY_TYPE_TEST -from app.template_previews import get_page_count_for_letter from app.utils import ( DELIVERED_STATUSES, FAILURE_STATUSES, @@ -33,7 +26,6 @@ from app.utils import ( set_status_filters, ) from app.utils.csv import generate_notifications_csv -from app.utils.letters import get_letter_validation_error from app.utils.templates import get_template from app.utils.user import user_has_permissions @@ -46,30 +38,10 @@ def view_notification(service_id, notification_id): personalisation = get_all_personalisation_from_notification(notification) error_message = None - page_count = get_page_count_for_letter(notification['template'], values=personalisation) - if page_count and page_count > LETTER_MAX_PAGE_COUNT: - # We check page count here to show the right error message for a letter that is too long. - # Another way to do this would be to get the status and error message from letter metadata. - # This would be a significant amount of work though, out of scope for this bug fix. - # This is because currently we do not pull the letter from S3 when showing preview. - # Instead, we generate letter preview based on the letter template and personalisation. - # Additionally, when a templated letter is sent via the api and the personalisation pushes the - # page count over 10 pages, it takes a while for validation status to come through. - # Checking page count here will enable us to show the error message even if the letter is not - # fully processed yet. - error_message = get_letter_validation_error( - "letter-too-long", [1], page_count - ) - if notification.get('postage'): - if notification["status"] == "validation-failed": - notification['template']['postage'] = None - else: - notification['template']['postage'] = notification['postage'] template = get_template( notification['template'], current_service, - page_count=page_count, show_recipient=True, redact_missing_personalisation=True, sms_sender=notification['reply_to_text'], @@ -81,11 +53,6 @@ def view_notification(service_id, notification_id): else: job = None - 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 @@ -105,14 +72,6 @@ def view_notification(service_id, notification_id): status='sending,delivered,failed', ) - if notification['notification_type'] == 'letter': - estimated_letter_delivery_date = get_letter_timings( - notification['created_at'], - postage=notification['postage'] - ).earliest_delivery - else: - estimated_letter_delivery_date = None - return render_template( 'views/notifications/notification.html', finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)), @@ -133,12 +92,8 @@ def view_notification(service_id, notification_id): created_at=notification['created_at'], updated_at=notification['updated_at'], help=get_help_argument(), - estimated_letter_delivery_date=estimated_letter_delivery_date, notification_id=notification['id'], - postage=notification['postage'], can_receive_inbound=(current_service.has_permission('inbound_sms')), - is_precompiled_letter=notification['template']['is_precompiled_letter'], - show_cancel_button=show_cancel_button, sent_with_test_key=( notification.get('key_type') == KEY_TYPE_TEST ), diff --git a/app/main/views/organisations.py b/app/main/views/organisations.py index ea176ce94..fbe5f6fcd 100644 --- a/app/main/views/organisations.py +++ b/app/main/views/organisations.py @@ -9,7 +9,6 @@ from notifications_python_client.errors import HTTPError from app import ( current_organisation, email_branding_client, - letter_branding_client, org_invite_api_client, organisations_client, ) @@ -22,7 +21,6 @@ from app.main.forms import ( AdminOrganisationGoLiveNotesForm, AdminPreviewBrandingForm, AdminSetEmailBrandingForm, - AdminSetLetterBrandingForm, InviteOrgUserForm, OrganisationAgreementSignedForm, OrganisationCrownStatusForm, @@ -96,7 +94,7 @@ def organisation_dashboard(org_id): search_form=SearchByNameForm() if len(services) > 7 else None, **{ f'total_{key}': sum(service[key] for service in services) - for key in ('emails_sent', 'sms_cost', 'letter_cost') + for key in ('emails_sent', 'sms_cost') }, download_link=url_for( '.download_organisation_usage_report', @@ -123,7 +121,6 @@ def download_organisation_usage_report(org_id): monetary_column_names = OrderedDict([ ('sms_cost', 'Spent on text messages ($)'), - ('letter_cost', 'Spent on letters ($)') ]) org_usage_data = [ @@ -386,51 +383,6 @@ def organisation_preview_email_branding(org_id): ) -@main.route("/organisations//settings/set-letter-branding", methods=['GET', 'POST']) -@user_is_platform_admin -def edit_organisation_letter_branding(org_id): - letter_branding = letter_branding_client.get_all_letter_branding() - - form = AdminSetLetterBrandingForm( - all_branding_options=get_branding_as_value_and_label(letter_branding), - current_branding=current_organisation.letter_branding_id, - ) - - if form.validate_on_submit(): - return redirect(url_for( - '.organisation_preview_letter_branding', - org_id=org_id, - branding_style=form.branding_style.data, - )) - - return render_template( - 'views/organisations/organisation/settings/set-letter-branding.html', - form=form, - search_form=SearchByNameForm() - ) - - -@main.route("/organisations//settings/preview-letter-branding", methods=['GET', 'POST']) -@user_is_platform_admin -def organisation_preview_letter_branding(org_id): - branding_style = request.args.get('branding_style') - - form = AdminPreviewBrandingForm(branding_style=branding_style) - - if form.validate_on_submit(): - current_organisation.update( - letter_branding_id=form.branding_style.data, - delete_services_cache=True, - ) - return redirect(url_for('.organisation_settings', org_id=org_id)) - - return render_template( - 'views/organisations/organisation/settings/preview-letter-branding.html', - form=form, - action=url_for('main.organisation_preview_letter_branding', org_id=org_id), - ) - - @main.route("/organisations//settings/edit-organisation-domains", methods=['GET', 'POST']) @user_is_platform_admin def edit_organisation_domains(org_id): diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index c86436d31..fd9a2a863 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -1,16 +1,14 @@ import itertools -import re from collections import OrderedDict from datetime import datetime -from flask import abort, flash, redirect, render_template, request, url_for +from flask import abort, flash, render_template, request, url_for from notifications_python_client.errors import HTTPError from app import ( billing_api_client, complaint_api_client, format_date_numeric, - letter_jobs_client, notification_api_client, platform_stats_api_client, service_api_client, @@ -19,7 +17,6 @@ from app.extensions import redis_client from app.main import main from app.main.forms import ( AdminClearCacheForm, - AdminReturnedLettersForm, BillingReportDateFilterForm, DateFilterForm, RequiredDateFilterForm, @@ -137,22 +134,6 @@ def make_columns(global_stats, complaints_number): 'label': 'test text messages' } }, - # letter - { - 'black_box': { - 'number': global_stats['letter']['total'], - 'notification_type': 'letter' - }, - 'other_data': [ - get_tech_failure_status_box_data(global_stats['letter']), - get_status_box_data(global_stats['letter'], - 'virus-scan-failed', 'virus scan failures', ZERO_FAILURE_THRESHOLD) - ], - 'test_data': { - 'number': global_stats['letter']['test-key'], - 'label': 'test letters' - } - }, ] @@ -222,10 +203,8 @@ def live_services_csv(): ('live_date', 'Live date'), ('sms_volume_intent', 'SMS volume intent'), ('email_volume_intent', 'Email volume intent'), - ('letter_volume_intent', 'Letter volume intent'), ('sms_totals', 'SMS sent this year'), ('email_totals', 'Emails sent this year'), - ('letter_totals', 'Letters sent this year'), ('free_sms_fragment_limit', 'Free sms allowance'), ]) @@ -280,7 +259,7 @@ def get_billing_report(): end_date = form.end_date.data headers = [ "organisation_id", "organisation_name", "service_id", "service_name", - "sms_cost", "sms_chargeable_units", "total_letters", "letter_cost", "letter_breakdown", + "sms_cost", "sms_chargeable_units", "purchase_order_number", "contact_names", "contact_email_addresses", "billing_reference" ] try: @@ -295,8 +274,8 @@ def get_billing_report(): rows = [ [ r["organisation_id"], r["organisation_name"], r["service_id"], r["service_name"], - r["sms_cost"], r["sms_chargeable_units"], r["total_letters"], r["letter_cost"], - r["letter_breakdown"].strip(), r.get("purchase_order_number"), r.get("contact_names"), + r["sms_cost"], r["sms_chargeable_units"], + r.get("purchase_order_number"), r.get("contact_names"), r.get("contact_email_addresses"), r.get("billing_reference") ] for r in result @@ -324,7 +303,6 @@ def get_volumes_by_service(): headers = [ "organisation id", "organisation name", "service id", "service name", "free allowance", "sms notifications", "sms chargeable units", "email totals", - "letter totals", "letter cost", "letter sheet totals" ] result = billing_api_client.get_data_for_volumes_by_service_report(start_date, end_date) @@ -332,7 +310,6 @@ def get_volumes_by_service(): [ r["organisation_id"], r["organisation_name"], r["service_id"], r["service_name"], r["free_allowance"], r["sms_notifications"], r["sms_chargeable_units"], r["email_totals"], - r["letter_totals"], r["letter_cost"], r["letter_sheet_totals"] ] for r in result ] @@ -358,14 +335,14 @@ def get_daily_volumes(): end_date = form.end_date.data headers = [ "day", "sms totals", "sms fragment totals", "sms chargeable units", - "email totals", "letter totals", "letter sheet totals" + "email totals", ] result = billing_api_client.get_data_for_daily_volumes_report(start_date, end_date) rows = [ [ r["day"], r["sms_totals"], r["sms_fragment_totals"], r["sms_chargeable_units"], - r["email_totals"], r["letter_totals"], r["letter_sheet_totals"] + r["email_totals"], ] for r in result ] @@ -446,46 +423,6 @@ def platform_admin_list_complaints(): ) -@main.route("/platform-admin/returned-letters", methods=["GET", "POST"]) -@user_is_platform_admin -def platform_admin_returned_letters(): - form = AdminReturnedLettersForm() - - if form.validate_on_submit(): - references = [ - re.sub('NOTIFY00[0-9]', '', r.strip()) - for r in form.references.data.split('\n') - if r.strip() - ] - - try: - letter_jobs_client.submit_returned_letters(references) - redis_client.delete_by_pattern( - 'service-????????-????-????-????-????????????-returned-letters-statistics' - ) - redis_client.delete_by_pattern( - 'service-????????-????-????-????-????????????-returned-letters-summary' - ) - except HTTPError as error: - if error.status_code == 400: - error_references = [ - re.match('references (.*) does not match', e['message']).group(1) - for e in error.message - ] - form.references.errors.append("Invalid references: {}".format(', '.join(error_references))) - else: - raise error - else: - flash('Submitted {} letter references'.format(len(references)), 'default') - return redirect( - url_for('.platform_admin_returned_letters') - ) - return render_template( - 'views/platform-admin/returned-letters.html', - form=form, - ) - - @main.route("/platform-admin/clear-cache", methods=['GET', 'POST']) @user_is_platform_admin def clear_cache(): @@ -500,8 +437,6 @@ def clear_cache(): 'service-????????-????-????-????-????????????-templates', 'service-????????-????-????-????-????????????-data-retention', 'service-????????-????-????-????-????????????-template-folders', - 'service-????????-????-????-????-????????????-returned-letters-statistics', - 'service-????????-????-????-????-????????????-returned-letters-summary', ]), ('template', [ 'service-????????-????-????-????-????????????-templates', @@ -512,10 +447,6 @@ def clear_cache(): 'email_branding', 'email_branding-????????-????-????-????-????????????', ]), - ('letter_branding', [ - 'letter_branding', - 'letter_branding-????????-????-????-????-????????????', - ]), ('organisation', [ 'organisations', 'domains', @@ -588,14 +519,9 @@ def create_global_stats(services): 'failed': 0, 'requested': 0 }, - 'letter': { - 'delivered': 0, - 'failed': 0, - 'requested': 0 - } } for service in services: - for msg_type, status in itertools.product(('sms', 'email', 'letter'), ('delivered', 'failed', 'requested')): + for msg_type, status in itertools.product(('sms', 'email'), ('delivered', 'failed', 'requested')): stats[msg_type][status] += service['statistics'][msg_type][status] for stat in stats.values(): diff --git a/app/main/views/returned_letters.py b/app/main/views/returned_letters.py deleted file mode 100644 index ba222a066..000000000 --- a/app/main/views/returned_letters.py +++ /dev/null @@ -1,64 +0,0 @@ -from collections import OrderedDict - -from flask import render_template - -from app import current_service, service_api_client -from app.main import main -from app.models.spreadsheet import Spreadsheet -from app.utils.user import user_has_permissions - - -@main.route("/services//returned-letters") -@user_has_permissions('view_activity') -def returned_letter_summary(service_id): - return render_template( - 'views/returned-letter-summary.html', - data=current_service.returned_letter_summary, - ) - - -@main.route("/services//returned-letters/") -@user_has_permissions('view_activity') -def returned_letters(service_id, reported_at): - - page_size = 50 - returned_letters = service_api_client.get_returned_letters(service_id, reported_at) - count_of_returned_letters = len(returned_letters) - - return render_template( - 'views/returned-letters.html', - returned_letters=returned_letters[:page_size], - reported_at=reported_at, - more_than_one_page=(count_of_returned_letters > page_size), - page_size=page_size, - count_of_returned_letters=count_of_returned_letters, - ) - - -@main.route("/services//returned-letters/.csv") -@user_has_permissions('view_activity') -def returned_letters_report(service_id, reported_at): - returned_letters = service_api_client.get_returned_letters(service_id, reported_at) - column_names = OrderedDict([ - ('notification_id', 'Notification ID'), - ('client_reference', 'Reference'), - ('created_at', 'Date sent'), - ('email_address', 'Sent by'), - ('template_name', 'Template name'), - ('template_id', 'Template ID'), - ('template_version', 'Template version'), - ('original_file_name', 'Spreadsheet file name'), - ('job_row_number', 'Spreadsheet row number'), - ('uploaded_letter_file_name', 'Uploaded letter file name') - ]) - - # initialise with header row - data = [[x for x in column_names.values()]] - - for row in returned_letters: - data.append([row[key] for key in column_names.keys()]) - - return Spreadsheet.from_rows(data).as_csv_data, 200, { - 'Content-Type': 'text/csv; charset=utf-8', - 'Content-Disposition': 'inline; filename="{} returned letters.csv"'.format(reported_at) - } diff --git a/app/main/views/send.py b/app/main/views/send.py index 68f4813ea..fa95e3ba7 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -14,13 +14,8 @@ from flask import ( ) from flask_login import current_user from notifications_python_client.errors import HTTPError -from notifications_utils import LETTER_MAX_PAGE_COUNT, SMS_CHAR_COUNT_LIMIT +from notifications_utils import SMS_CHAR_COUNT_LIMIT from notifications_utils.insensitive_dict import InsensitiveDict -from notifications_utils.pdf import is_letter_too_long -from notifications_utils.postal_address import ( - PostalAddress, - address_lines_1_to_7_keys, -) from notifications_utils.recipients import RecipientCSV, first_column_headings from notifications_utils.sanitise_text import SanitiseASCII from xlrd.biffh import XLRDError @@ -37,7 +32,6 @@ from app.main import main, no_cookie from app.main.forms import ( ChooseTimeForm, CsvUploadForm, - LetterAddressForm, SetSenderForm, get_placeholder_form_instance, ) @@ -49,7 +43,7 @@ from app.s3_client.s3_csv_client import ( s3upload, set_metadata_on_csv_upload, ) -from app.template_previews import TemplatePreview, get_page_count_for_letter +from app.template_previews import TemplatePreview from app.utils import ( PermanentRedirect, should_skip_template_page, @@ -59,11 +53,6 @@ from app.utils.csv import Spreadsheet, get_errors_for_csv from app.utils.templates import get_template from app.utils.user import user_has_permissions -letter_address_columns = [ - column.replace('_', ' ') - for column in address_lines_1_to_7_keys -] - def get_example_csv_fields(column_headers, use_example_as_example, submitted_fields): if use_example_as_example: @@ -78,12 +67,6 @@ def get_example_csv_rows(template, use_example_as_example=True, submitted_fields return { 'email': ['test@example.com'] if use_example_as_example else [current_user.email_address], 'sms': ['12223334444'] if use_example_as_example else [current_user.mobile_number], - 'letter': [ - (submitted_fields or {}).get( - key, get_example_letter_address(key) if use_example_as_example else key - ) - for key in letter_address_columns - ] }[template.template_type] + get_example_csv_fields( ( placeholder for placeholder in template.placeholders @@ -96,14 +79,6 @@ def get_example_csv_rows(template, use_example_as_example=True, submitted_fields ) -def get_example_letter_address(key): - return { - 'address line 1': 'A. Name', - 'address line 2': '123 Example Street', - 'address line 3': 'XM4 5HQ' - }.get(key, '') - - @main.route("/services//send//csv", methods=['GET', 'POST']) @user_has_permissions('send_messages', restrict_admin_usage=True) def send_messages(service_id, template_id): @@ -130,13 +105,6 @@ def send_messages(service_id, template_id): db_template, current_service, show_recipient=True, - letter_preview_url=url_for( - 'no_cookie.view_letter_template_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - page_count=get_page_count_for_letter(db_template), - ), email_reply_to=email_reply_to, sms_sender=sms_sender, ) @@ -217,9 +185,6 @@ def set_sender(service_id, template_id): template = current_service.get_template_with_user_permission_or_403(template_id, current_user) - if template['template_type'] == 'letter': - return redirect_to_one_off - sender_details = get_sender_details(service_id, template['template_type']) if len(sender_details) == 1: @@ -272,11 +237,6 @@ def get_sender_context(sender_details, template_type): 'description': 'Where should replies come back to?', 'field_name': 'email_address' }, - 'letter': { - 'title': 'Send to one recipient', - 'description': 'What should appear in the top right of the letter?', - 'field_name': 'contact_block' - }, 'sms': { 'title': 'Who should the message come from?', 'description': 'Who should the message come from?', @@ -301,7 +261,6 @@ def get_sender_context(sender_details, template_type): def get_sender_details(service_id, template_type): api_call = { 'email': service_api_client.get_reply_to_email_addresses, - 'letter': service_api_client.get_letter_contacts, 'sms': service_api_client.get_sms_senders }[template_type] return api_call(service_id) @@ -314,11 +273,6 @@ def send_one_off(service_id, template_id): session['placeholders'] = {} db_template = current_service.get_template_with_user_permission_or_403(template_id, current_user) - if db_template['template_type'] == 'letter': - session['sender_id'] = None - return redirect( - url_for('.send_one_off_letter_address', service_id=service_id, template_id=template_id) - ) if db_template['template_type'] not in current_service.available_template_types: return redirect(url_for( @@ -344,72 +298,6 @@ def get_notification_check_endpoint(service_id, template): )) -@main.route( - "/services//send//one-off/address", - methods=['GET', 'POST'] -) -@user_has_permissions('send_messages', restrict_admin_usage=True) -def send_one_off_letter_address(service_id, template_id): - if {'recipient', 'placeholders'} - set(session.keys()): - # if someone has come here via a bookmark or back button they might have some stuff still in their session - return redirect(url_for('.send_one_off', service_id=service_id, template_id=template_id)) - - db_template = current_service.get_template_with_user_permission_or_403(template_id, current_user) - - session_placeholders = get_normalised_placeholders_from_session() - - template = get_template( - db_template, - current_service, - show_recipient=True, - letter_preview_url=url_for( - 'no_cookie.send_test_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), - page_count=get_page_count_for_letter(db_template, session_placeholders), - email_reply_to=None, - sms_sender=None - ) - - current_session_address = PostalAddress.from_personalisation(session_placeholders) - - form = LetterAddressForm( - address=current_session_address.normalised, - allow_international_letters=current_service.has_permission('international_letters'), - ) - - if form.validate_on_submit(): - session['placeholders'].update(PostalAddress(form.address.data).as_personalisation) - - placeholders = fields_to_fill_in(template) - if all_placeholders_in_session(placeholders): - return get_notification_check_endpoint(service_id, template) - - first_non_address_placeholder_index = len(address_lines_1_to_7_keys) - - return redirect(url_for( - 'main.send_one_off_step', - service_id=service_id, - template_id=template_id, - step_index=first_non_address_placeholder_index, - )) - - return render_template( - 'views/send-one-off-letter-address.html', - page_title=get_send_test_page_title( - template_type='letter', - entering_recipient=True, - name=template.name, - ), - template=template, - form=form, - back_link=get_back_link(service_id, template, 0), - link_to_upload=True, - ) - - @main.route( "/services//send//one-off/step-", methods=['GET', 'POST'], @@ -438,13 +326,6 @@ def send_one_off_step(service_id, template_id, step_index): db_template, current_service, show_recipient=True, - letter_preview_url=url_for( - 'no_cookie.send_test_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), - page_count=get_page_count_for_letter(db_template, values=template_values), email_reply_to=email_reply_to, sms_sender=sms_sender ) @@ -462,22 +343,6 @@ def send_one_off_step(service_id, template_id, step_index): template_id=template_id, )) - # if we're in a letter, we should show address block rather than "address line #" or "postcode" - if template.template_type == 'letter': - if step_index < len(address_lines_1_to_7_keys): - return redirect(url_for( - '.send_one_off_letter_address', - service_id=service_id, - template_id=template_id, - )) - if current_placeholder in InsensitiveDict(PostalAddress('').as_personalisation): - return redirect(url_for( - request.endpoint, - service_id=service_id, - template_id=template_id, - step_index=step_index + 1, - )) - form = get_placeholder_form_instance( current_placeholder, dict_to_populate_from=get_normalised_placeholders_from_session(), @@ -487,12 +352,8 @@ def send_one_off_step(service_id, template_id, step_index): if form.validate_on_submit(): # if it's the first input (phone/email), we store against `recipient` as well, for easier extraction. - # Only if it's not a letter. - # And only if we're not on the test route, since that will already have the user's own number set - if ( - step_index == 0 - and template.template_type != 'letter' - ): + # Only if we're not on the test route, since that will already have the user's own number set + if step_index == 0: session['recipient'] = form.placeholder_value.data session['placeholders'][current_placeholder] = form.placeholder_value.data @@ -542,12 +403,6 @@ def send_test_preview(service_id, template_id, filetype): template = get_template( db_template, current_service, - letter_preview_url=url_for( - 'no_cookie.send_test_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), ) template.values = get_normalised_placeholders_from_session() @@ -596,7 +451,7 @@ def send_from_contact_list(service_id, template_id, contact_list_id): )) -def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_pdf=False): +def _check_messages(service_id, template_id, upload_id, preview_row): 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. @@ -633,20 +488,8 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_ db_template, current_service, show_recipient=True, - letter_preview_url=url_for( - 'no_cookie.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, - # In this case, we don't provide template values when calculating the page count - # because we don't know them at this point. It means that later on we will need to - # recalculate the page count once we have the values - page_count=get_page_count_for_letter(db_template), ) recipients = RecipientCSV( contents, @@ -658,11 +501,10 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_ ) if current_service.trial_mode else None, remaining_messages=remaining_messages, allow_international_sms=current_service.has_permission('international_sms'), - allow_international_letters=current_service.has_permission('international_letters'), ) if request.args.get('from_test'): - # only happens if generating a letter preview test + # TODO: may not be required after letters code removed back_link = url_for('main.send_one_off', service_id=service_id, template_id=template.id) choose_time_form = None else: @@ -677,9 +519,6 @@ 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) - template.page_count = page_count - original_file_name = get_csv_metadata(service_id, upload_id).get('original_file_name', '') return dict( @@ -695,20 +534,11 @@ def _check_messages(service_id, template_id, upload_id, preview_row, letters_as_ remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, - trying_to_send_letters_in_trial_mode=all(( - current_service.trial_mode, - template.template_type == 'letter', - )), first_recipient_column=recipients.recipient_column_headers[0], preview_row=preview_row, sent_previously=job_api_client.has_sent_previously( service_id, template.id, db_template['version'], original_file_name ), - letter_too_long=is_letter_too_long(page_count), - letter_max_pages=LETTER_MAX_PAGE_COUNT, - letter_min_address_lines=PostalAddress.MIN_LINES, - letter_max_address_lines=PostalAddress.MAX_LINES, - page_count=page_count ) @@ -737,7 +567,6 @@ def check_messages(service_id, template_id, upload_id, row_index=2): if ( data['errors'] - or data['trying_to_send_letters_in_trial_mode'] ): return render_template('views/check/column-errors.html', **data) @@ -748,8 +577,7 @@ def check_messages(service_id, template_id, upload_id, row_index=2): 'original_file_name': data.get('original_file_name', ''), } - if session.get('sender_id') and data['template'].template_type != 'letter': - # sender_id is not an option for sending letters. + if session.get('sender_id'): metadata_kwargs['sender_id'] = session['sender_id'] set_metadata_on_csv_upload(service_id, upload_id, **metadata_kwargs) @@ -767,6 +595,7 @@ def check_messages(service_id, template_id, upload_id, row_index=2): ) @user_has_permissions('send_messages') def check_messages_preview(service_id, template_id, upload_id, filetype, row_index=2): + # TODO: likely candidate for deletion if filetype == 'pdf': page = None elif filetype == 'png': @@ -775,7 +604,7 @@ def check_messages_preview(service_id, template_id, upload_id, filetype, row_ind abort(404) template = _check_messages( - service_id, template_id, upload_id, row_index, letters_as_pdf=True + service_id, template_id, upload_id, row_index )['template'] return TemplatePreview.from_utils_template(template, filetype, page=page) @@ -823,9 +652,6 @@ def start_job(service_id, upload_id): def fields_to_fill_in(template, prefill_current_user=False): - if 'letter' == template.template_type: - return letter_address_columns + list(template.placeholders) - if not prefill_current_user: return first_column_headings[template.template_type] + list(template.placeholders) @@ -881,20 +707,6 @@ def get_back_link(service_id, template, step_index, placeholders=None): template_id=template.id, ) - if template.template_type == 'letter' and placeholders: - # Make sure we’re not redirecting users to a page which will - # just redirect them forwards again - back_link_destination_step_index = next(( - index - for index, placeholder in reversed( - list(enumerate(placeholders[:step_index])) - ) - if placeholder not in InsensitiveDict( - PostalAddress('').as_personalisation - ) - ), 1) - return get_back_link(service_id, template, back_link_destination_step_index + 1) - return url_for( 'main.send_one_off_step', service_id=service_id, @@ -964,13 +776,6 @@ def _check_notification(service_id, template_id, exception=None): show_recipient=True, email_reply_to=email_reply_to, sms_sender=sms_sender, - letter_preview_url=url_for( - 'no_cookie.check_notification_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), - page_count=get_page_count_for_letter(db_template), ) placeholders = fields_to_fill_in(template) @@ -980,21 +785,15 @@ def _check_notification(service_id, template_id, exception=None): if ( ( not session.get('recipient') - and db_template['template_type'] != 'letter' ) or not all_placeholders_in_session(template.placeholders) ): 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) - template.page_count = page_count return dict( template=template, back_link=back_link, - 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 {}), ) @@ -1086,11 +885,7 @@ def get_sms_sender_from_session(): def get_spreadsheet_column_headings_from_template(template): column_headings = [] - if template.template_type == 'letter': - # We want to avoid showing `address line 7` for now - recipient_columns = letter_address_columns - else: - recipient_columns = first_column_headings[template.template_type] + recipient_columns = first_column_headings[template.template_type] for column_heading in ( recipient_columns + list(template.placeholders) diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index f325aae29..96382cdcc 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -22,7 +22,6 @@ from app import ( current_service, email_branding_client, inbound_number_client, - letter_branding_client, notification_api_client, organisations_client, service_api_client, @@ -46,16 +45,13 @@ from app.main.forms import ( AdminServiceRateLimitForm, AdminServiceSMSAllowanceForm, AdminSetEmailBrandingForm, - AdminSetLetterBrandingForm, AdminSetOrganisationForm, ChooseEmailBrandingForm, - ChooseLetterBrandingForm, EstimateUsageForm, RenameServiceForm, SearchByNameForm, ServiceContactDetailsForm, ServiceEditInboundNumberForm, - ServiceLetterContactBlockForm, ServiceOnOffSettingForm, ServiceReplyToEmailForm, ServiceSmsSenderForm, @@ -76,7 +72,6 @@ from app.utils.user import ( PLATFORM_ADMIN_SERVICE_PERMISSIONS = OrderedDict([ ('inbound_sms', {'title': 'Receive inbound SMS', 'requires': 'sms', 'endpoint': '.service_set_inbound_number'}), ('email_auth', {'title': 'Email authentication'}), - ('international_letters', {'title': 'Send international letters', 'requires': 'letter'}), ]) @@ -132,7 +127,6 @@ def estimate_usage(service_id): form = EstimateUsageForm( volume_email=current_service.volume_email, volume_sms=current_service.volume_sms, - volume_letter=current_service.volume_letter, consent_to_research={ True: 'yes', False: 'no', @@ -143,7 +137,6 @@ def estimate_usage(service_id): current_service.update( volume_email=form.volume_email.data, volume_sms=form.volume_sms.data, - volume_letter=form.volume_letter.data, consent_to_research=(form.consent_to_research.data == 'yes'), ) return redirect(url_for( @@ -607,27 +600,6 @@ def service_set_international_sms(service_id): ) -@main.route("/services//service-settings/set-international-letters", methods=['GET', 'POST']) -@user_has_permissions('manage_service') -def service_set_international_letters(service_id): - form = ServiceOnOffSettingForm( - 'Send letters to international addresses', - enabled=current_service.has_permission('international_letters'), - ) - if form.validate_on_submit(): - current_service.force_permission( - 'international_letters', - on=form.enabled.data, - ) - return redirect( - url_for(".service_settings", service_id=service_id) - ) - return render_template( - 'views/service-settings/set-international-letters.html', - form=form, - ) - - @main.route("/services//service-settings/set-inbound-sms", methods=['GET']) @user_has_permissions('manage_service') def service_set_inbound_sms(service_id): @@ -636,24 +608,11 @@ def service_set_inbound_sms(service_id): ) -@main.route("/services//service-settings/set-letters", methods=['GET']) -@user_has_permissions('manage_service') -def service_set_letters(service_id): - return redirect( - url_for( - '.service_set_channel', - service_id=current_service.id, - channel='letter', - ), - code=301, - ) - - @main.route("/services//service-settings/set-", methods=['GET', 'POST']) @user_has_permissions('manage_service') def service_set_channel(service_id, channel): - if channel not in {'email', 'sms', 'letter'}: + if channel not in {'email', 'sms'}: abort(404) form = ServiceSwitchChannelForm( @@ -684,103 +643,6 @@ def service_set_auth_type(service_id): ) -@main.route("/services//service-settings/letter-contacts", methods=['GET']) -@user_has_permissions('manage_service', 'manage_api_keys') -def service_letter_contact_details(service_id): - letter_contact_details = service_api_client.get_letter_contacts(service_id) - return render_template( - 'views/service-settings/letter-contact-details.html', - letter_contact_details=letter_contact_details) - - -@main.route("/services//service-settings/letter-contact/add", methods=['GET', 'POST']) -@user_has_permissions('manage_service') -def service_add_letter_contact(service_id): - form = ServiceLetterContactBlockForm() - first_contact_block = current_service.count_letter_contact_details == 0 - from_template = request.args.get('from_template') - if form.validate_on_submit(): - new_letter_contact = service_api_client.add_letter_contact( - current_service.id, - contact_block=form.letter_contact_block.data.replace('\r', '') or None, - is_default=first_contact_block if first_contact_block else form.is_default.data - ) - if from_template: - service_api_client.update_service_template_sender( - service_id, - from_template, - new_letter_contact['data']['id'], - ) - return redirect( - url_for('.view_template', service_id=service_id, template_id=from_template) - ) - return redirect(url_for('.service_letter_contact_details', service_id=service_id)) - return render_template( - 'views/service-settings/letter-contact/add.html', - form=form, - first_contact_block=first_contact_block, - back_link=( - url_for('main.view_template', template_id=from_template, service_id=current_service.id) - if from_template - else url_for('.service_letter_contact_details', service_id=current_service.id) - ), - ) - - -@main.route( - "/services//service-settings/letter-contact//edit", - methods=['GET', 'POST'], - endpoint="service_edit_letter_contact", -) -@main.route( - "/services//service-settings/letter-contact//delete", - methods=['GET'], - endpoint="service_confirm_delete_letter_contact", -) -@user_has_permissions('manage_service') -def service_edit_letter_contact(service_id, letter_contact_id): - letter_contact_block = current_service.get_letter_contact_block(letter_contact_id) - form = ServiceLetterContactBlockForm( - letter_contact_block=letter_contact_block['contact_block'] - ) - if request.method == 'GET': - form.is_default.data = letter_contact_block['is_default'] - if form.validate_on_submit(): - current_service.edit_letter_contact_block( - id=letter_contact_id, - contact_block=form.letter_contact_block.data.replace('\r', '') or None, - is_default=letter_contact_block['is_default'] or form.is_default.data - ) - return redirect(url_for('.service_letter_contact_details', service_id=service_id)) - - if (request.endpoint == "main.service_confirm_delete_letter_contact"): - flash("Are you sure you want to delete this contact block?", 'delete') - return render_template( - 'views/service-settings/letter-contact/edit.html', - form=form, - letter_contact_id=letter_contact_block['id']) - - -@main.route("/services//service-settings/letter-contact/make-blank-default") -@user_has_permissions('manage_service') -def service_make_blank_default_letter_contact(service_id): - current_service.remove_default_letter_contact_block() - return redirect(url_for('.service_letter_contact_details', service_id=service_id)) - - -@main.route( - "/services//service-settings/letter-contact//delete", - methods=['POST'], -) -@user_has_permissions('manage_service') -def service_delete_letter_contact(service_id, letter_contact_id): - service_api_client.delete_letter_contact( - service_id=current_service.id, - letter_contact_id=letter_contact_id, - ) - return redirect(url_for('.service_letter_contact_details', service_id=current_service.id)) - - @main.route("/services//service-settings/sms-sender", methods=['GET']) @user_has_permissions('manage_service', 'manage_api_keys') def service_sms_senders(service_id): @@ -956,51 +818,6 @@ def service_preview_email_branding(service_id): ) -@main.route("/services//service-settings/set-letter-branding", methods=['GET', 'POST']) -@user_is_platform_admin -def service_set_letter_branding(service_id): - letter_branding = letter_branding_client.get_all_letter_branding() - - form = AdminSetLetterBrandingForm( - all_branding_options=get_branding_as_value_and_label(letter_branding), - current_branding=current_service.letter_branding_id, - ) - - if form.validate_on_submit(): - return redirect(url_for( - '.service_preview_letter_branding', - service_id=service_id, - branding_style=form.branding_style.data, - )) - - return render_template( - 'views/service-settings/set-letter-branding.html', - form=form, - search_form=SearchByNameForm() - ) - - -@main.route("/services//service-settings/preview-letter-branding", methods=['GET', 'POST']) -@user_is_platform_admin -def service_preview_letter_branding(service_id): - branding_style = request.args.get('branding_style') - - form = AdminPreviewBrandingForm(branding_style=branding_style) - - if form.validate_on_submit(): - current_service.update( - letter_branding=form.branding_style.data - ) - return redirect(url_for('.service_settings', service_id=service_id)) - - return render_template( - 'views/service-settings/preview-letter-branding.html', - form=form, - service_id=service_id, - action=url_for('main.service_preview_letter_branding', service_id=service_id), - ) - - @main.route("/services//service-settings/link-service-to-organisation", methods=['GET', 'POST']) @user_is_platform_admin def link_service_to_organisation(service_id): @@ -1156,46 +973,6 @@ def email_branding_something_else(service_id): ) -@main.route("/services//service-settings/letter-branding", methods=['GET', 'POST']) -@user_has_permissions('manage_service') -def letter_branding_request(service_id): - form = ChooseLetterBrandingForm(current_service) - from_template = request.args.get('from_template') - branding_name = current_service.letter_branding_name - if form.validate_on_submit(): - ticket_message = render_template( - 'support-tickets/branding-request.txt', - current_branding=branding_name, - branding_requested=dict(form.options.choices)[form.options.data], - detail=form.something_else.data, - ) - ticket = NotifySupportTicket( - subject=f'Letter 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.organisation_id, - org_type=current_service.organisation_type, - service_id=current_service.id - ) - zendesk_client.send_ticket_to_zendesk(ticket) - flash(( - 'Thanks for your branding request. We’ll get back to you ' - 'within one working day.' - ), 'default') - return redirect(url_for( - '.view_template', service_id=current_service.id, template_id=from_template - ) if from_template else url_for('.service_settings', service_id=current_service.id)) - - return render_template( - 'views/service-settings/branding/letter-branding-options.html', - form=form, - branding_name=branding_name, - from_template=from_template - ) - - @main.route("/services//data-retention", methods=['GET']) @user_is_platform_admin def data_retention(service_id): diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index df5a21918..f1ad0b092 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -12,10 +12,6 @@ def features_nav(): "name": "Text messages", "link": "main.features_sms", }, - # { - # "name": "Letters", - # "link": "main.features_letters", - # }, ] }, { @@ -67,14 +63,6 @@ def using_notify_nav(): # "name": "Send files by email", # "link": "main.send_files_by_email", # }, - # { - # "name": "Upload a letter", - # "link": "main.upload_a_letter", - # }, - # { - # "name": "Letter specification", - # "link": "main.letter_specification", - # }, ] }, # { diff --git a/app/main/views/templates.py b/app/main/views/templates.py index d20756616..6ebafa539 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -11,8 +11,7 @@ from flask import ( ) from flask_login import current_user from notifications_python_client.errors import HTTPError -from notifications_utils import LETTER_MAX_PAGE_COUNT, SMS_CHAR_COUNT_LIMIT -from notifications_utils.pdf import is_letter_too_long +from notifications_utils import SMS_CHAR_COUNT_LIMIT from app import ( current_service, @@ -26,8 +25,6 @@ from app.formatters import character_count, message_count from app.main import main, no_cookie from app.main.forms import ( EmailTemplateForm, - LetterTemplateForm, - LetterTemplatePostageForm, SearchTemplatesForm, SetTemplateSenderForm, SMSTemplateForm, @@ -37,15 +34,14 @@ from app.main.forms import ( from app.main.views.send import get_sender_details from app.models.service import Service from app.models.template_list import TemplateList, TemplateLists -from app.template_previews import TemplatePreview, get_page_count_for_letter +from app.template_previews import TemplatePreview from app.utils import NOTIFICATION_TYPES, should_skip_template_page from app.utils.templates import get_template -from app.utils.user import user_has_permissions, user_is_platform_admin +from app.utils.user import user_has_permissions form_objects = { 'email': EmailTemplateForm, 'sms': SMSTemplateForm, - 'letter': LetterTemplateForm, } @@ -61,27 +57,14 @@ def view_template(service_id, template_id): '.set_sender', 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( template, current_service, - letter_preview_url=url_for( - 'no_cookie.view_letter_template_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), show_recipient=True, - page_count=page_count, ), - 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 ) @@ -199,7 +182,6 @@ def get_template_nav_label(value): 'all': 'All', 'sms': 'Text message', 'email': 'Email', - 'letter': 'Letter', }[value] @@ -218,56 +200,10 @@ def get_template_nav_items(template_folder_id): ] -@no_cookie.route("/services//templates/.") -@user_has_permissions() -def view_letter_template_preview(service_id, template_id, filetype): - if filetype not in ('pdf', 'png'): - abort(404) - - db_template = current_service.get_template(template_id) - - return TemplatePreview.from_database_object(db_template, filetype, page=request.args.get('page')) - - -@no_cookie.route("/templates/letter-preview-image/") -@user_is_platform_admin -def letter_branding_preview_image(filename): - template = { - 'subject': 'An example letter', - 'content': ( - 'Lorem Ipsum is simply dummy text of the printing and typesetting ' - 'industry.\n\nLorem Ipsum has been the industry’s 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\nIt 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' - '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.' - ), - 'template_type': 'letter', - } - filename = None if filename == 'no-branding' else filename - - return TemplatePreview.from_example_template(template, filename) - - -def _view_template_version(service_id, template_id, version, letters_as_pdf=False): +def _view_template_version(service_id, template_id, version): return dict(template=get_template( current_service.get_template(template_id, version=version), - current_service, - letter_preview_url=url_for( - 'no_cookie.view_template_version_preview', - service_id=service_id, - template_id=template_id, - version=version, - filetype='png', - ) if not letters_as_pdf else None + current_service )) @@ -295,22 +231,6 @@ def _add_template_by_type(template_type, template_folder_id): service_id=current_service.id, )) - if template_type == 'letter': - blank_letter = service_api_client.create_service_template( - 'New letter template', - 'letter', - 'Body', - current_service.id, - 'Main heading', - 'normal', - template_folder_id - ) - return redirect(url_for( - '.view_template', - service_id=current_service.id, - template_id=blank_letter['data']['id'], - )) - return redirect(url_for( '.add_service_template', service_id=current_service.id, @@ -724,12 +644,6 @@ def delete_service_template(service_id, template_id): template=get_template( template, current_service, - letter_preview_url=url_for( - 'no_cookie.view_letter_template_preview', - service_id=service_id, - template_id=template['id'], - filetype='png', - ), show_recipient=True, ), user_has_template_permission=True, @@ -746,12 +660,6 @@ def confirm_redact_template(service_id, template_id): template=get_template( template, current_service, - letter_preview_url=url_for( - 'no_cookie.view_letter_template_preview', - service_id=service_id, - template_id=template_id, - filetype='png', - ), show_recipient=True, ), user_has_template_permission=True, @@ -786,13 +694,6 @@ def view_template_versions(service_id, template_id): get_template( template, current_service, - letter_preview_url=url_for( - 'no_cookie.view_template_version_preview', - service_id=service_id, - template_id=template_id, - version=template['version'], - filetype='png', - ) ) for template in service_api_client.get_service_template_versions(service_id, template_id)['data'] ] @@ -835,36 +736,11 @@ def set_template_sender(service_id, template_id): ) -@main.route('/services//templates//edit-postage', methods=['GET', 'POST']) -@user_has_permissions('manage_templates') -def edit_template_postage(service_id, template_id): - template = current_service.get_template_with_user_permission_or_403(template_id, current_user) - if template["template_type"] != "letter": - abort(404) - form = LetterTemplatePostageForm(**template) - if form.validate_on_submit(): - postage = form.postage.data - service_api_client.update_service_template_postage(service_id, template_id, postage) - - return redirect(url_for('.view_template', service_id=service_id, template_id=template_id)) - - return render_template( - 'views/templates/edit-template-postage.html', - form=form, - service_id=service_id, - template_id=template_id, - template_postage=template["postage"] - ) - - def get_template_sender_form_dict(service_id, template): context = { 'email': { 'field_name': 'email_address' }, - 'letter': { - 'field_name': 'contact_block' - }, 'sms': { 'field_name': 'sms_sender' } @@ -881,5 +757,5 @@ def get_template_sender_form_dict(service_id, template): context['value_and_label'] = [(sender['id'], nl2br(sender[sender_format])) for sender in service_senders] context['value_and_label'].insert(0, ('', 'Blank')) # Add blank option to start of list - context['current_choice'] = template['service_letter_contact'] if template['service_letter_contact'] else '' + context['current_choice'] = '' return context diff --git a/app/main/views/uploads.py b/app/main/views/uploads.py index 910fe36e4..8ab61cc0c 100644 --- a/app/main/views/uploads.py +++ b/app/main/views/uploads.py @@ -1,50 +1,23 @@ -import base64 import itertools -import json -import uuid from datetime import datetime from io import BytesIO from zipfile import BadZipFile -from flask import ( - abort, - current_app, - flash, - redirect, - render_template, - request, - send_file, - url_for, -) +from flask import flash, redirect, render_template, request, send_file, url_for from notifications_utils.insensitive_dict import InsensitiveDict -from notifications_utils.pdf import pdf_page_count -from notifications_utils.postal_address import PostalAddress from notifications_utils.recipients import RecipientCSV from notifications_utils.sanitise_text import SanitiseASCII -from PyPDF2.errors import PdfReadError -from requests import RequestException from xlrd.biffh import XLRDError from xlrd.xldate import XLDateError -from app import current_service, notification_api_client, service_api_client -from app.extensions import antivirus_client +from app import current_service from app.main import main -from app.main.forms import CsvUploadForm, LetterUploadPostageForm, PDFUploadForm +from app.main.forms import CsvUploadForm from app.models.contact_list import ContactList -from app.s3_client.s3_letter_upload_client import ( - LetterNotFoundError, - backup_original_letter_to_s3, - get_letter_metadata, - get_letter_pdf_and_metadata, - get_transient_letter_file_location, - upload_letter_to_s3, -) -from app.template_previews import TemplatePreview, sanitise_letter from app.utils import unicode_truncate from app.utils.csv import Spreadsheet, get_errors_for_csv -from app.utils.letters import get_letter_validation_error from app.utils.pagination import generate_next_dict, generate_previous_dict -from app.utils.templates import get_sample_template, get_template +from app.utils.templates import get_sample_template from app.utils.user import user_has_permissions MAX_FILE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB @@ -82,253 +55,6 @@ def uploads(service_id): ) -@main.route("/services//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() - original_filename = form.file.data.filename - - if current_app.config['ANTIVIRUS_ENABLED']: - virus_free = antivirus_client.scan(BytesIO(pdf_file_bytes)) - if not virus_free: - return invalid_upload_error('Your file contains a virus') - - if len(pdf_file_bytes) > MAX_FILE_UPLOAD_SIZE: - 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.error('Invalid PDF uploaded for service_id: {}'.format(service_id)) - return invalid_upload_error( - "There’s a problem with your file", - 'Notify cannot read this PDF.
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) - - try: - response = sanitise_letter( - BytesIO(pdf_file_bytes), - upload_id=upload_id, - allow_international_letters=current_service.has_permission( - 'international_letters' - ), - ) - 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, - message=validation_failed_message, - invalid_pages=invalid_pages) - else: - raise ex - else: - response = response.json() - recipient = response['recipient_address'] - status = 'valid' - file_contents = base64.b64decode(response['file'].encode()) - - upload_letter_to_s3( - file_contents, - file_location=file_location, - status=status, - page_count=page_count, - filename=original_filename, - recipient=recipient) - - backup_original_letter_to_s3( - pdf_file_bytes, - upload_id=upload_id, - ) - - return redirect( - url_for( - 'main.uploaded_letter_preview', - service_id=current_service.id, - file_id=upload_id, - ) - ) - - 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(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//preview-letter/") -@user_has_permissions('send_messages') -def uploaded_letter_preview(service_id, file_id): - re_upload_form = PDFUploadForm() - - try: - metadata = get_letter_metadata(service_id, file_id) - except LetterNotFoundError as e: - current_app.logger.warning(e) - - # If the file is missing it's likely because this is a duplicate - # request, the notification already exists and the file has been - # moved to a different bucket. Note that the ID of a precompiled - # notification is always set to the file_id. - return redirect(url_for( - '.view_notification', - service_id=service_id, - notification_id=file_id, - )) - - original_filename = metadata.get('filename') - page_count = metadata.get('page_count') - status = metadata.get('status') - error_shortcode = metadata.get('message') - invalid_pages = metadata.get('invalid_pages') - postal_address = PostalAddress(metadata.get('recipient', '')) - - if invalid_pages: - invalid_pages = json.loads(invalid_pages) - - error_message = get_letter_validation_error(error_shortcode, invalid_pages, page_count) - template_dict = service_api_client.get_precompiled_template(service_id) - # Override pre compiled letter template postage to none as it has not yet been picked even though - # the pre compiled letter template has its postage set as second class as the DB currently requires - # a non null value of postage for letter templates - template_dict['postage'] = None - - form = LetterUploadPostageForm( - postage_zone=postal_address.postage - ) - - template = get_template( - template_dict, - service_id, - letter_preview_url=url_for( - '.view_letter_upload_as_preview', - service_id=service_id, - file_id=file_id - ), - page_count=page_count - ) - - return render_template( - 'views/uploads/preview.html', - original_filename=original_filename, - template=template, - status=status, - file_id=file_id, - message=error_message, - error_code=error_shortcode, - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS, - postal_address=postal_address, - re_upload_form=re_upload_form - ) - - -@main.route("/services//preview-letter-image/") -@user_has_permissions('send_messages') -def view_letter_upload_as_preview(service_id, file_id): - try: - page = int(request.args.get('page')) - except ValueError: - abort(400) - - pdf_file, metadata = get_letter_pdf_and_metadata(service_id, file_id) - invalid_pages = json.loads(metadata.get('invalid_pages', '[]')) - - if ( - metadata.get('message') == 'content-outside-printable-area' and - page in invalid_pages - ): - return TemplatePreview.from_invalid_pdf_file(pdf_file, page) - else: - return TemplatePreview.from_valid_pdf_file(pdf_file, page) - - -@main.route("/services//upload-letter/send/", methods=['POST']) -@user_has_permissions('send_messages', restrict_admin_usage=True) -def send_uploaded_letter(service_id, file_id): - if not current_service.has_permission('letter'): - abort(403) - - try: - metadata = get_letter_metadata(service_id, file_id) - except LetterNotFoundError as e: - current_app.logger.warning(e) - - # If the file is missing it's likely because this is a duplicate - # request, the notification already exists and the file has been - # moved to a different bucket. Note that the ID of a precompiled - # notification is always set to the file_id. - return redirect(url_for( - '.view_notification', - service_id=service_id, - notification_id=file_id, - )) - - if metadata.get('status') != 'valid': - abort(403) - - postal_address = PostalAddress(metadata.get('recipient')) - - form = LetterUploadPostageForm( - postage_zone=postal_address.postage - ) - - if not form.validate_on_submit(): - return uploaded_letter_preview(service_id, file_id) - - notification_api_client.send_precompiled_letter( - service_id, - metadata.get('filename'), - file_id, - form.postage.data, - postal_address.raw_address, - ) - - return redirect(url_for( - '.view_notification', - service_id=service_id, - notification_id=file_id, - )) - - @main.route("/services//upload-contact-list", methods=['GET', 'POST']) @user_has_permissions('send_messages') def upload_contact_list(service_id): diff --git a/app/models/event.py b/app/models/event.py index 0a778fe24..2697ec01b 100644 --- a/app/models/event.py +++ b/app/models/event.py @@ -79,14 +79,6 @@ class ServiceEvent(Event): def format_inbound_api(self): return 'Updated the callback for received text messages' - def format_letter_branding(self): - if self.value_to is None: - return 'Removed the logo from this service’s letters' - return 'Updated the logo on this service’s letters' - - def format_letter_contact_block(self): - return 'Updated the default letter contact block for this service' - def format_message_limit(self): return ( '{} this service’s daily message limit from {} to {}' diff --git a/app/models/job.py b/app/models/job.py index bf527c376..237452965 100644 --- a/app/models/job.py +++ b/app/models/job.py @@ -1,7 +1,3 @@ -from notifications_utils.letter_timings import ( - CANCELLABLE_JOB_LETTER_STATUSES, - get_letter_timings, -) from werkzeug.utils import cached_property from app.models import JSONModel, ModelList, PaginatedModelList @@ -51,10 +47,6 @@ class Job(JSONModel): def upload_type(self): return self._dict.get('upload_type') - @property - def pdf_letter(self): - return self.upload_type == 'letter' - @property def processing_started(self): if not self._dict.get('processing_started'): @@ -139,24 +131,11 @@ class Job(JSONModel): @property def uncancellable_notifications(self): + # TODO: this is redundant now return ( n for n in self.all_notifications - if n['status'] not in CANCELLABLE_JOB_LETTER_STATUSES ) - @cached_property - def postage(self): - # There might be no notifications if the job has only just been - # created and the tasks haven't run yet - try: - return self.all_notifications[0]['postage'] - except IndexError: - return self.template['postage'] - - @property - def letter_timings(self): - return get_letter_timings(self.created_at, postage=self.postage) - @property def failure_rate(self): if not self.notifications_delivered: diff --git a/app/models/organisation.py b/app/models/organisation.py index ac846bbbb..0492c6897 100644 --- a/app/models/organisation.py +++ b/app/models/organisation.py @@ -10,7 +10,6 @@ from app.models import ( SortByNameMixin, ) from app.notify_client.email_branding_client import email_branding_client -from app.notify_client.letter_branding_client import letter_branding_client from app.notify_client.organisations_api_client import organisations_client @@ -32,7 +31,6 @@ class Organisation(JSONModel, SortByNameMixin): 'active', 'crown', 'organisation_type', - 'letter_branding_id', 'email_branding_id', 'agreement_signed', 'agreement_signed_at', @@ -167,13 +165,6 @@ class Organisation(JSONModel, SortByNameMixin): return self.email_branding['name'] return 'GOV.UK' - @cached_property - def letter_branding(self): - if self.letter_branding_id: - return letter_branding_client.get_letter_branding( - self.letter_branding_id - ) - @cached_property def agreement_signed_by(self): if self.agreement_signed_by_id: diff --git a/app/models/service.py b/app/models/service.py index 054a5107c..3ea3d75aa 100644 --- a/app/models/service.py +++ b/app/models/service.py @@ -18,7 +18,6 @@ from app.notify_client.email_branding_client import email_branding_client from app.notify_client.inbound_number_client import inbound_number_client from app.notify_client.invite_api_client import invite_api_client from app.notify_client.job_api_client import job_api_client -from app.notify_client.letter_branding_client import letter_branding_client from app.notify_client.organisations_api_client import organisations_client from app.notify_client.service_api_client import service_api_client from app.notify_client.template_folder_api_client import ( @@ -52,20 +51,17 @@ class Service(JSONModel, SortByNameMixin): 'service_callback_api', 'volume_email', 'volume_sms', - 'volume_letter', } TEMPLATE_TYPES = ( 'email', 'sms', - 'letter', ) ALL_PERMISSIONS = TEMPLATE_TYPES + ( 'edit_folder_permissions', 'email_auth', 'inbound_sms', - 'international_letters', 'international_sms', 'upload_document', ) @@ -260,7 +256,6 @@ class Service(JSONModel, SortByNameMixin): self.consent_to_research is not None and any(( self.volume_email, self.volume_sms, - self.volume_letter, )) ) @@ -364,55 +359,11 @@ class Service(JSONModel, SortByNameMixin): self.sms_sender_is_govuk, )) - @cached_property - def letter_contact_details(self): - return service_api_client.get_letter_contacts(self.id) - - @property - def count_letter_contact_details(self): - return len(self.letter_contact_details) - - @property - def default_letter_contact_block(self): - return next( - ( - letter_contact_block - for letter_contact_block in self.letter_contact_details - if letter_contact_block['is_default'] - ), None - ) - - @property - def default_letter_contact_block_html(self): - # import in the function to prevent cyclical imports - from app import nl2br - - if self.default_letter_contact_block: - return nl2br(self.default_letter_contact_block['contact_block']) - return '' - - def edit_letter_contact_block(self, id, contact_block, is_default): - service_api_client.update_letter_contact( - self.id, letter_contact_id=id, contact_block=contact_block, is_default=is_default, - ) - - def remove_default_letter_contact_block(self): - if self.default_letter_contact_block: - self.edit_letter_contact_block( - self.default_letter_contact_block['id'], - self.default_letter_contact_block['contact_block'], - is_default=False, - ) - - def get_letter_contact_block(self, id): - return service_api_client.get_letter_contact(self.id, id) - @property def volumes(self): return sum(filter(None, ( self.volume_email, self.volume_sms, - self.volume_letter, ))) @property @@ -465,26 +416,10 @@ class Service(JSONModel, SortByNameMixin): return 'GOV.UK' return self.email_branding['name'] - @cached_property - def letter_branding_name(self): - if self.letter_branding is None: - return 'no' - return self.letter_branding['name'] - @property def needs_to_change_email_branding(self): return self.email_branding_id is None and self.organisation_type != Organisation.TYPE_CENTRAL - @property - def letter_branding_id(self): - return self._dict['letter_branding'] - - @cached_property - def letter_branding(self): - if self.letter_branding_id: - return letter_branding_client.get_letter_branding(self.letter_branding_id) - return None - @cached_property def organisation(self): return Organisation.from_id(self.organisation_id) @@ -592,26 +527,6 @@ class Service(JSONModel, SortByNameMixin): } ) - @cached_property - def returned_letter_statistics(self): - return service_api_client.get_returned_letter_statistics(self.id) - - @cached_property - def returned_letter_summary(self): - return service_api_client.get_returned_letter_summary(self.id) - - @property - def count_of_returned_letters_in_last_7_days(self): - return self.returned_letter_statistics['returned_letter_count'] - - @property - def date_of_most_recent_returned_letter_report(self): - return self.returned_letter_statistics['most_recent_report'] - - @property - def has_returned_letters(self): - return bool(self.date_of_most_recent_returned_letter_report) - @property def contact_lists(self): return ContactLists(self.id) diff --git a/app/navigation.py b/app/navigation.py index 7a0468508..812386686 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -47,7 +47,6 @@ class HeaderNavigation(Navigation): 'features': { 'features', 'features_email', - 'features_letters', 'features_sms', 'message_status', 'roadmap', @@ -84,12 +83,10 @@ class HeaderNavigation(Navigation): 'change_user_auth', 'clear_cache', 'create_email_branding', - 'create_letter_branding', 'edit_sms_provider_ratio', 'email_branding', 'find_services_by_name', 'find_users_by_email', - 'letter_branding', 'live_services', 'live_services_csv', 'notifications_sent_by_service', @@ -101,12 +98,10 @@ class HeaderNavigation(Navigation): 'platform_admin', 'platform_admin_list_complaints', 'platform_admin_reports', - 'platform_admin_returned_letters', 'platform_admin_splash_page', 'suspend_service', 'trial_services', 'update_email_branding', - 'update_letter_branding', 'user_information', 'view_provider', 'view_providers', @@ -136,8 +131,6 @@ class MainNavigation(Navigation): 'conversation', 'inbox', 'monthly', - 'returned_letter_summary', - 'returned_letters', 'service_dashboard', 'template_usage', 'view_notification', @@ -156,11 +149,9 @@ class MainNavigation(Navigation): 'copy_template', 'delete_service_template', 'edit_service_template', - 'edit_template_postage', 'manage_template_folder', 'send_messages', 'send_one_off', - 'send_one_off_letter_address', 'send_one_off_step', 'send_one_off_to_myself', 'no_cookie.send_test_preview', @@ -176,8 +167,6 @@ class MainNavigation(Navigation): 'save_contact_list', 'contact_list', 'delete_contact_list', - 'upload_letter', - 'uploaded_letter_preview', 'uploads', 'view_job', 'view_jobs', @@ -205,36 +194,27 @@ class MainNavigation(Navigation): 'email_branding_request', 'email_branding_something_else', 'estimate_usage', - 'letter_branding_request', 'link_service_to_organisation', 'request_to_go_live', 'service_add_email_reply_to', - 'service_add_letter_contact', 'service_add_sms_sender', 'service_agreement', 'service_accept_agreement', 'service_confirm_agreement', 'service_confirm_delete_email_reply_to', - 'service_confirm_delete_letter_contact', 'service_confirm_delete_sms_sender', 'service_edit_email_reply_to', - 'service_edit_letter_contact', 'service_edit_sms_sender', 'service_email_reply_to', - 'service_letter_contact_details', - 'service_make_blank_default_letter_contact', 'service_name_change', 'service_preview_email_branding', - 'service_preview_letter_branding', 'service_set_auth_type', 'service_set_channel', 'send_files_by_email_contact_details', 'service_set_email_branding', 'service_set_inbound_number', 'service_set_inbound_sms', - 'service_set_international_letters', 'service_set_international_sms', - 'service_set_letters', 'service_set_reply_to_email', 'service_set_sms_prefix', 'service_verify_reply_to_address', @@ -244,7 +224,6 @@ class MainNavigation(Navigation): 'set_free_sms_allowance', 'set_message_limit', 'set_rate_limit', - 'service_set_letter_branding', 'submit_request_to_go_live', }, 'api-integration': { @@ -269,7 +248,6 @@ class CaseworkNavigation(Navigation): 'choose_from_contact_list', 'choose_template', 'send_one_off', - 'send_one_off_letter_address', 'send_one_off_step', 'send_one_off_to_myself', }, @@ -285,8 +263,6 @@ class CaseworkNavigation(Navigation): 'save_contact_list', 'contact_list', 'delete_contact_list', - 'upload_letter', - 'uploaded_letter_preview', 'uploads', }, } @@ -304,14 +280,12 @@ class OrgNavigation(Navigation): 'edit_organisation_crown_status', 'edit_organisation_domains', 'edit_organisation_email_branding', - 'edit_organisation_letter_branding', 'edit_organisation_domains', 'edit_organisation_go_live_notes', 'edit_organisation_name', 'edit_organisation_notes', 'edit_organisation_type', 'organisation_preview_email_branding', - 'organisation_preview_letter_branding', 'organisation_settings', }, diff --git a/app/notify_client/letter_branding_client.py b/app/notify_client/letter_branding_client.py deleted file mode 100644 index 736d9d025..000000000 --- a/app/notify_client/letter_branding_client.py +++ /dev/null @@ -1,32 +0,0 @@ -from app.notify_client import NotifyAdminAPIClient, cache - - -class LetterBrandingClient(NotifyAdminAPIClient): - - @cache.set('letter_branding-{branding_id}') - def get_letter_branding(self, branding_id): - return self.get(url='/letter-branding/{}'.format(branding_id)) - - @cache.set('letter_branding') - def get_all_letter_branding(self): - return self.get(url='/letter-branding') - - @cache.delete('letter_branding') - def create_letter_branding(self, filename, name): - data = { - "filename": filename, - "name": name, - } - return self.post(url="/letter-branding", data=data) - - @cache.delete('letter_branding') - @cache.delete('letter_branding-{branding_id}') - def update_letter_branding(self, branding_id, filename, name): - data = { - "filename": filename, - "name": name, - } - return self.post(url="/letter-branding/{}".format(branding_id), data=data) - - -letter_branding_client = LetterBrandingClient() diff --git a/app/notify_client/letter_jobs_client.py b/app/notify_client/letter_jobs_client.py deleted file mode 100644 index 6314642ee..000000000 --- a/app/notify_client/letter_jobs_client.py +++ /dev/null @@ -1,13 +0,0 @@ -from app.notify_client import NotifyAdminAPIClient - - -class LetterJobsClient(NotifyAdminAPIClient): - - def submit_returned_letters(self, references): - return self.post( - url='/letters/returned', - data={'references': references} - ) - - -letter_jobs_client = LetterJobsClient() diff --git a/app/notify_client/notification_api_client.py b/app/notify_client/notification_api_client.py index 5e38a8835..36afbbf2e 100644 --- a/app/notify_client/notification_api_client.py +++ b/app/notify_client/notification_api_client.py @@ -63,16 +63,6 @@ class NotificationApiClient(NotifyAdminAPIClient): data = _attach_current_user(data) return self.post(url='/service/{}/send-notification'.format(service_id), data=data) - def send_precompiled_letter(self, service_id, filename, file_id, postage, recipient_address): - data = { - 'filename': filename, - 'file_id': file_id, - 'postage': postage, - 'recipient_address': recipient_address - } - data = _attach_current_user(data) - return self.post(url='/service/{}/send-pdf-letter'.format(service_id), data=data) - def get_notification(self, service_id, notification_id): return self.get(url='/service/{}/notifications/{}'.format(service_id, notification_id)) @@ -84,29 +74,7 @@ class NotificationApiClient(NotifyAdminAPIClient): include_one_off=False, count_pages=False ) - return self.map_letters_to_accepted(ret) - - @staticmethod - def map_letters_to_accepted(notifications): - for notification in notifications['notifications']: - if notification['notification_type'] == 'letter': - if notification['status'] in ('created', 'sending'): - notification['status'] = 'accepted' - - if notification['status'] in ('delivered', 'returned-letter'): - notification['status'] = 'received' - return notifications - - def get_notification_letter_preview(self, service_id, notification_id, file_type, page=None): - - get_url = '/service/{}/template/preview/{}/{}{}'.format( - service_id, - notification_id, - file_type, - '?page={}'.format(page) if page else '' - ) - - return self.get(url=get_url) + return ret def update_notification_to_cancelled(self, service_id, notification_id): return self.post( diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index 83e8d3f87..449a5e4b0 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -88,8 +88,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): 'free_sms_fragment_limit', 'go_live_at', 'go_live_user', - 'letter_branding', - 'letter_contact_block', 'message_limit', 'name', 'notes', @@ -103,7 +101,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): 'restricted', 'sms_sender', 'volume_email', - 'volume_letter', 'volume_sms', } if disallowed_attributes: @@ -236,14 +233,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): data ) - @cache.delete('service-{service_id}-templates') - @cache.delete_by_pattern('service-{service_id}-template-*') - def update_service_template_postage(self, service_id, template_id, postage): - return self.post( - "/service/{0}/template/{1}".format(service_id, template_id), - _attach_current_user({'postage': postage}) - ) - @cache.set('service-{service_id}-template-{template_id}-version-{version}') def get_service_template(self, service_id, template_id, version=None): """ @@ -444,45 +433,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): data=None ) - def get_letter_contacts(self, service_id): - return self.get("/service/{}/letter-contact".format(service_id)) - - def get_letter_contact(self, service_id, letter_contact_id): - return self.get("/service/{}/letter-contact/{}".format(service_id, letter_contact_id)) - - @cache.delete('service-{service_id}') - @cache.delete_by_pattern('service-{service_id}-template-*') - def add_letter_contact(self, service_id, contact_block, is_default=False): - return self.post( - "/service/{}/letter-contact".format(service_id), - data={ - "contact_block": contact_block, - "is_default": is_default - } - ) - - @cache.delete('service-{service_id}') - @cache.delete_by_pattern('service-{service_id}-template-*') - def update_letter_contact(self, service_id, letter_contact_id, contact_block, is_default=False): - return self.post( - "/service/{}/letter-contact/{}".format( - service_id, - letter_contact_id, - ), - data={ - "contact_block": contact_block, - "is_default": is_default - } - ) - - @cache.delete('service-{service_id}') - @cache.delete_by_pattern('service-{service_id}-template-*') - def delete_letter_contact(self, service_id, letter_contact_id): - return self.post( - "/service/{}/letter-contact/{}/archive".format(service_id, letter_contact_id), - data=None - ) - def get_sms_senders(self, service_id): return self.get( "/service/{}/sms-sender".format(service_id) @@ -575,17 +525,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): def get_service_data_retention(self, service_id): return self.get("/service/{}/data-retention".format(service_id)) - @cache.set('service-{service_id}-returned-letters-statistics') - def get_returned_letter_statistics(self, service_id): - return self.get("service/{}/returned-letter-statistics".format(service_id)) - - @cache.set('service-{service_id}-returned-letters-summary') - def get_returned_letter_summary(self, service_id): - return self.get("service/{}/returned-letter-summary".format(service_id)) - - def get_returned_letters(self, service_id, reported_at): - return self.get("service/{}/returned-letters?reported_at={}".format(service_id, reported_at)) - def get_notification_count(self, service_id): # if cache is not set, or not enabled, return 0 diff --git a/app/s3_client/s3_letter_upload_client.py b/app/s3_client/s3_letter_upload_client.py deleted file mode 100644 index 4bb479fdb..000000000 --- a/app/s3_client/s3_letter_upload_client.py +++ /dev/null @@ -1,97 +0,0 @@ -import json -import urllib - -import botocore -from boto3 import resource -from flask import current_app -from notifications_utils.s3 import s3upload as utils_s3upload - - -class LetterNotFoundError(Exception): - pass - - -def get_transient_letter_file_location(service_id, upload_id): - return 'service-{}/{}.pdf'.format(service_id, upload_id) - - -def backup_original_letter_to_s3( - data, - upload_id, -): - utils_s3upload( - filedata=data, - region=current_app.config['AWS_REGION'], - bucket_name=current_app.config['PRECOMPILED_ORIGINALS_BACKUP_LETTERS'], - file_location=f'{upload_id}.pdf', - ) - - -def upload_letter_to_s3( - data, - *, - file_location, - status, - page_count, - filename, - message=None, - invalid_pages=None, - recipient=None -): - # Use of urllib.parse.quote encodes metadata into ascii, which is required by s3. - # Making sure data for displaying to users is decoded is taken care of by LetterMetadata - metadata = { - 'status': status, - 'page_count': str(page_count), - 'filename': urllib.parse.quote(filename), - } - if message: - metadata['message'] = message - if invalid_pages: - metadata['invalid_pages'] = json.dumps(invalid_pages) - if recipient: - metadata['recipient'] = urllib.parse.quote(recipient) - - utils_s3upload( - filedata=data, - region=current_app.config['AWS_REGION'], - bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'], - file_location=file_location, - metadata=metadata, - ) - - -class LetterMetadata: - KEYS_TO_DECODE = ["filename", "recipient"] - - def __init__(self, metadata): - self._metadata = metadata - - def get(self, key, default=None): - value = self._metadata.get(key, default) - if value and key in self.KEYS_TO_DECODE: - value = urllib.parse.unquote(value) - return value - - -def get_letter_s3_object(service_id, file_id): - try: - file_location = get_transient_letter_file_location(service_id, file_id) - s3 = resource('s3') - return s3.Object(current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location).get() - except botocore.exceptions.ClientError as e: - if e.response['Error']['Code'] == 'NoSuchKey': - raise LetterNotFoundError(f'Letter not found for service {service_id} and file {file_id}') - - raise - - -def get_letter_pdf_and_metadata(service_id, file_id): - s3_object = get_letter_s3_object(service_id, file_id) - pdf = s3_object['Body'].read() - return pdf, LetterMetadata(s3_object['Metadata']) - - -def get_letter_metadata(service_id, file_id): - s3_object = get_letter_s3_object(service_id, file_id) - return LetterMetadata(s3_object['Metadata']) diff --git a/app/s3_client/s3_logo_client.py b/app/s3_client/s3_logo_client.py index aba076624..dc432abec 100644 --- a/app/s3_client/s3_logo_client.py +++ b/app/s3_client/s3_logo_client.py @@ -8,9 +8,6 @@ from app.s3_client import get_s3_object TEMP_TAG = 'temp-{user_id}_' EMAIL_LOGO_LOCATION_STRUCTURE = '{temp}{unique_id}-{filename}' -LETTER_PREFIX = 'letters/static/images/letter-template/' -LETTER_TEMP_TAG = LETTER_PREFIX + TEMP_TAG -LETTER_TEMP_LOGO_LOCATION = 'letters/static/images/letter-template/temp-{user_id}_{unique_id}-{filename}' def get_logo_location(filename=None): @@ -53,10 +50,6 @@ def get_temp_truncated_filename(filename, user_id): return filename[len(TEMP_TAG.format(user_id=user_id)):] -def get_letter_filename_with_no_path_or_extension(filename): - return filename[len(LETTER_PREFIX):-4] - - def upload_email_logo(filename, filedata, user_id): upload_file_name = EMAIL_LOGO_LOCATION_STRUCTURE.format( temp=TEMP_TAG.format(user_id=user_id), @@ -77,26 +70,6 @@ def upload_email_logo(filename, filedata, user_id): return upload_file_name -def upload_letter_temp_logo(filename, filedata, user_id): - upload_filename = LETTER_TEMP_LOGO_LOCATION.format( - user_id=user_id, - unique_id=str(uuid.uuid4()), - filename=filename - ) - bucket_name = bucket_creds('bucket') - utils_s3upload( - filedata=filedata, - region=bucket_creds('region'), - bucket_name=bucket_name, - file_location=upload_filename, - content_type='image/svg+xml', - access_key=bucket_creds('access_key_id'), - secret_key=bucket_creds('secret_access_key'), - ) - - return upload_filename - - def permanent_email_logo_name(filename, user_id): if filename.startswith(TEMP_TAG.format(user_id=user_id)): return get_temp_truncated_filename(filename=filename, user_id=user_id) @@ -104,38 +77,13 @@ def permanent_email_logo_name(filename, user_id): return filename -def permanent_letter_logo_name(filename, extension): - return LETTER_PREFIX + filename + '.' + extension - - -def letter_filename_for_db(filename, user_id): - filename = get_letter_filename_with_no_path_or_extension(filename) - - if filename.startswith(TEMP_TAG.format(user_id=user_id)): - filename = get_temp_truncated_filename(filename=filename, user_id=user_id) - - return filename - - def delete_email_temp_files_created_by(user_id): for obj in get_s3_objects_filter_by_prefix(TEMP_TAG.format(user_id=user_id)): delete_s3_object(obj.key) -def delete_letter_temp_files_created_by(user_id): - for obj in get_s3_objects_filter_by_prefix(LETTER_TEMP_TAG.format(user_id=user_id)): - delete_s3_object(obj.key) - - def delete_email_temp_file(filename): if not filename.startswith(TEMP_TAG[:5]): raise ValueError('Not a temp file: {}'.format(filename)) delete_s3_object(filename) - - -def delete_letter_temp_file(filename): - if not filename.startswith(LETTER_TEMP_TAG[:43]): - raise ValueError('Not a temp file: {}'.format(filename)) - - delete_s3_object(filename) diff --git a/app/templates/components/branding-preview.html b/app/templates/components/branding-preview.html index 67d59ed79..db3e3001d 100644 --- a/app/templates/components/branding-preview.html +++ b/app/templates/components/branding-preview.html @@ -5,7 +5,3 @@ {% macro email_branding_preview(branding_style) %} {{ branding_preview(branding_style, 'main.email_template') }} {% endmacro %} - -{% macro letter_branding_preview(branding_style) %} - {{ branding_preview(branding_style, 'main.letter_template') }} -{% endmacro %} diff --git a/app/templates/components/table.html b/app/templates/components/table.html index cfd029ee8..f5e15c9eb 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -147,7 +147,7 @@ {% macro notification_status_field(notification) %} - {% set displayed_on_single_line = notification.status in ['created', 'pending', 'pending-virus-check', 'sending', 'delivered', 'returned-letter', 'accepted', 'received'] %} + {% set displayed_on_single_line = notification.status in ['created', 'pending', 'pending-virus-check', 'sending', 'delivered', 'accepted', 'received'] %} {% if not notification %} {% call field(align='right') %}{% endcall %} @@ -166,18 +166,10 @@ {% endif %} - {% if notification['notification_type'] == "letter" %} - {% if notification.status == 'permanent-failure' %} - {{ (notification.updated_at)|format_datetime_short }} - {% else %} - {{ (notification.created_at)|format_datetime_short }} - {% endif %} - {% else %} - {{ notification.status|format_notification_status_as_time( - notification.created_at|format_datetime_short, - (notification.updated_at or notification.created_at)|format_datetime_short - ) }} - {% endif %} + {{ notification.status|format_notification_status_as_time( + notification.created_at|format_datetime_short, + (notification.updated_at or notification.created_at)|format_datetime_short + ) }} {% if displayed_on_single_line %}{% endif %} {% endcall %} diff --git a/app/templates/partials/check/letter-too-long.html b/app/templates/partials/check/letter-too-long.html deleted file mode 100644 index 50d377945..000000000 --- a/app/templates/partials/check/letter-too-long.html +++ /dev/null @@ -1,8 +0,0 @@ -

- Your letter is too long -

-

- Letters must be {{ letter_max_pages }} pages or less ({{ letter_max_pages // 2 }} double-sided sheets of paper). -
- Your letter is {{ page_count }} pages long. -

diff --git a/app/templates/partials/check/letter-validation-failed-banner.html b/app/templates/partials/check/letter-validation-failed-banner.html deleted file mode 100644 index 6596c31dd..000000000 --- a/app/templates/partials/check/letter-validation-failed-banner.html +++ /dev/null @@ -1,18 +0,0 @@ -{% from "components/banner.html" import banner_wrapper %} - -{% call banner_wrapper(type='dangerous') %} - {% if message is string %} -

- {{ message }} -

- {% else %} -

- {{ message.title }} -

- {% if message.detail %} -

- {{ message.detail | safe }} -

- {% endif %} - {% endif %} -{% endcall %} diff --git a/app/templates/partials/check/trying-to-send-letters-in-trial-mode.html b/app/templates/partials/check/trying-to-send-letters-in-trial-mode.html deleted file mode 100644 index 3fec6e14a..000000000 --- a/app/templates/partials/check/trying-to-send-letters-in-trial-mode.html +++ /dev/null @@ -1,8 +0,0 @@ -

- You cannot send - {{ 'this letter' if count_of_recipients == 1 else 'these letters' }} -

-

- In trial mode you - can only preview how your letters will look -

diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html index e8a3f0973..7e181f578 100644 --- a/app/templates/partials/jobs/notifications.html +++ b/app/templates/partials/jobs/notifications.html @@ -24,25 +24,18 @@ {% if notifications %}
{% endif %} - - {% if job.template_type == 'letter' %} -
+ {% if job.still_processing %} +

+ Report is {{ "{:.0f}%".format(job.percentage_complete * 0.99) }} complete… +

+ {% elif notifications %} +

+ Download this report (CSV) +   + {{ time_left }} +

{% endif %} - {% if job.still_processing %} -

- Report is {{ "{:.0f}%".format(job.percentage_complete * 0.99) }} complete… -

- {% elif notifications %} -

- Download this report (CSV) -   - {{ time_left }} -

- {% endif %} - {% if job.template_type == 'letter' %} -
- {% endif %} - + {% call(item, row_number) list_table( notifications, caption=uploaded_file_name, diff --git a/app/templates/partials/templates/guidance-postage.html b/app/templates/partials/templates/guidance-postage.html deleted file mode 100644 index cac43b94d..000000000 --- a/app/templates/partials/templates/guidance-postage.html +++ /dev/null @@ -1,15 +0,0 @@ -

- Delivery times -

-

- Letters sent before 5:30pm are dispatched the next working day (Monday to Friday). -

-

- First class letters are delivered one day after they're dispatched. Second class letters are delivered 2 days after they're dispatched. -

-

- Royal Mail delivers from Monday to Saturday, excluding bank holidays. -

-

- See a list of postage prices. -

diff --git a/app/templates/support-tickets/go-live-request.txt b/app/templates/support-tickets/go-live-request.txt index 37abc2933..5042bf653 100644 --- a/app/templates/support-tickets/go-live-request.txt +++ b/app/templates/support-tickets/go-live-request.txt @@ -22,7 +22,6 @@ Agreement signed on behalf of: {{ organisation.agreement_signed_on_behalf_of_ema Emails in next year: {{ service.volume_email|format_thousands }} Text messages in next year: {{ service.volume_sms|format_thousands }} -Letters in next year: {{ service.volume_letter|format_thousands }} Consent to research: {{ service.consent_to_research|format_yes_no }} Other live services for that user: {{ user.live_services|format_yes_no }} diff --git a/app/templates/views/check/column-errors.html b/app/templates/views/check/column-errors.html index d8084654d..838b6bc7e 100644 --- a/app/templates/views/check/column-errors.html +++ b/app/templates/views/check/column-errors.html @@ -52,16 +52,9 @@

There’s a problem with your column names

- {% if template.template_type == 'letter' %} -

- Your file needs at least 3 address columns, for example ‘address line 1’, - ‘address line 2’ and ‘address line 3’. -

- {% else %}

Your file needs a column called ‘{{ first_recipient_column }}’.

- {% endif %}

Right now it has {{ recipients.column_headers | formatted_list( prefix='one column, called ', @@ -113,16 +106,6 @@ {% include "partials/check/not-allowed-to-send-to.html" %} {% endwith %} - {% elif trying_to_send_letters_in_trial_mode %} - -

- {% with - count_of_recipients=count_of_recipients - %} - {% include "partials/check/trying-to-send-letters-in-trial-mode.html" %} - {% endwith %} -
- {% elif recipients.more_rows_than_can_send %} {% include "partials/check/too-many-messages.html" %} @@ -165,15 +148,7 @@ {% call index_field() %} {% set displayed_index = item.index + 2 %} - {% if ( - trying_to_send_letters_in_trial_mode and - (not errors or recipients.more_rows_than_can_send) and - displayed_index != preview_row - ) %} - {{ displayed_index }} - {% else %} - {{ displayed_index }} - {% endif %} + {{ displayed_index }} {% endcall %} {% for column in column_headers %} diff --git a/app/templates/views/check/ok.html b/app/templates/views/check/ok.html index f8097874d..6faa23353 100644 --- a/app/templates/views/check/ok.html +++ b/app/templates/views/check/ok.html @@ -21,12 +21,6 @@ {{ page_header('Preview of {}'.format(template.name)) }} - {% if letter_too_long %} - {% call banner_wrapper(type='dangerous') %} - {% include "partials/check/letter-too-long.html" %} - {% endcall %} - {% endif %} - {{ govukSkipLink({ "text": "Skip to file contents", "href": "#" + file_contents_header_id @@ -37,7 +31,7 @@
diff --git a/app/templates/views/check/row-errors.html b/app/templates/views/check/row-errors.html index 2f28ab991..84f548af6 100644 --- a/app/templates/views/check/row-errors.html +++ b/app/templates/views/check/row-errors.html @@ -74,20 +74,6 @@ No content for this message {% elif item.message_too_long %} Message is too long - {% elif not item.as_postal_address.has_enough_lines %} - Address must be at least {{ letter_min_address_lines }} lines long - {% elif item.as_postal_address.has_too_many_lines %} - Address must be no more than {{ letter_max_address_lines }} lines long - {% elif not item.as_postal_address.has_valid_last_line %} - {% if item.as_postal_address.allow_international_letters %} - Last line of the address must be a UK postcode or another country - {% elif item.as_postal_address.international %} - You do not have permission to send letters to other countries - {% else %} - Last line of the address must be a real UK postcode - {% endif %} - {% elif item.as_postal_address.has_invalid_characters %} - Address lines must not start with any of the following characters: @ ( ) = [ ] ” \ / , < > ~ {% endif %} {% endcall %} diff --git a/app/templates/views/dashboard/_inbox.html b/app/templates/views/dashboard/_inbox.html index 9dd6dc9a8..90f9fb6b6 100644 --- a/app/templates/views/dashboard/_inbox.html +++ b/app/templates/views/dashboard/_inbox.html @@ -14,17 +14,4 @@ {% endif %} {% endif %} - {% if current_service.has_returned_letters %} - - {% endif %} diff --git a/app/templates/views/dashboard/_jobs.html b/app/templates/views/dashboard/_jobs.html index 37cc923f9..0c50a57e1 100644 --- a/app/templates/views/dashboard/_jobs.html +++ b/app/templates/views/dashboard/_jobs.html @@ -7,7 +7,7 @@ caption="Recent files uploaded", caption_visible=False, empty_message=( - 'Upload a letter and Notify will print, pack and post it for you.' if current_service.has_permission('letter') else 'You have not uploaded any files yet.' + 'You have not uploaded any files yet.' ), field_headings=[ 'File', @@ -62,29 +62,12 @@ suffix='waiting to send' ) ) }} - {% elif item.template_type == 'letter' %} - {{ big_number( - item.notification_count, - smallest=True, - label=item.notification_count|message_count_label( - item.template_type, - suffix='' - ) - ) }} {% elif item.upload_type == 'contact_list' %} {{ big_number( item.row_count, smallest=True, label="saved {}".format(item.row_count|recipient_count_label(item.template_type)) ) }} - {% elif item.pdf_letter %} -

- {% for line in item.recipient.splitlines() %} - {% if loop.index < 3 %} - {{ line }}
- {% endif %} - {% endfor %} -

{% else %}
diff --git a/app/templates/views/dashboard/template-statistics.html b/app/templates/views/dashboard/template-statistics.html index e58267ecf..c8f6023ed 100644 --- a/app/templates/views/dashboard/template-statistics.html +++ b/app/templates/views/dashboard/template-statistics.html @@ -19,19 +19,10 @@ ) %} {% call row_heading() %} - {% if item.is_precompiled_letter %} - - Provided as PDF - - - Letter - - {% else %} {{ item.template_name }} {{ 1|message_count_label(item.template_type, suffix='template')|capitalize }} - {% endif %} {% endcall %} {{ spark_bar_field(item.count, most_used_template_count, id=item.template_id) }} diff --git a/app/templates/views/dashboard/write-first-messages.html b/app/templates/views/dashboard/write-first-messages.html index 1abd722d8..b956ab62b 100644 --- a/app/templates/views/dashboard/write-first-messages.html +++ b/app/templates/views/dashboard/write-first-messages.html @@ -2,10 +2,6 @@ diff --git a/app/templates/views/edit-letter-template.html b/app/templates/views/edit-letter-template.html deleted file mode 100644 index 258a53f8f..000000000 --- a/app/templates/views/edit-letter-template.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/textbox.html" import textbox %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import sticky_page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - {{ heading_action }} letter template -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ - "href": url_for('main.view_template', service_id=current_service.id, template_id=template.id) if template else url_for('main.choose_template', service_id=current_service.id, template_folder_id=template_folder_id) - }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('{} letter template'.format(heading_action)) }} - - {% call form_wrapper() %} -
-
- {{ form.name(param_extensions={ - "classes": "govuk-!-width-full", - "hint": {"text": "Your recipients will not see this"} - }) }} - {{ textbox(form.subject, width='1-1', highlight_placeholders=True, rows=2) }} - {{ textbox(form.template_content, highlight_placeholders=True, width='1-1', rows=8) }} - {{ sticky_page_footer( - 'Save' - ) }} -
-
- {% include "partials/templates/guidance-formatting-letters.html" %} - {% include "partials/templates/guidance-personalisation.html" %} - {% include "partials/templates/guidance-optional-content.html" %} -
-
- {% endcall %} - -{% endblock %} diff --git a/app/templates/views/features.html b/app/templates/views/features.html index 2d94d1ab8..4e06898eb 100644 --- a/app/templates/views/features.html +++ b/app/templates/views/features.html @@ -14,7 +14,6 @@

You do not need any technical knowledge to use Notify.

{% if not current_user.is_authenticated %} @@ -53,7 +52,6 @@

Notify commits to sending 95% of text messages within 10 seconds.

diff --git a/app/templates/views/features/letters.html b/app/templates/views/features/letters.html deleted file mode 100644 index 5989813f9..000000000 --- a/app/templates/views/features/letters.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "content_template.html" %} -{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %} - -{% block per_page_title %} - Letters -{% endblock %} - -{% block content_column_content %} - -

Letters

-

US Notify will print, pack and post your letters for you.

- {% if not current_user.is_authenticated %} -

Create an account and try Notify for yourself.

- {% endif %} - -

Features

-

Notify makes it easy to:

-
    -
  • create reusable letter templates
  • -
  • personalise the content of your letter
  • -
  • send bulk mail
  • -
-

You can also integrate with our API to send letters automatically.

- -

Choose your postage

-

Notify can send UK letters by first or second class post.

-

First class letters are delivered one day after they’re dispatched. Second class letters are delivered 2 days after they’re dispatched.

-

Letters are printed at 5:30pm and dispatched the next working day (Monday to Friday). Royal Mail delivers from Monday to Saturday, excluding bank holidays.

- -

Branding

-

Add your organisation’s logo to your letter templates.

-

See how to change your letter branding.

- -

Upload your own letters

-

You can create reusable letter templates in Notify, or upload and send your own letters with the Notify API.

-

Read our documentation.

- -

International letters

-

Notify checks for international addresses and will automatically charge you the correct postage.

-

Letters to Europe are delivered 3 to 5 days after they’re dispatched. Letters sent anywhere else in the world take 5 to 7 days to arrive.

- -

Pricing

-

It costs between 41 pence and £1.28 (plus VAT) to send a letter. Prices include:

-
    -
  • paper
  • -
  • double-sided colour printing
  • -
  • C5 size envelopes with an address window
  • -
  • first or second class postage
  • -
-

Letters can be up to 10 pages long (5 double-sided sheets of paper).

-

See pricing for more details.

- -{% endblock %} diff --git a/app/templates/views/guidance/branding-and-customisation.html b/app/templates/views/guidance/branding-and-customisation.html index db442faf9..625c11150 100644 --- a/app/templates/views/guidance/branding-and-customisation.html +++ b/app/templates/views/guidance/branding-and-customisation.html @@ -15,7 +15,6 @@
  • change your email branding
  • add a reply-to email address
  • change the text message sender
  • -
  • change your letter branding
  • Change your email branding

    @@ -53,15 +52,4 @@
  • Select Change or Add text message sender.
  • -

    Change your letter branding

    - -

    Letter templates do not have default branding.

    - -

    To add a logo to your letters:

    - -
      -
    1. Go to the Letter settings section of the {{ service_link(current_service, 'main.service_settings', 'settings') }} page.
    2. -
    3. Select Change on the Letter branding row.
    4. -
    - {% endblock %} diff --git a/app/templates/views/guidance/create-and-send-messages.html b/app/templates/views/guidance/create-and-send-messages.html index f9f1a4b58..938d4bb7d 100644 --- a/app/templates/views/guidance/create-and-send-messages.html +++ b/app/templates/views/guidance/create-and-send-messages.html @@ -17,6 +17,6 @@
    1. Go to the {{ service_link(current_service, 'main.choose_template', 'templates') }} page and choose an existing template.
    2. Select Send.
    3. -
    4. If you’re sending emails, select Upload a list of email addresses. If you’re sending text messages, select Upload a list of phone numbers. If you’re sending letters, select Upload a list of addresses.
    5. +
    6. If you’re sending emails, select Upload a list of email addresses. If you’re sending text messages, select Upload a list of phone numbers.
    7. {% endblock %} diff --git a/app/templates/views/guidance/edit-and-format-messages.html b/app/templates/views/guidance/edit-and-format-messages.html index 599c502c8..4fb558636 100644 --- a/app/templates/views/guidance/edit-and-format-messages.html +++ b/app/templates/views/guidance/edit-and-format-messages.html @@ -34,8 +34,6 @@
    8. horizontal rules
    9. -

      Letter templates can include headings and bullets.

      -

      Notify does not allow bold, italics, subheadings, underlined text or different fonts. This is because they can make it harder for users to read what you’ve written.

      diff --git a/app/templates/views/guidance/index.html b/app/templates/views/guidance/index.html index 747dabb28..2507ba8a3 100644 --- a/app/templates/views/guidance/index.html +++ b/app/templates/views/guidance/index.html @@ -18,7 +18,6 @@
    10. edit and format messages
    11. add branding and customisation
    12. send files by email
    13. -

      More information

      @@ -27,7 +26,6 @@ diff --git a/app/templates/views/guidance/letter-specification.html b/app/templates/views/guidance/letter-specification.html deleted file mode 100644 index eed3f61b0..000000000 --- a/app/templates/views/guidance/letter-specification.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "content_template.html" %} -{% from "components/service-link.html" import service_link %} - -{% block per_page_title %} - Letter specification -{% endblock %} - -{% block content_column_content %} - -

      Letter specification

      - -

      Page size and layout: A4 portrait (210 × 297 mm)

      -

      Maximum file size: 2 MB

      -

      Your letter must be 10 pages or less (5 double-sided sheets of paper).

      -

      The content of your letter must appear inside the printable area.

      - -

      To help you set up your letter, you can download our letter specification as a PDF.

      - -
      - - - See a text version of the letter specification - - -
      -

      Page 1 of 10

      - -

      Left margin 15mm

      -

      Right margin 15mm

      -

      Top margin 5mm

      -

      Bottom margin 5mm

      - -

      Logo block

      - -

      Position: 15mm from left edge, 5mm from top edge

      -

      Size: 200mm wide by 25mm high

      - -

      Address block

      - -

      Position: 39.5mm from left edge, 24.6mm from top edge

      -

      Size: 95.4mm wide by 26.8mm high

      - -

      Letter contact block

      - -

      Position: 125mm from left edge, 30mm from top edge

      -

      Size: 65mm wide by 65mm high

      - -

      Pages 2 to 10

      - -

      Left margin 15mm

      -

      Right margin 15mm

      -

      Top margin 5mm

      -

      Bottom margin 5mm

      -
      -
      - -{% endblock %} diff --git a/app/templates/views/guidance/upload-a-letter.html b/app/templates/views/guidance/upload-a-letter.html deleted file mode 100644 index 5633f7288..000000000 --- a/app/templates/views/guidance/upload-a-letter.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "content_template.html" %} -{% from "components/service-link.html" import service_link %} - -{% block per_page_title %} - Upload a letter -{% endblock %} - -{% block content_column_content %} - -

      Upload a letter

      - -

      Upload a one-off letter as a PDF and we’ll print, pack and post it for you.

      -

      You can use this feature if you send a lot of one-off letters or if our reusable letter templates do not meet your needs.

      - -

      To upload and send a letter from a PDF file:

      - -
        -
      1. Go to the {{ service_link(current_service, 'main.uploads', 'uploads') }} page.
      2. -
      3. Select Upload a letter.
      4. -
      5. Select Choose file.
      6. -
      - -

      Your file must meet our letter specification.

      - -{% endblock %} diff --git a/app/templates/views/jobs/jobs.html b/app/templates/views/jobs/jobs.html index a199ac0ce..b76f892e3 100644 --- a/app/templates/views/jobs/jobs.html +++ b/app/templates/views/jobs/jobs.html @@ -15,23 +15,10 @@

      You have not uploaded any files recently.

      - {% if current_user.has_permissions('send_messages') and current_service.has_permission('letter')%} -

      - Upload a letter and Notify will print, pack and post it for you. -

      - {% endif %} {% endif %} {{ previous_next_navigation(prev_page, next_page) }} {% if current_user.has_permissions('send_messages') %}
      - {% if current_service.has_permission('letter') %} - {{ govukButton({ - "element": "a", - "text": "Upload a letter", - "href": url_for('.upload_letter', service_id=current_service.id), - "classes": "govuk-button--secondary govuk-!-margin-right-3" - }) }} - {% endif %} {{ govukButton({ "element": "a", "text": "Upload an emergency contact list", diff --git a/app/templates/views/letter-branding/manage-letter-branding.html b/app/templates/views/letter-branding/manage-letter-branding.html deleted file mode 100644 index c57a17fb3..000000000 --- a/app/templates/views/letter-branding/manage-letter-branding.html +++ /dev/null @@ -1,44 +0,0 @@ -{% extends "views/platform-admin/_base_template.html" %} -{% from "components/file-upload.html" import file_upload %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block per_page_title %} - {{ '{} letter branding'.format('Update' if is_update else 'Add')}} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.letter_branding') }) }} -{% endblock %} - -{% block platform_admin_content %} - - {{ page_header('{} letter branding'.format('Update' if is_update else 'Add')) }} -
      -
      - {% if logo %} -
      - -
      - {% endif %} -

      - Logos should be SVG files, cropped to artwork bounds and with all fonts outlined. -

      - {{ file_upload(file_upload_form.file, allowed_file_extensions=['svg'], button_text='{} logo'.format('Update' if is_update else 'Upload')) }} - {% call form_wrapper() %} -
      - {{ letter_branding_details_form.name(param_extensions={ - "formGroup": {"classes": "govuk-!-margin-top-3"} - }) }} - {{ page_footer( - 'Save', - button_name='operation', - button_value='branding-details' - ) }} -
      - {% endcall %} -
      - -{% endblock %} diff --git a/app/templates/views/letter-branding/select-letter-branding.html b/app/templates/views/letter-branding/select-letter-branding.html deleted file mode 100644 index 19611e4b9..000000000 --- a/app/templates/views/letter-branding/select-letter-branding.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "views/platform-admin/_base_template.html" %} -{% from "components/page-header.html" import page_header %} -{% from "components/live-search.html" import live_search %} -{% from "components/button/macro.njk" import govukButton %} - -{% set page_title = "Letter branding" %} - -{% block per_page_title %} - {{ page_title }} -{% endblock %} - -{% block platform_admin_content %} - -

      {{ page_title }}

      - {{ live_search(target_selector='.letter-brand', show=True, form=search_form, autofocus=True) }} - -
      - {{ govukButton({ - "element": "a", - "text": "New brand", - "href": url_for('.create_letter_branding'), - "classes": "govuk-button--secondary" - }) }} -
      - -{% endblock %} diff --git a/app/templates/views/message-status.html b/app/templates/views/message-status.html index 012eb6896..5214c457d 100644 --- a/app/templates/views/message-status.html +++ b/app/templates/views/message-status.html @@ -67,33 +67,4 @@ {% endcall %}
      - - {% endblock %} diff --git a/app/templates/views/notifications.html b/app/templates/views/notifications.html index ed90cb23a..de92c1649 100644 --- a/app/templates/views/notifications.html +++ b/app/templates/views/notifications.html @@ -5,11 +5,7 @@ {% from "components/form.html" import form_wrapper %} {% from "components/button/macro.njk" import govukButton %} -{% set title_status = ( - 'Failed ' - if status == 'failed' and message_type == 'letter' - else '' -) %} +{% set title_status = '' %} {% set page_title = ( (title_status + 99|message_count_label(message_type, suffix='')) | capitalize if current_user.has_permissions('view_activity') @@ -23,15 +19,12 @@ {% block maincolumn_content %} {{ page_header(page_title) }} - {% if not message_type == "letter" %} - - {{ ajax_block( - partials, - url_for('.get_notifications_as_json', service_id=current_service.id, message_type=message_type, status=status), - 'counts' - ) }} - - {% endif %} + + {{ ajax_block( + partials, + url_for('.get_notifications_as_json', service_id=current_service.id, message_type=message_type, status=status), + 'counts' + ) }} {% call form_wrapper( action=url_for('.view_notifications', service_id=current_service.id, message_type=message_type), diff --git a/app/templates/views/notifications/check.html b/app/templates/views/notifications/check.html index ba0bebc16..c15c0f512 100644 --- a/app/templates/views/notifications/check.html +++ b/app/templates/views/notifications/check.html @@ -13,18 +13,7 @@ {% endblock %} {% block maincolumn_content %} - {% if template.template_type == 'letter' and current_service.trial_mode %} - {% set error = 'trial-mode-letters' %} -
      - {% call banner_wrapper(type='dangerous') %} - {% with - count_of_recipients=1 - %} - {% include "partials/check/trying-to-send-letters-in-trial-mode.html" %} - {% endwith %} - {% endcall %} -
      - {% elif error == 'not-allowed-to-send-to' %} + {% if error == 'not-allowed-to-send-to' %}
      {% call banner_wrapper(type='dangerous') %} {% with @@ -50,13 +39,6 @@ {% include "partials/check/message-too-long.html" %} {% endcall %}
      - {% elif letter_too_long %} - {% set error = 'letter-too-long' %} -
      - {% call banner_wrapper(type='dangerous') %} - {% include "partials/check/letter-too-long.html" %} - {% endcall %} -
      {% else %} {{ page_header('Preview of ‘{}’'.format(template.name)) }} {% endif %} @@ -75,9 +57,6 @@ {% set button_text %}Send 1 {{ 1|message_count_label(template.template_type, suffix='') }}{% endset %} {{ govukButton({ "text": button_text }) }} {% endif %} - {% if template.template_type == 'letter' %} - Download as a PDF - {% endif %}
      diff --git a/app/templates/views/notifications/invalid_precompiled_letter.html b/app/templates/views/notifications/invalid_precompiled_letter.html deleted file mode 100644 index 141ccef73..000000000 --- a/app/templates/views/notifications/invalid_precompiled_letter.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "withnav_template.html" %} - -{% block service_page_title %} - Letter -{% endblock %} - -{% block maincolumn_content %} - -

      Letter

      - -

      - Provided as PDF on {{ created_at|format_datetime_short }} -

      -

      - Validation failed – There’s a problem with your letter.
      Notify cannot read this PDF. -

      -{% endblock %} diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index 34296c689..c624b9360 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -21,23 +21,15 @@ 1|message_count_label(template.template_type, suffix='') | capitalize ) }}

      - {% if is_precompiled_letter %} - {% if created_by %} - Uploaded - {% else %} - Provided as PDF - {% endif %} + {% if help %} + ‘{{ template.name }}’ {% else %} - {% if help %} - ‘{{ template.name }}’ - {% else %} - ‘{{ template.name }}’ - {% endif %} - was sent + ‘{{ template.name }}’ {% endif %} + was sent {% if job and job.original_file_name != 'Report' %} {% set destination = - {'letter': 'an address', 'email': 'an email address', 'sms': 'a phone number'} %} + {'email': 'an email address', 'sms': 'a phone number'} %} to {{ destination[template.template_type] }} from {{ job.original_file_name }} {% elif created_by %} @@ -46,7 +38,7 @@ {{ created_at|format_datetime_human }}

      -
      +
      {{ template|string }}
      @@ -64,4 +56,4 @@

      {% endif %} -{% endblock %} +{% endblock %}q diff --git a/app/templates/views/organisations/organisation/index.html b/app/templates/views/organisations/organisation/index.html index b10efba95..589f4a661 100644 --- a/app/templates/views/organisations/organisation/index.html +++ b/app/templates/views/organisations/organisation/index.html @@ -38,17 +38,6 @@ ) }}
    -
    -

    Letters

    -
    - {{ big_number( - total_letter_cost, - 'spent', - currency="$", - smaller=True - ) }} -
    -
    {% if search_form %} @@ -93,14 +82,6 @@ ) }} {% endif %} -
    - {{ big_number( - service.letter_cost, - 'spent on letters', - currency="$", - smallest=True - ) }} -
    {% endfor %} diff --git a/app/templates/views/organisations/organisation/settings/index.html b/app/templates/views/organisations/organisation/settings/index.html index ca63ce59c..b1af005b7 100644 --- a/app/templates/views/organisations/organisation/settings/index.html +++ b/app/templates/views/organisations/organisation/settings/index.html @@ -109,19 +109,6 @@ ) }} {% endcall %} - {% call row() %} {{ text_field('Known email domains') }} {{ optional_text_field(current_org.domains or None, default='None') }} diff --git a/app/templates/views/organisations/organisation/settings/preview-letter-branding.html b/app/templates/views/organisations/organisation/settings/preview-letter-branding.html deleted file mode 100644 index 0b4075e0f..000000000 --- a/app/templates/views/organisations/organisation/settings/preview-letter-branding.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "org_template.html" %} -{% from "components/form.html" import form_wrapper %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/branding-preview.html" import letter_branding_preview %} - -{% block per_page_title %} - Preview letter branding -{% endblock %} - -{% block maincolumn_content %} - -

    Preview letter branding

    -
    -
    - {{ letter_branding_preview(form.branding_style.data) }} - {% call form_wrapper(action=action) %} -
    - {{ form.hidden_tag() }} - {{ page_footer('Save') }} -
    - {% endcall %} -
    -
    -{% endblock %} diff --git a/app/templates/views/organisations/organisation/settings/set-letter-branding.html b/app/templates/views/organisations/organisation/settings/set-letter-branding.html deleted file mode 100644 index 057e2d70e..000000000 --- a/app/templates/views/organisations/organisation/settings/set-letter-branding.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "org_template.html" %} -{% from "components/live-search.html" import live_search %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/page-header.html" import page_header %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% set page_title = "Default letter branding" %} - -{% block per_page_title %} - {{ page_title }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('.organisation_settings', org_id=current_org.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header(page_title) }} - {% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %} -
    -
    -
    -
    -
    -
    - {{ live_search( - target_selector='.govuk-radios__item', - show=True, - form=search_form, - label='Search by name', - autofocus=True - ) }} - {{ form.branding_style }} -
    -
    -
    - {{ page_footer('Preview') }} -
    - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/performance.html b/app/templates/views/performance.html index 11e17579d..81abeb449 100644 --- a/app/templates/views/performance.html +++ b/app/templates/views/performance.html @@ -26,27 +26,20 @@
    -
    +
    {{ big_number( email_notifications|format_billions, label=email_notifications|message_count_noun('email'), smallest=True, ) }}
    -
    +
    {{ big_number( sms_notifications|format_billions, label=sms_notifications|message_count_noun('sms'), smallest=True, ) }}
    -
    - {{ big_number( - letter_notifications|format_billions, - label=letter_notifications|message_count_noun('letter'), - smallest=True, - ) }} -
    @@ -60,7 +53,6 @@ 'Date', 99|message_count_noun('email')|capitalize, 99|message_count_noun('sms')|capitalize, - 99|message_count_noun('letter')|capitalize, ], empty_message='No data to show' ) %} @@ -73,9 +65,6 @@ {% call field() %} {{ item.sms|format_thousands }} {% endcall %} - {% call field() %} - {{ item.letters|format_thousands }} - {% endcall %} {% endcall %}
  • diff --git a/app/templates/views/platform-admin/_global_stats.html b/app/templates/views/platform-admin/_global_stats.html index 4de9f778c..8dfefdedc 100644 --- a/app/templates/views/platform-admin/_global_stats.html +++ b/app/templates/views/platform-admin/_global_stats.html @@ -21,14 +21,4 @@ smaller=True ) }}
  • -
    - {{ big_number_with_status( - global_stats.letter.requested, - global_stats.letter.requested|message_count_label('letter'), - global_stats.letter.failed, - global_stats.letter.failure_rate, - global_stats.letter.failure_rate|float > 3, - smaller=True - ) }} -
    diff --git a/app/templates/views/platform-admin/daily-volumes-report.html b/app/templates/views/platform-admin/daily-volumes-report.html index 1fc4e939f..420dbcc5e 100644 --- a/app/templates/views/platform-admin/daily-volumes-report.html +++ b/app/templates/views/platform-admin/daily-volumes-report.html @@ -34,8 +34,6 @@ ('sms fragments', 'The number of text message fragments sent times the rate multiplier'), ('sms chargeable units', 'The number of text message fragments sent'), ('email totals', 'The number of emails sent'), - ('letter totals', 'The number of letters sent'), - ('letter sheet totals', 'The number of sheets sent') ] %} {% call row() %} {{ text_field(column_heading) }} diff --git a/app/templates/views/platform-admin/get-billing-report.html b/app/templates/views/platform-admin/get-billing-report.html index 8979c2d4d..d9517ee9e 100644 --- a/app/templates/views/platform-admin/get-billing-report.html +++ b/app/templates/views/platform-admin/get-billing-report.html @@ -31,8 +31,6 @@ {% for column_heading, description in [ ('sms cost', 'The total cost of text messages sent after a service has used its free allowance.'), ('sms chargeable units', 'The number of fragments sent after a service has used its free allowance. This number takes into account the cost multiplier for sending international text messages.' | safe), - ('letter cost', 'The total cost of letters sent by a service.'), - ('letter breakdown', 'The number of letters sent by a service, grouped by postage and unit cost.'), ('purchase order number, contact names, contact email addresses and billing reference', 'We add this data manually based on the information we get from services. You can help by adding it to the service settings page.'), ] %} {% call row() %} diff --git a/app/templates/views/platform-admin/returned-letters.html b/app/templates/views/platform-admin/returned-letters.html deleted file mode 100644 index d4a55ce15..000000000 --- a/app/templates/views/platform-admin/returned-letters.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "views/platform-admin/_base_template.html" %} -{% from "components/textbox.html" import textbox %} -{% from "components/page-footer.html" import sticky_page_footer %} -{% from "components/form.html" import form_wrapper %} - -{% block per_page_title %} - {{ page_title|capitalize }} -{% endblock %} - -{% block platform_admin_content %} - -

    Submit returned letters

    - {% call form_wrapper() %} - {{ textbox(form.references, width='1-1', rows=8, autosize=True) }} - {{ sticky_page_footer("Submit") }} - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/platform-admin/services.html b/app/templates/views/platform-admin/services.html index 0f7a2a975..ff731a0a8 100644 --- a/app/templates/views/platform-admin/services.html +++ b/app/templates/views/platform-admin/services.html @@ -13,7 +13,6 @@ field_headings=[ right_aligned_field_heading('Emails'), right_aligned_field_heading('Text messages'), - right_aligned_field_heading('Letters') ], field_headings_visible=False, ) %} @@ -33,7 +32,7 @@ {% endcall %} {% call row() %} - {% for channel in ('email', 'sms', 'letter') %} + {% for channel in ('email', 'sms') %} {% call field(border=False) %} {{ big_number( service['stats'][channel]['requested'], diff --git a/app/templates/views/platform-admin/volumes-by-service-report.html b/app/templates/views/platform-admin/volumes-by-service-report.html index 1ad2de2bf..54d15c931 100644 --- a/app/templates/views/platform-admin/volumes-by-service-report.html +++ b/app/templates/views/platform-admin/volumes-by-service-report.html @@ -33,9 +33,6 @@ ('sms notifications', 'The number of text messages sent by the service.'), ('sms chargeable units', 'The number of text message fragments times the rate multiplier sent by the service.'), ('email totals', 'The number of emails sent by a service'), - ('letter totals', 'The number of letters sent by a service'), - ('letter costs', 'The cost of the letters, rate * letter totals'), - ('letter sheet totals', 'The number of sheet sent by a service') ] %} {% call row() %} {{ text_field(column_heading) }} diff --git a/app/templates/views/pricing/how-to-pay.html b/app/templates/views/pricing/how-to-pay.html index 9598ba50e..760d644cf 100644 --- a/app/templates/views/pricing/how-to-pay.html +++ b/app/templates/views/pricing/how-to-pay.html @@ -10,7 +10,7 @@ {{ page_header('How to pay') }}

    You’ll only pay for the additional text messages that you send. There’s no monthly charge, no setup fee and no procurement cost.

    @@ -229,39 +228,4 @@ "html": smsIntRates }) }} - - - - {% endblock %} diff --git a/app/templates/views/returned-letter-summary.html b/app/templates/views/returned-letter-summary.html deleted file mode 100644 index 3f5b445ed..000000000 --- a/app/templates/views/returned-letter-summary.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/table.html" import list_table, row_heading %} -{% from "components/page-header.html" import page_header %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Returned letters -{% endblock %} - - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.service_dashboard', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} -
    -
    - {{ page_header('Returned letters') }} -

    - Reports are published once a month. -

    -

    - You’ll only get a report if one or more of your letters is returned. -

    -
    -
    -
    - {% call(item, row_number) list_table( - data, - caption="Returned letters report", - caption_visible=False, - empty_message='If you have returned letter reports they will be listed here', - field_headings=['Report'], - field_headings_visible=False - ) %} - {% call row_heading() %} - {{ item.reported_at | format_date_normal }} -

    - {{ item.returned_letter_count|format_thousands }} {{ item.returned_letter_count|message_count_label('letter', suffix='')}} -

    - {% endcall %} - {% endcall %} -
    - -{% endblock %} diff --git a/app/templates/views/returned-letters.html b/app/templates/views/returned-letters.html deleted file mode 100644 index b0f30118a..000000000 --- a/app/templates/views/returned-letters.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/table.html" import list_table, field %} -{% from "components/page-header.html" import page_header %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Returned letters for {{ reported_at|format_date_normal }} -{% endblock %} - - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.returned_letter_summary', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -{{ page_header('Returned letters for {}'.format(reported_at|format_date_normal)) }} - -

    - Download this report (CSV) -

    - -
    - {% call(item, row_number) list_table( - returned_letters, - caption="Returned letters for {}".format(today), - caption_visible=False, - empty_message='If you have returned letter reports they will be listed here', - field_headings=['Template name', 'Originally sent'], - field_headings_visible=False - ) %} - {% call field() %} - {{ item.template_name or item.uploaded_letter_file_name or 'Provided as PDF' }} - - {% if item.client_reference %} - Reference {{ item.client_reference }} - {% elif item.original_file_name %} - Sent from {{ item.original_file_name }} - {% else %} - No reference provided - {% endif %} - - {% endcall %} - {% call field(align='right') %} - - - Sent {{ item.created_at|format_date_normal }} - - - {% endcall %} - {% endcall %} - {% if more_than_one_page %} - - {% endif %} -
    - -{% endblock %} diff --git a/app/templates/views/send-one-off-letter-address.html b/app/templates/views/send-one-off-letter-address.html deleted file mode 100644 index e24c8ab9b..000000000 --- a/app/templates/views/send-one-off-letter-address.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/textbox.html" import textbox %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - {{ page_title }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": back_link }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header(page_title) }} - - {% call form_wrapper( - class='send-one-off-form', - module="autofocus", - data_kwargs={'force-focus': True} - ) %} -
    -
    - {{ textbox( - form.address, - rows=4, - width='1-1', - autofocus=True, - autosize=True, - ) }} -
    -
    -

    - - Upload a list of {{ 999|recipient_count_label(template.template_type) }} - -

    - {{ page_footer('Continue') }} - {% endcall %} - - {{ template|string }} - -{% endblock %} diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index 43bfb061f..d6a08f0a8 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -197,76 +197,6 @@ {% endcall %} {% endcall %} - - @@ -278,7 +208,6 @@
    • send {{ current_service.message_limit }} text messages and emails per day
    • send messages to yourself and other people in your team
    • -

    @@ -385,11 +314,6 @@ {{ text_field(current_service.email_branding_name) }} {{ edit_field('Change', url_for('.service_set_email_branding', service_id=current_service.id), suffix='email branding (admin view)') }} {% endcall %} - {% call row() %} - {{ text_field('Letter branding')}} - {{ optional_text_field(current_service.letter_branding.name) }} - {{ edit_field('Change', url_for('.service_set_letter_branding', service_id=current_service.id), suffix='letter branding (admin view)') }} - {% endcall %} {% call row() %} {{ text_field('Custom data retention')}} {% call field() %} diff --git a/app/templates/views/service-settings/branding/letter-branding-options.html b/app/templates/views/service-settings/branding/letter-branding-options.html deleted file mode 100644 index a55c8536f..000000000 --- a/app/templates/views/service-settings/branding/letter-branding-options.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/radios.html" import radio, conditional_radio_panel %} -{% from "components/select-input.html" import select_wrapper %} -{% from "components/textbox.html" import textbox %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Change letter branding -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ - "href": url_for('.view_template', service_id=current_service.id, template_id=from_template) if from_template else url_for('.service_settings', service_id=current_service.id) - }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('Change letter branding') }} - -

    - Your letters currently have {{ branding_name }} branding. -

    - - {% call form_wrapper() %} - {% if form.something_else_is_only_option %} - {{ textbox( - form.something_else, - hint='Include links to your brand guidelines or examples of how to use your branding.', - width='1-1', - ) }} - {% else %} - {% call select_wrapper(form.options) %} - {% for option in form.options %} - {{ radio(option, data_target='panel-something-else' if option.data == form.FALLBACK_OPTION_VALUE else '') }} - {% endfor %} - {% endcall %} - {% call conditional_radio_panel('panel-something-else') %} - {{ textbox( - form.something_else, - hint='Include links to your brand guidelines or examples of how to use your branding.', - width='1-1', - autosize=True, - ) }} - {% endcall %} - {% endif %} -

    - We’ll email you once your branding’s ready to use, or if we need any - more information. -

    - {{ page_footer('Request new branding') }} - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/service-settings/estimate-usage.html b/app/templates/views/service-settings/estimate-usage.html index 8ffcfd793..b0312c9e2 100644 --- a/app/templates/views/service-settings/estimate-usage.html +++ b/app/templates/views/service-settings/estimate-usage.html @@ -35,10 +35,6 @@ "classes": "govuk-!-width-one-half", "hint": {"text": "For example, 50,000"}, }) }} - {{ form.volume_letter(param_extensions={ - "classes": "govuk-!-width-one-half", - "hint": {"text": "For example, 50,000"}, - }) }} {{ form.consent_to_research }} {{ page_footer('Continue') }} diff --git a/app/templates/views/service-settings/letter-contact-details.html b/app/templates/views/service-settings/letter-contact-details.html deleted file mode 100644 index fdd9c8aba..000000000 --- a/app/templates/views/service-settings/letter-contact-details.html +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} -{% from "components/page-header.html" import page_header %} -{% from "components/table.html" import row_group, row, text_field, edit_field, field, boolean_field, list_table with context %} -{% from "components/button/macro.njk" import govukButton %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Sender addresses -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.service_settings', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
    - {{ page_header('Sender addresses') }} -
    -
    -
    -
    -
    -

    - Blank - {% if not current_service.default_letter_contact_block %} - (default) - {% endif %} -

    -
    -
    - {% if current_service.default_letter_contact_block and current_user.has_permissions('manage_service') %} - Make default - {% endif %} -
    -
    -
    - {% for item in letter_contact_details %} -
    -
    -
    -

    - {{ item.contact_block | nl2br }} -

    -

    - {%- if item.is_default -%} - (default) - {% endif %} -

    -
    -
    - {% if current_user.has_permissions('manage_service') %} - - Change {{ item.contact_block }} - - {% endif %} -
    -
    - {% if letter_contact_details|length > 1 %} - {% set first_line_of_contact_block = item.contact_block|get_lines_with_normalised_whitespace|first %} - {{ copy_to_clipboard(item.id, name=first_line_of_contact_block, thing="ID") }} - {% endif %} -
    - {% endfor %} -
    - {% if current_user.has_permissions('manage_service') %} -
    -
    -
    - {{ govukButton({ - "element": "a", - "text": "Add a new address", - "href": url_for('.service_add_letter_contact', service_id=current_service.id) - }) }} -
    -
    -
    - {% endif %} -{% endblock %} diff --git a/app/templates/views/service-settings/letter-contact/add.html b/app/templates/views/service-settings/letter-contact/add.html deleted file mode 100644 index 5e90df44e..000000000 --- a/app/templates/views/service-settings/letter-contact/add.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/textbox.html" import textbox %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Add a new address -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": back_link }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('Add a new address') }} -
    -
    - {% call form_wrapper() %} - {{ textbox( - form.letter_contact_block, - label='This will appear as the sender address on your letters.'|safe, - hint='10 lines maximum', - width='1-2', - rows=10, - highlight_placeholders=True - ) }} - {% if not first_contact_block %} - {{ form.is_default }} - {% endif %} - {{ page_footer('Add') }} - {% endcall %} -
    -
    - -{% endblock %} diff --git a/app/templates/views/service-settings/letter-contact/edit.html b/app/templates/views/service-settings/letter-contact/edit.html deleted file mode 100644 index 41120c41a..000000000 --- a/app/templates/views/service-settings/letter-contact/edit.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/textbox.html" import textbox %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Change sender address -{% endblock %} - -{% block backLink %} - {% if not request.args.get('from_template') %} - {{ govukBackLink({ "href": url_for('.service_letter_contact_details', service_id=current_service.id) }) }} - {% endif %} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('Change sender address') }} - {% call form_wrapper() %} - {{ textbox( - form.letter_contact_block, - label='This will appear as the sender address on your letters.'|safe, - hint='10 lines maximum', - width='1-2', - rows=10, - highlight_placeholders=True - ) }} - - - {% if form.is_default.data %} -

    - This is currently your default address for {{ current_service.name }}. -

    - {% else %} - {{ form.is_default }} - {% endif %} - - {{ page_footer( - 'Save', - delete_link=url_for('.service_confirm_delete_letter_contact', service_id=current_service.id, letter_contact_id=letter_contact_id), - delete_link_text='Delete' - ) }} - - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/service-settings/preview-letter-branding.html b/app/templates/views/service-settings/preview-letter-branding.html deleted file mode 100644 index 2c9e1a30a..000000000 --- a/app/templates/views/service-settings/preview-letter-branding.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "views/platform-admin/_base_template.html" %} -{% from "components/form.html" import form_wrapper %} -{% from "components/button/macro.njk" import govukButton %} -{% from "components/branding-preview.html" import letter_branding_preview %} - -{% block per_page_title %} - Preview letter branding -{% endblock %} - -{% block platform_admin_content %} - -

    Preview letter branding

    -
    -
    - {{ letter_branding_preview(form.branding_style.data) }} - {% call form_wrapper(action=action) %} -
    - {{ form.hidden_tag() }} - -
    - {% endcall %} -
    -
    -{% endblock %} diff --git a/app/templates/views/service-settings/set-international-letters.html b/app/templates/views/service-settings/set-international-letters.html deleted file mode 100644 index b6bcfe8f3..000000000 --- a/app/templates/views/service-settings/set-international-letters.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Send international letters -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.service_settings', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
    -
    - {{ page_header('Send international letters') }} -

    - It costs more to send a letter to an international address. -

    -

    - See pricing for the list - of rates. -

    - {% call form_wrapper() %} - {{ form.enabled }} - {{ page_footer('Save') }} - {% endcall %} -
    -
    - -{% endblock %} diff --git a/app/templates/views/service-settings/set-letter-branding.html b/app/templates/views/service-settings/set-letter-branding.html deleted file mode 100644 index 065ff5495..000000000 --- a/app/templates/views/service-settings/set-letter-branding.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/live-search.html" import live_search %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% set page_title = "Set letter branding" %} - -{% block service_page_title %} - {{ page_title }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('.service_settings', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header(page_title) }} - {% call form_wrapper(data_kwargs={'preview-type': 'letter'}) %} -
    -
    -
    -
    -
    -
    - {{ live_search( - target_selector='.govuk-radios__item', - show=True, - form=search_form, - label='Search by name', - autofocus=True - ) }} - {{ form.branding_style }} -
    -
    -
    - {{ page_footer('Preview') }} -
    - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/service-settings/set-letter.html b/app/templates/views/service-settings/set-letter.html deleted file mode 100644 index 22871370d..000000000 --- a/app/templates/views/service-settings/set-letter.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Send letters -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.service_settings', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
    -
    - {{ page_header('Send letters') }} -

    - It costs between 41 pence and £1.28 to send a letter using Notify. -

    -

    - See pricing for the list - of rates. -

    - {% call form_wrapper() %} - {{ form.enabled }} - {{ page_footer('Save') }} - {% endcall %} -
    -
    - -{% endblock %} diff --git a/app/templates/views/service-settings/set-sms.html b/app/templates/views/service-settings/set-sms.html index 2432baebd..f7ed24860 100644 --- a/app/templates/views/service-settings/set-sms.html +++ b/app/templates/views/service-settings/set-sms.html @@ -27,7 +27,7 @@ after your free allowance.

    - See pricing for more details. + See pricing for more details.

    {% call form_wrapper() %} {{ form.enabled }} diff --git a/app/templates/views/signedout.html b/app/templates/views/signedout.html index 32e2aa81b..0a33ab5b4 100644 --- a/app/templates/views/signedout.html +++ b/app/templates/views/signedout.html @@ -58,8 +58,7 @@ Control your content

    - You do not need any technical knowledge to create email, - text message or letter templates. + You do not need any technical knowledge to create message templates.

    @@ -152,11 +151,6 @@ free text messages a year,
    then {{ sms_rate }} pence per message
    -
    -

    Letters

    -
    41 pence
    - to print and post a one page letter -

    There’s no monthly charge, no setup fee and no procurement process. diff --git a/app/templates/views/templates/_template.html b/app/templates/views/templates/_template.html index 70aa2c640..f9dcafead 100644 --- a/app/templates/views/templates/_template.html +++ b/app/templates/views/templates/_template.html @@ -1,18 +1,6 @@ {% from "components/banner.html" import banner_wrapper %}

    - {% if current_user.has_permissions('manage_templates') and template.template_type == 'letter' %} - {% if not current_service.letter_branding_id %} - Add logo - {% endif %} - Change postage - Edit letter template - {% if current_service.count_letter_contact_details %} - Edit letter contact block - {% else %} - Edit letter contact block - {% endif %} - {% endif %} {{ template|string }}

    @@ -30,34 +18,19 @@ {% else %}
    - {% if template.template_type == 'letter' %} - {% if letter_too_long %} - {% call banner_wrapper(type='dangerous') %} - {% include "partials/check/letter-too-long.html" %} - {% endcall %} - {% endif %} - {% if current_user.has_permissions('send_messages', restrict_admin_usage=True) and not letter_too_long %} - - {% endif %} - {% else %} - {% if current_user.has_permissions('send_messages', restrict_admin_usage=True) %} - - {% endif %} - {% if current_user.has_permissions('manage_templates') %} - - {% endif %} + {% if current_user.has_permissions('send_messages', restrict_admin_usage=True) %} + + {% endif %} + {% if current_user.has_permissions('manage_templates') %} + {% endif %}
    diff --git a/app/templates/views/templates/choose.html b/app/templates/views/templates/choose.html index e8fece3a8..f9995069b 100644 --- a/app/templates/views/templates/choose.html +++ b/app/templates/views/templates/choose.html @@ -27,7 +27,7 @@ {% else %} You need to ask your service manager to add templates before you can {% endif %} - send emails, text messages or letters. + send messages.

    {% else %} diff --git a/app/templates/views/templates/edit-template-postage.html b/app/templates/views/templates/edit-template-postage.html deleted file mode 100644 index e246c5f73..000000000 --- a/app/templates/views/templates/edit-template-postage.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/form.html" import form_wrapper %} -{% from "components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Change postage -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('.view_template', service_id=service_id, template_id=template_id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('Change postage') }} - {% call form_wrapper() %} -
    -
    - {{ form.postage }} - {{ page_footer('Save') }} -
    -
    - {% include "partials/templates/guidance-postage.html" %} -
    -
    - {% endcall %} - -{% endblock %} diff --git a/app/templates/views/templates/template.html b/app/templates/views/templates/template.html index 89bd5f80c..78080bf81 100644 --- a/app/templates/views/templates/template.html +++ b/app/templates/views/templates/template.html @@ -70,14 +70,12 @@   {% endif %} - {% if template.template_type not in ('letter') %} - {% if not template._template.redact_personalisation %} - - Hide personalisation after sending - - {% else %} -

    Personalisation is hidden after sending

    - {% endif %} + {% if not template._template.redact_personalisation %} + + Hide personalisation after sending + + {% else %} +

    Personalisation is hidden after sending

    {% endif %} {% endif %}
    diff --git a/app/templates/views/trial-mode.html b/app/templates/views/trial-mode.html index 51aa2328b..0acbee69d 100644 --- a/app/templates/views/trial-mode.html +++ b/app/templates/views/trial-mode.html @@ -13,7 +13,6 @@
    • send 50 text messages and emails per day
    • send messages to yourself and other people in your team
    • -
    {% if current_service and current_service.trial_mode %} diff --git a/app/templates/views/uploads/preview.html b/app/templates/views/uploads/preview.html deleted file mode 100644 index 52a8afe45..000000000 --- a/app/templates/views/uploads/preview.html +++ /dev/null @@ -1,87 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/page-header.html" import page_header %} -{% from "components/page-footer.html" import page_footer %} -{% from "components/back-link/macro.njk" import govukBackLink %} -{% from "components/file-upload.html" import file_upload %} - -{% block service_page_title %} - {{ original_filename }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.upload_letter', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {% if status == 'invalid' and message %} - {% include "partials/check/letter-validation-failed-banner.html" %} -
    -
    -
    - {{ file_upload( - re_upload_form.file, - allowed_file_extensions=['pdf'], - action=url_for('main.upload_letter', service_id=current_service.id), - button_text='Upload your file again' - ) }} -
    - Back to top -
    -
    - {% elif current_service.trial_mode %} - {% call banner_wrapper(type='dangerous') %} - {% with - count_of_recipients=1 - %} - {% include "partials/check/trying-to-send-letters-in-trial-mode.html" %} - {% endwith %} - {% endcall %} - {% else %} - {{ page_header( - original_filename - ) }} - {% endif %} - -
    - {{ template|string }} -
    - - {% if status == 'valid' %} -
    -

    - Recipient: {{ postal_address.as_single_line }} -

    - - {% if current_service.live %} - {% if postal_address.international %} -

    - Postage: international -

    - {% endif %} - - {% endif %} - -
    - {% endif %} -{% endblock %} diff --git a/app/templates/views/using-notify.html b/app/templates/views/using-notify.html index 2e9a0bf00..c6cb4ed14 100644 --- a/app/templates/views/using-notify.html +++ b/app/templates/views/using-notify.html @@ -23,7 +23,6 @@
  • message status types
  • email replies
  • text message replies
  • -
  • letters
  • diff --git a/app/url_converters.py b/app/url_converters.py index 59fd31685..a3dd92cbc 100644 --- a/app/url_converters.py +++ b/app/url_converters.py @@ -18,10 +18,5 @@ class TicketTypeConverter(BaseConverter): regex = f'(?:{PROBLEM_TICKET_TYPE}|{QUESTION_TICKET_TYPE}|{GENERAL_TICKET_TYPE})' -class LetterFileExtensionConverter(BaseConverter): - - regex = '(?:pdf|png)' - - class SimpleDateTypeConverter(BaseConverter): regex = r'([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))' diff --git a/app/utils/__init__.py b/app/utils/__init__.py index 65f5b9fd2..15435418c 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -9,12 +9,12 @@ from werkzeug.datastructures import MultiDict from werkzeug.routing import RequestRedirect SENDING_STATUSES = ['created', 'pending', 'sending', 'pending-virus-check'] -DELIVERED_STATUSES = ['delivered', 'sent', 'returned-letter'] +DELIVERED_STATUSES = ['delivered', 'sent'] FAILURE_STATUSES = ['failed', 'temporary-failure', 'permanent-failure', 'technical-failure', 'virus-scan-failed', 'validation-failed'] REQUESTED_STATUSES = SENDING_STATUSES + DELIVERED_STATUSES + FAILURE_STATUSES -NOTIFICATION_TYPES = ["sms", "email", "letter"] +NOTIFICATION_TYPES = ["sms", "email"] def service_has_permission(permission): @@ -68,7 +68,6 @@ def should_skip_template_page(db_template): return ( current_user.has_permissions('send_messages') and not current_user.has_permissions('manage_templates', 'manage_api_keys') - and db_template['template_type'] != 'letter' and not db_template['archived'] ) diff --git a/app/utils/branding.py b/app/utils/branding.py index 380f957e4..3e4518f21 100644 --- a/app/utils/branding.py +++ b/app/utils/branding.py @@ -20,23 +20,3 @@ def get_email_choices(service): and service.email_branding_name.lower() != f'GOV.UK and {service.organisation.name}'.lower() ): yield ('govuk_and_org', f'GOV.UK and {service.organisation.name}') - - -def get_letter_choices(service): - organisation_branding_id = service.organisation.letter_branding_id if service.organisation else None - - # if ( - # service.organisation_type in Organisation.NHS_TYPES - # and service.letter_branding_name != 'NHS' - # ): - # yield ('nhs', 'NHS') - - if ( - service.organisation - # and service.organisation_type not in Organisation.NHS_TYPES - and ( - service.letter_branding_id is None # GOV.UK is current branding - or service.letter_branding_id != organisation_branding_id - ) - ): - yield ('organisation', service.organisation.name) diff --git a/app/utils/csv.py b/app/utils/csv.py index ba0e2c57b..2bcde2282 100644 --- a/app/utils/csv.py +++ b/app/utils/csv.py @@ -20,11 +20,6 @@ def get_errors_for_csv(recipients, template_type): errors.append("fix 1 email address") else: errors.append("fix {} email addresses".format(number_of_bad_recipients)) - elif 'letter' == template_type: - if 1 == number_of_bad_recipients: - errors.append("fix 1 address") - else: - errors.append("fix {} addresses".format(number_of_bad_recipients)) if any(recipients.rows_with_missing_data): number_of_rows_with_missing_data = len(list(recipients.rows_with_missing_data)) @@ -89,8 +84,7 @@ def generate_notifications_csv(**kwargs): ] else: values = [ - # the recipient for precompiled letters is the full address block - notification['recipient'].splitlines()[0].lstrip().rstrip(' ,'), + notification['recipient'], notification['client_reference'], notification['template_name'], notification['template_type'], diff --git a/app/utils/letters.py b/app/utils/letters.py deleted file mode 100644 index ea05d6670..000000000 --- a/app/utils/letters.py +++ /dev/null @@ -1,187 +0,0 @@ -from flask import url_for -from notifications_utils.formatters import unescaped_formatted_list -from notifications_utils.postal_address import PostalAddress - -LETTER_VALIDATION_MESSAGES = { - 'letter-not-a4-portrait-oriented': { - 'title': 'Your letter is not A4 portrait size', - 'detail': ( - 'You need to change the size or orientation of {invalid_pages}.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - 'summary': ( - 'Validation failed because {invalid_pages} {invalid_pages_are_or_is} not A4 portrait size.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - }, - 'content-outside-printable-area': { - 'title': 'Your content is outside the printable area', - 'detail': ( - 'You need to edit {invalid_pages}.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - 'summary': ( - 'Validation failed because content is outside the printable area on {invalid_pages}.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - }, - 'letter-too-long': { - 'title': 'Your letter is too long', - 'detail': ( - 'Letters must be 10 pages or less (5 double-sided sheets of paper).
    ' - 'Your letter is {page_count} pages long.' - ), - 'summary': ( - 'Validation failed because this letter is {page_count} pages long.
    ' - 'Letters must be 10 pages or less (5 double-sided sheets of paper).' - ), - }, - 'no-encoded-string': { - 'title': 'Sanitise failed - No encoded string' - }, - 'unable-to-read-the-file': { - 'title': 'There’s a problem with your file', - 'detail': ( - 'Notify cannot read this PDF.' - '
    Save a new copy of your file and try again.' - ), - 'summary': ( - 'Validation failed because Notify cannot read this PDF.
    ' - 'Save a new copy of your file and try again.' - ), - }, - 'address-is-empty': { - 'title': 'The address block is empty', - 'detail': ( - 'You need to add a recipient address.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - 'summary': ( - 'Validation failed because the address block is empty.
    ' - 'Files must meet our ' - '' - 'letter specification' - '.' - ), - }, - 'not-a-real-uk-postcode': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - 'The last line of the address must be a real UK postcode.' - ), - 'summary': ( - 'Validation failed because the last line of the address is not a real UK postcode.' - ), - }, - 'cant-send-international-letters': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - 'You do not have permission to send letters to other countries.' - ), - 'summary': ( - 'Validation failed because your service cannot send letters to other countries.' - ), - }, - 'not-a-real-uk-postcode-or-country': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - 'The last line of the address must be a UK postcode or ' - 'another country.' - ), - 'summary': ( - 'Validation failed because the last line of the address is ' - 'not a UK postcode or another country.' - ), - }, - 'not-enough-address-lines': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - f'The address must be at least {PostalAddress.MIN_LINES} ' - f'lines long.' - ), - 'summary': ( - f'Validation failed because the address must be at least ' - f'{PostalAddress.MIN_LINES} lines long.' - ), - }, - 'too-many-address-lines': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - f'The address must be no more than {PostalAddress.MAX_LINES} ' - f'lines long.' - ), - 'summary': ( - f'Validation failed because the address must be no more ' - f'than {PostalAddress.MAX_LINES} lines long.' - ), - }, - 'invalid-char-in-address': { - 'title': 'There’s a problem with the address for this letter', - 'detail': ( - "Address lines must not start with any of the following characters: @ ( ) = [ ] ” \\ / , < > ~" - ), - 'summary': ( - "Validation failed because address lines must not start with any of the " - "following characters: @ ( ) = [ ] ” \\ / , < > ~" - ), - }, - 'notify-tag-found-in-content': { - 'title': 'There’s a problem with your letter', - 'detail': ( - 'Your file includes a letter you’ve downloaded from Notify.
    ' - 'You need to edit {invalid_pages}.' - ), - 'summary': ( - 'Validation failed because your file includes a letter ' - 'you’ve downloaded from Notify on {invalid_pages}.' - ) - }, -} - - -def get_letter_validation_error(validation_message, invalid_pages=None, page_count=None): - if not invalid_pages: - invalid_pages = [] - if validation_message not in LETTER_VALIDATION_MESSAGES: - return {'title': 'Validation failed'} - - invalid_pages_are_or_is = 'is' if len(invalid_pages) == 1 else 'are' - - invalid_pages = unescaped_formatted_list( - invalid_pages, - before_each='', - after_each='', - prefix='page', - prefix_plural='pages' - ) - - return { - 'title': LETTER_VALIDATION_MESSAGES[validation_message]['title'], - 'detail': LETTER_VALIDATION_MESSAGES[validation_message]['detail'].format( - invalid_pages=invalid_pages, - invalid_pages_are_or_is=invalid_pages_are_or_is, - page_count=page_count, - letter_spec_guidance=url_for('.letter_specification') - ), - 'summary': LETTER_VALIDATION_MESSAGES[validation_message]['summary'].format( - invalid_pages=invalid_pages, - invalid_pages_are_or_is=invalid_pages_are_or_is, - page_count=page_count, - letter_spec_guidance=url_for('.letter_specification'), - ), - } diff --git a/app/utils/templates.py b/app/utils/templates.py index 2ecd568dd..5c412047a 100644 --- a/app/utils/templates.py +++ b/app/utils/templates.py @@ -1,8 +1,5 @@ -from flask import current_app from notifications_utils.template import ( EmailPreviewTemplate, - LetterImageTemplate, - LetterPreviewTemplate, SMSPreviewTemplate, ) @@ -12,18 +9,12 @@ def get_sample_template(template_type): return EmailPreviewTemplate({'content': 'any', 'subject': '', 'template_type': 'email'}) if template_type == 'sms': return SMSPreviewTemplate({'content': 'any', 'template_type': 'sms'}) - if template_type == 'letter': - return LetterImageTemplate( - {'content': 'any', 'subject': '', 'template_type': 'letter'}, postage='second', image_url='x', page_count=1 - ) def get_template( template, service, show_recipient=False, - letter_preview_url=None, - page_count=1, redact_missing_personalisation=False, email_reply_to=None, sms_sender=None, @@ -47,19 +38,3 @@ def get_template( show_recipient=show_recipient, redact_missing_personalisation=redact_missing_personalisation, ) - if 'letter' == template['template_type']: - if letter_preview_url: - return LetterImageTemplate( - template, - image_url=letter_preview_url, - page_count=int(page_count), - contact_block=template['reply_to_text'], - postage=template['postage'], - ) - else: - return LetterPreviewTemplate( - template, - contact_block=template['reply_to_text'], - admin_base_url=current_app.config['ADMIN_BASE_URL'], - redact_missing_personalisation=redact_missing_personalisation, - ) diff --git a/app/utils/user_permissions.py b/app/utils/user_permissions.py index a57dc5dde..6d8dec6f2 100644 --- a/app/utils/user_permissions.py +++ b/app/utils/user_permissions.py @@ -1,7 +1,8 @@ from itertools import chain permission_mappings = { - 'send_messages': ['send_texts', 'send_emails', 'send_letters'], + # TODO: consider turning off email-sending permissions during SMS pilot + 'send_messages': ['send_texts', 'send_emails'], 'manage_templates': ['manage_templates'], 'manage_service': ['manage_users', 'manage_settings'], 'manage_api_keys': ['manage_api_keys'], diff --git a/paas-failwhale/static_503/stylesheets/main.css b/paas-failwhale/static_503/stylesheets/main.css index 3afa3ac5b..c4e0b73fc 100644 --- a/paas-failwhale/static_503/stylesheets/main.css +++ b/paas-failwhale/static_503/stylesheets/main.css @@ -9447,7 +9447,6 @@ only screen and (min-resolution: 2dppx) { .edit-template-link-letter-contact, .edit-template-link-letter-address, .edit-template-link-letter-body, -.edit-template-link-letter-postage, .edit-template-link-letter-branding, .edit-template-link { font-family: "nta", Arial, sans-serif; @@ -9467,7 +9466,6 @@ only screen and (min-resolution: 2dppx) { .edit-template-link-letter-contact, .edit-template-link-letter-address, .edit-template-link-letter-body, - .edit-template-link-letter-postage, .edit-template-link-letter-branding, .edit-template-link { font-size: 19px; @@ -9478,12 +9476,10 @@ only screen and (min-resolution: 2dppx) { .edit-template-link-letter-contact:link, .edit-template-link-letter-address:link, .edit-template-link-letter-body:link, -.edit-template-link-letter-postage:link, .edit-template-link-letter-branding:link, .edit-template-link-letter-contact:visited, .edit-template-link-letter-address:visited, .edit-template-link-letter-body:visited, -.edit-template-link-letter-postage:visited, .edit-template-link-letter-branding:visited, .edit-template-link:link, .edit-template-link:visited { @@ -9493,37 +9489,11 @@ only screen and (min-resolution: 2dppx) { .edit-template-link-letter-contact:hover, .edit-template-link-letter-address:hover, .edit-template-link-letter-body:hover, -.edit-template-link-letter-postage:hover, .edit-template-link-letter-branding:hover, .edit-template-link:hover { color: #d5e8f3 } -.edit-template-link-letter-contact { - right: -25px; - top: 232px -} - -.edit-template-link-letter-address { - top: 14.65%; - left: -5px -} - -.edit-template-link-letter-body { - top: 400px; - left: -5px -} - -.edit-template-link-letter-postage { - top: 51px; - right: 145px -} - -.edit-template-link-letter-branding { - top: 51px; - left: 66px -} - .notification-status { font-family: "nta", Arial, sans-serif; font-weight: 400; diff --git a/tests/__init__.py b/tests/__init__.py index 156b511b1..d4b5ecae1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -77,7 +77,6 @@ def user_json( 'view_activity', 'send_texts', 'send_emails', - 'send_letters', 'manage_users', 'manage_templates', 'manage_settings', @@ -148,7 +147,6 @@ def service_json( email_branding=None, branding='govuk', created_at=None, - letter_contact_block=None, inbound_api=None, service_callback_api=None, permissions=None, @@ -187,8 +185,6 @@ def service_json( 'email_branding': email_branding, 'branding': branding, 'created_at': created_at or str(datetime.utcnow()), - 'letter_branding': None, - 'letter_contact_block': letter_contact_block, 'permissions': permissions, 'inbound_api': inbound_api, 'service_callback_api': service_callback_api, @@ -196,7 +192,6 @@ def service_json( 'contact_link': contact_link, 'volume_email': 111111, 'volume_sms': 222222, - 'volume_letter': 333333, 'consent_to_research': True, 'count_as_live': True, 'organisation': organisation_id, @@ -215,7 +210,6 @@ def organisation_json( active=True, created_at=None, services=None, - letter_branding_id=None, email_branding_id=None, domains=None, crown=True, @@ -243,7 +237,6 @@ def organisation_json( 'users': users, 'created_at': created_at or str(datetime.utcnow()), 'email_branding_id': email_branding_id, - 'letter_branding_id': letter_branding_id, 'organisation_type': organisation_type, 'crown': crown, 'agreement_signed': agreement_signed, @@ -273,11 +266,8 @@ def template_json(service_id, archived=False, process_type='normal', redact_personalisation=None, - service_letter_contact=None, reply_to=None, reply_to_text=None, - is_precompiled_letter=False, - postage=None, folder=None ): template = { @@ -290,12 +280,9 @@ def template_json(service_id, 'updated_at': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f'), 'archived': archived, 'process_type': process_type, - 'service_letter_contact': service_letter_contact, 'reply_to': reply_to, 'reply_to_text': reply_to_text, - 'is_precompiled_letter': is_precompiled_letter, 'folder': folder, - 'postage': postage } if content is None: template['content'] = "template content" @@ -479,14 +466,11 @@ def notification_json( reply_to_text=None, client_reference=None, created_by_name=None, - postage=None, ): if template is None: template = template_json(service_id, str(generate_uuid()), type_=template_type) if to is None: - if template_type == 'letter': - to = '1 Example Street' - elif template_type == 'email': + if template_type == 'email': to = 'example@gsa.gov' else: to = '07123456789' @@ -499,8 +483,6 @@ def notification_json( if status is None: status = 'delivered' links = {} - if template_type == 'letter': - postage = postage or 'second' if with_links: links = { @@ -528,7 +510,6 @@ def notification_json( 'service': service_id, 'template_version': template['version'], 'personalisation': personalisation or {}, - 'postage': postage, 'notification_type': template_type, 'reply_to_text': reply_to_text, 'client_reference': client_reference, diff --git a/tests/app/main/forms/test_placeholder_form.py b/tests/app/main/forms/test_placeholder_form.py index 93279c4ef..bbfbe256a 100644 --- a/tests/app/main/forms/test_placeholder_form.py +++ b/tests/app/main/forms/test_placeholder_form.py @@ -41,7 +41,6 @@ def test_form_class_not_mutated(notify_admin): (True, 'phone number', 'sms', 'invalid', 'Must not contain letters or symbols'), (True, 'phone number', 'email', 'invalid', None), - (True, 'phone number', 'letter', 'invalid', None), (True, 'email address', 'sms', 'invalid', None), ]) diff --git a/tests/app/main/test_formatters.py b/tests/app/main/test_formatters.py index 01116073e..2f5f6016b 100644 --- a/tests/app/main/test_formatters.py +++ b/tests/app/main/test_formatters.py @@ -27,11 +27,6 @@ from app.formatters import ( ('temporary-failure', 'sms', partial(url_for, 'main.message_status', _anchor='text-message-statuses')), ('permanent-failure', 'sms', partial(url_for, 'main.message_status', _anchor='text-message-statuses')), ('technical-failure', 'sms', partial(url_for, 'main.message_status', _anchor='text-message-statuses')), - # Letter statuses are never linked - ('technical-failure', 'letter', lambda: None), - ('cancelled', 'letter', lambda: None), - ('accepted', 'letter', lambda: None), - ('received', 'letter', lambda: None), )) def test_format_notification_status_as_url( client_request, diff --git a/tests/app/main/views/accounts/test_choose_accounts.py b/tests/app/main/views/accounts/test_choose_accounts.py index a99404c80..e789f7f5e 100644 --- a/tests/app/main/views/accounts/test_choose_accounts.py +++ b/tests/app/main/views/accounts/test_choose_accounts.py @@ -326,7 +326,6 @@ def test_should_show_back_to_service_if_user_belongs_to_service( '' 'Dashboard ' 'Send messages ' - # 'Letters ' 'Team members' ) # TODO: set sidebar variables in common test module diff --git a/tests/app/main/views/organisations/test_organisations.py b/tests/app/main/views/organisations/test_organisations.py index b2b3961ce..d7fe5028a 100644 --- a/tests/app/main/views/organisations/test_organisations.py +++ b/tests/app/main/views/organisations/test_organisations.py @@ -456,10 +456,10 @@ def test_organisation_services_shows_live_services_and_usage( 'app.organisations_client.get_services_and_usage', return_value={"services": [ {'service_id': SERVICE_ONE_ID, 'service_name': '1', 'chargeable_billable_sms': 250122, 'emails_sent': 13000, - 'free_sms_limit': 250000, 'letter_cost': 30.50, 'sms_billable_units': 122, 'sms_cost': 0, + 'free_sms_limit': 250000, 'sms_billable_units': 122, 'sms_cost': 0, 'sms_remainder': None}, {'service_id': SERVICE_TWO_ID, 'service_name': '5', 'chargeable_billable_sms': 0, 'emails_sent': 20000, - 'free_sms_limit': 250000, 'letter_cost': 0, 'sms_billable_units': 2500, 'sms_cost': 42.0, + 'free_sms_limit': 250000, 'sms_billable_units': 2500, 'sms_cost': 42.0, 'sms_remainder': None} ]} ) @@ -475,19 +475,16 @@ def test_organisation_services_shows_live_services_and_usage( # Totals assert normalize_spaces(usage_rows[0].text) == "Emails 33,000 sent" assert normalize_spaces(usage_rows[1].text) == "Text messages $42.00 spent" - assert normalize_spaces(usage_rows[2].text) == "Letters $30.50 spent" assert normalize_spaces(services[0].text) == '1' assert normalize_spaces(services[1].text) == '5' assert services[0].find('a')['href'] == url_for('main.usage', service_id=SERVICE_ONE_ID) - assert normalize_spaces(usage_rows[3].text) == "13,000 emails sent" - assert normalize_spaces(usage_rows[4].text) == "122 free text messages sent" - assert normalize_spaces(usage_rows[5].text) == "$30.50 spent on letters" + assert normalize_spaces(usage_rows[2].text) == "13,000 emails sent" + assert normalize_spaces(usage_rows[3].text) == "122 free text messages sent" assert services[1].find('a')['href'] == url_for('main.usage', service_id=SERVICE_TWO_ID) - assert normalize_spaces(usage_rows[6].text) == "20,000 emails sent" - assert normalize_spaces(usage_rows[7].text) == "$42.00 spent on text messages" - assert normalize_spaces(usage_rows[8].text) == "$0.00 spent on letters" + assert normalize_spaces(usage_rows[4].text) == "20,000 emails sent" + assert normalize_spaces(usage_rows[5].text) == "$42.00 spent on text messages" # Ensure there’s no ‘this org has no services message’ assert not page.select('.govuk-hint') @@ -505,7 +502,7 @@ def test_organisation_services_shows_live_services_and_usage_with_count_of_1( 'app.organisations_client.get_services_and_usage', return_value={"services": [ {'service_id': SERVICE_ONE_ID, 'service_name': '1', 'chargeable_billable_sms': 1, 'emails_sent': 1, - 'free_sms_limit': 250000, 'letter_cost': 0, 'sms_billable_units': 1, 'sms_cost': 0, + 'free_sms_limit': 250000, 'sms_billable_units': 1, 'sms_cost': 0, 'sms_remainder': None}, ]} ) @@ -518,11 +515,9 @@ def test_organisation_services_shows_live_services_and_usage_with_count_of_1( # Totals assert normalize_spaces(usage_rows[0].text) == "Emails 1 sent" assert normalize_spaces(usage_rows[1].text) == "Text messages $0.00 spent" - assert normalize_spaces(usage_rows[2].text) == "Letters $0.00 spent" - assert normalize_spaces(usage_rows[3].text) == "1 email sent" - assert normalize_spaces(usage_rows[4].text) == "1 free text message sent" - assert normalize_spaces(usage_rows[5].text) == "$0.00 spent on letters" + assert normalize_spaces(usage_rows[2].text) == "1 email sent" + assert normalize_spaces(usage_rows[3].text) == "1 free text message sent" @freeze_time("2020-02-20 20:20") @@ -577,7 +572,6 @@ def test_organisation_services_shows_search_bar( 'chargeable_billable_sms': 250122, 'emails_sent': 13000, 'free_sms_limit': 250000, - 'letter_cost': 30.50, 'sms_billable_units': 122, 'sms_cost': 1.93, 'sms_remainder': None @@ -624,7 +618,6 @@ def test_organisation_services_hides_search_bar_for_7_or_fewer_services( 'chargeable_billable_sms': 250122, 'emails_sent': 13000, 'free_sms_limit': 250000, - 'letter_cost': 30.50, 'sms_billable_units': 122, 'sms_cost': 1.93, 'sms_remainder': None @@ -657,7 +650,6 @@ def test_organisation_services_links_to_downloadable_report( 'chargeable_billable_sms': 250122, 'emails_sent': 13000, 'free_sms_limit': 250000, - 'letter_cost': 30.50, 'sms_billable_units': 122, 'sms_cost': 1.93, 'sms_remainder': None @@ -693,7 +685,6 @@ def test_download_organisation_usage_report( 'chargeable_billable_sms': 22, 'emails_sent': 13000, 'free_sms_limit': 100, - 'letter_cost': 30.5, 'sms_billable_units': 122, 'sms_cost': 1.934, 'sms_remainder': 0 @@ -704,7 +695,6 @@ def test_download_organisation_usage_report( 'chargeable_billable_sms': 222, 'emails_sent': 23000, 'free_sms_limit': 250000, - 'letter_cost': 60.5, 'sms_billable_units': 322, 'sms_cost': 3.935, 'sms_remainder': 0 @@ -721,9 +711,9 @@ def test_download_organisation_usage_report( assert csv_report.string == ( "Service ID,Service Name,Emails sent,Free text message allowance remaining," - "Spent on text messages ($),Spent on letters ($)" - "\r\n596364a0-858e-42c8-9062-a8fe822260eb,Service 1,13000,0,1.93,30.50" - "\r\n147ad62a-2951-4fa1-9ca0-093cd1a52c52,Service 1,23000,0,3.94,60.50\r\n" + "Spent on text messages ($)" + "\r\n596364a0-858e-42c8-9062-a8fe822260eb,Service 1,13000,0,1.93" + "\r\n147ad62a-2951-4fa1-9ca0-093cd1a52c52,Service 1,23000,0,3.94\r\n" ) @@ -943,7 +933,6 @@ def test_organisation_settings_for_platform_admin( 'Billing details None Change billing details for the organisation', 'Notes None Change the notes for the organisation', 'Default email branding GOV.UK Change default email branding for the organisation', - # 'Default letter branding No branding Change default letter branding for the organisation', 'Known email domains None Change known email domains for the organisation', ] diff --git a/tests/app/main/views/service_settings/test_email_branding_requests.py b/tests/app/main/views/service_settings/test_email_branding_requests.py index 0cb1be4e2..ca3c1467c 100644 --- a/tests/app/main/views/service_settings/test_email_branding_requests.py +++ b/tests/app/main/views/service_settings/test_email_branding_requests.py @@ -26,7 +26,6 @@ def test_email_branding_request_page_when_no_branding_is_set( client_request, mocker, mock_get_email_branding, - mock_get_letter_branding_by_id, organisation_type, expected_options, ): @@ -45,7 +44,6 @@ def test_email_branding_request_page_when_no_branding_is_set( assert mock_get_email_branding.called is False assert page.find('iframe')['src'] == url_for('main.email_template', branding_style='__NONE__') - assert mock_get_letter_branding_by_id.called is False button_text = normalize_spaces(page.select_one('.page-footer button').text) diff --git a/tests/app/main/views/service_settings/test_letter_branding_requests.py b/tests/app/main/views/service_settings/test_letter_branding_requests.py deleted file mode 100644 index edb23d64b..000000000 --- a/tests/app/main/views/service_settings/test_letter_branding_requests.py +++ /dev/null @@ -1,245 +0,0 @@ -from unittest.mock import ANY, PropertyMock - -import pytest -from flask import url_for -from notifications_utils.clients.zendesk.zendesk_client import ( - NotifySupportTicket, -) - -from tests import organisation_json, sample_uuid -from tests.conftest import ( - ORGANISATION_ID, - SERVICE_ONE_ID, - TEMPLATE_ONE_ID, - normalize_spaces, -) - - -@pytest.mark.parametrize('organisation_type, expected_options', ( - ('nhs_central', [ - ('nhs', 'NHS'), - ('something_else', 'Something else'), - ]), - ('other', None), -)) -@pytest.mark.skip(reason='Update for TTS') -def test_letter_branding_request_page_when_no_branding_is_set( - service_one, - client_request, - mock_get_email_branding, - mock_get_letter_branding_by_id, - organisation_type, - expected_options, -): - service_one['letter_branding'] = None - service_one['organisation_type'] = organisation_type - - page = client_request.get( - '.letter_branding_request', service_id=SERVICE_ONE_ID - ) - - assert mock_get_email_branding.called is False - assert mock_get_letter_branding_by_id.called is False - - button_text = normalize_spaces(page.select_one('.page-footer button').text) - assert button_text == 'Request new branding' - - if expected_options: - assert [ - ( - radio['value'], - page.select_one('label[for={}]'.format(radio['id'])).text.strip() - ) - for radio in page.select('input[type=radio]') - ] == expected_options - assert page.select_one( - '.conditional-radios-panel#panel-something-else textarea' - )['name'] == ( - 'something_else' - ) - else: - assert page.select_one( - 'textarea' - )['name'] == ( - 'something_else' - ) - assert not page.select('.conditional-radios-panel') - - -@pytest.mark.parametrize('from_template,back_link_url', [ - (None, '/services/{}/service-settings'.format(SERVICE_ONE_ID),), - (TEMPLATE_ONE_ID, '/services/{}/templates/{}'.format(SERVICE_ONE_ID, TEMPLATE_ONE_ID),) -]) -def test_letter_branding_request_page_back_link( - client_request, - from_template, - back_link_url, -): - if from_template: - page = client_request.get( - '.letter_branding_request', service_id=SERVICE_ONE_ID, from_template=from_template - ) - else: - page = client_request.get( - '.letter_branding_request', service_id=SERVICE_ONE_ID - ) - - back_link = page.select('a[class=govuk-back-link]') - assert back_link[0].attrs['href'] == back_link_url - - -@pytest.mark.parametrize('org_name, expected_organisation', ( - (None, 'Can’t tell (domain is user.gsa.gov)'), - ('Test Organisation', 'Test Organisation'), -)) -def test_letter_branding_request_submit( - client_request, - service_one, - mocker, - mock_get_letter_branding_by_id, - no_reply_to_email_addresses, - no_letter_contact_blocks, - single_sms_sender, - org_name, - expected_organisation, -): - service_one['letter_branding'] = sample_uuid() - organisation_id = ORGANISATION_ID if org_name else None - - mocker.patch( - 'app.models.service.Service.organisation_id', - new_callable=PropertyMock, - return_value=organisation_id, - ) - mocker.patch( - 'app.organisations_client.get_organisation', - return_value=organisation_json(name=org_name), - ) - - mock_create_ticket = mocker.spy(NotifySupportTicket, '__init__') - mock_send_ticket_to_zendesk = mocker.patch( - 'app.main.views.service_settings.zendesk_client.send_ticket_to_zendesk', - autospec=True, - ) - - page = client_request.post( - '.letter_branding_request', service_id=SERVICE_ONE_ID, - _data={ - 'options': 'something_else', - 'something_else': 'Homer Simpson', - }, - _follow_redirects=True, - ) - - mock_create_ticket.assert_called_once_with( - ANY, - message='\n'.join([ - 'Organisation: {}', - 'Service: service one', - 'http://localhost/services/596364a0-858e-42c8-9062-a8fe822260eb', - '', - '---', - 'Current branding: HM Government', - 'Branding requested: Something else\n\nHomer Simpson\n', - ]).format(expected_organisation), - subject='Letter branding request - service one', - ticket_type='question', - user_name='Test User', - user_email='test@user.gsa.gov', - org_id=organisation_id, - org_type='federal', - service_id=SERVICE_ONE_ID - ) - mock_send_ticket_to_zendesk.assert_called_once() - assert normalize_spaces(page.select_one('.banner-default').text) == ( - 'Thanks for your branding request. We’ll get back to you ' - 'within one working day.' - ) - - -@pytest.mark.parametrize('data, error_message', ( - ({'options': 'something_else'}, 'Cannot be empty'), # no data in 'something_else' textbox - ({'options': ''}, 'Select an option'), # no radio button selected -)) -def test_letter_branding_request_submit_when_form_has_missing_data( - client_request, - mocker, - service_one, - organisation_one, - data, - error_message, - mock_get_letter_branding_by_id, -): - mocker.patch( - 'app.organisations_client.get_organisation', - return_value=organisation_one, - ) - service_one['letter_branding'] = sample_uuid() - service_one['organisation'] = organisation_one - - page = client_request.post( - '.letter_branding_request', service_id=SERVICE_ONE_ID, - _data=data, - _follow_redirects=True, - ) - assert page.h1.text == 'Change letter branding' - assert normalize_spaces(page.select_one('.error-message').text) == error_message - - -@pytest.mark.parametrize('from_template', [ - None, - TEMPLATE_ONE_ID -]) -def test_letter_branding_request_submit_redirects_if_from_template_is_set( - client_request, - service_one, - mocker, - from_template, - -): - mocker.patch('app.main.views.service_settings.zendesk_client.send_ticket_to_zendesk', autospec=True) - data = {'options': 'something_else', 'something_else': 'Homer Simpson'} - - if from_template: - client_request.post( - '.letter_branding_request', service_id=SERVICE_ONE_ID, from_template=from_template, - _data=data, - _expected_redirect=url_for( - 'main.view_template', service_id=SERVICE_ONE_ID, template_id=from_template, - ) - ) - else: - client_request.post( - '.letter_branding_request', service_id=SERVICE_ONE_ID, - _data=data, - _expected_redirect=url_for('main.service_settings', service_id=SERVICE_ONE_ID) - ) - - -@pytest.mark.skip(reason='Update for TTS') -def test_letter_branding_submit_when_something_else_is_only_option( - client_request, - service_one, - mocker, - mock_get_letter_branding_by_id, -): - mock_create_ticket = mocker.spy(NotifySupportTicket, '__init__') - mocker.patch( - 'app.main.views.service_settings.zendesk_client.send_ticket_to_zendesk', - autospec=True, - ) - - client_request.post( - '.letter_branding_request', - service_id=SERVICE_ONE_ID, - _data={ - 'something_else': 'Homer Simpson', - }, - ) - - assert ( - 'Current branding: no\n' - 'Branding requested: Something else\n' - '\n' - 'Homer Simpson' - ) in mock_create_ticket.call_args_list[0][1]['message'] diff --git a/tests/app/main/views/service_settings/test_service_setting_permissions.py b/tests/app/main/views/service_settings/test_service_setting_permissions.py index d02a13d81..1b3502674 100644 --- a/tests/app/main/views/service_settings/test_service_setting_permissions.py +++ b/tests/app/main/views/service_settings/test_service_setting_permissions.py @@ -13,11 +13,9 @@ def get_service_settings_page( platform_admin_user, service_one, mock_get_inbound_number_for_service, - mock_get_all_letter_branding, mock_get_organisation, mock_get_free_sms_fragment_limit, no_reply_to_email_addresses, - no_letter_contact_blocks, single_sms_sender, mock_get_service_data_retention, ): @@ -63,18 +61,6 @@ def test_service_set_permission_requires_platform_admin( 'False', [], ), - ( - [], - 'international_letters', - 'True', - ['international_letters'], - ), - ( - ['international_letters'], - 'international_letters', - 'False', - [], - ), ]) def test_service_set_permission( mocker, @@ -113,9 +99,6 @@ def test_service_set_permission( ({'restricted': False}, '.service_switch_live', {}, 'Live On Change service status'), ({'permissions': ['sms']}, '.service_set_inbound_number', {}, 'Receive inbound SMS Off Change your settings for Receive inbound SMS'), - ({'permissions': ['letter']}, - '.service_set_permission', {'permission': 'international_letters'}, - 'Send international letters Off Change your settings for Send international letters'), ]) def test_service_setting_toggles_show( mocker, @@ -196,10 +179,8 @@ def test_normal_user_doesnt_see_any_platform_admin_settings( client_request, service_one, no_reply_to_email_addresses, - no_letter_contact_blocks, mock_get_organisation, single_sms_sender, - mock_get_all_letter_branding, mock_get_inbound_number_for_service, mock_get_free_sms_fragment_limit, mock_get_service_data_retention diff --git a/tests/app/main/views/service_settings/test_service_settings.py b/tests/app/main/views/service_settings/test_service_settings.py index 23ea1db25..a8431dfce 100644 --- a/tests/app/main/views/service_settings/test_service_settings.py +++ b/tests/app/main/views/service_settings/test_service_settings.py @@ -2,7 +2,7 @@ from datetime import datetime from functools import partial from unittest.mock import ANY, Mock, PropertyMock, call from urllib.parse import parse_qs, urlparse -from uuid import UUID, uuid4 +from uuid import uuid4 import pytest from flask import url_for @@ -28,9 +28,7 @@ from tests.conftest import ( create_active_user_no_api_key_permission, create_active_user_no_settings_permission, create_active_user_with_permissions, - create_letter_contact_block, create_multiple_email_reply_to_addresses, - create_multiple_letter_contact_blocks, create_multiple_sms_senders, create_platform_admin_user, create_reply_to_email_address, @@ -44,7 +42,6 @@ FAKE_TEMPLATE_ID = uuid4() @pytest.fixture def mock_get_service_settings_page_common( - mock_get_all_letter_branding, mock_get_inbound_number_for_service, mock_get_free_sms_fragment_limit, mock_get_service_data_retention, @@ -102,7 +99,6 @@ def mock_get_service_settings_page_common( 'Message limit 1,000 per day Change daily message limit', 'Free text message allowance 250,000 per year Change free text message allowance', 'Email branding GOV.UK Change email branding (admin view)', - 'Letter branding Not set Change letter branding (admin view)', 'Custom data retention Email – 7 days Change data retention', 'Receive inbound SMS Off Change your settings for Receive inbound SMS', 'Email authentication Off Change your settings for Email authentication', @@ -113,7 +109,6 @@ def test_should_show_overview( mocker, api_user_active, no_reply_to_email_addresses, - no_letter_contact_blocks, single_sms_sender, user, expected_rows, @@ -145,7 +140,6 @@ def test_no_go_live_link_for_service_without_organisation( client_request, mocker, no_reply_to_email_addresses, - no_letter_contact_blocks, single_sms_sender, platform_admin_user, mock_get_service_settings_page_common, @@ -168,7 +162,6 @@ def test_organisation_name_links_to_org_dashboard( client_request, platform_admin_user, no_reply_to_email_addresses, - no_letter_contact_blocks, single_sms_sender, mock_get_service_settings_page_common, mocker, @@ -198,7 +191,6 @@ def test_send_files_by_email_row_on_settings_page( client_request, platform_admin_user, no_reply_to_email_addresses, - no_letter_contact_blocks, single_sms_sender, mock_get_service_settings_page_common, mocker, @@ -269,7 +261,6 @@ def test_should_show_overview_for_service_with_more_things_set( mocker, service_one, single_reply_to_email_address, - single_letter_contact_block, single_sms_sender, mock_get_email_branding, mock_get_service_settings_page_common, @@ -286,60 +277,6 @@ def test_should_show_overview_for_service_with_more_things_set( assert row == " ".join(page.find_all('tr')[index + 1].text.split()) -@pytest.mark.skip(reason="Skipping letter-specific test") -def test_if_cant_send_letters_then_cant_see_letter_contact_block( - client_request, - service_one, - single_reply_to_email_address, - no_letter_contact_blocks, - single_sms_sender, - mock_get_service_settings_page_common, -): - response = client_request.get('main.service_settings', service_id=service_one['id']) - assert 'Letter contact block' not in response - - -@pytest.mark.skip(reason="Skipping letter-specific test") -def test_letter_contact_block_shows_none_if_not_set( - client_request, - service_one, - single_reply_to_email_address, - no_letter_contact_blocks, - single_sms_sender, - mock_get_service_settings_page_common, -): - service_one['permissions'] = ['letter'] - page = client_request.get( - 'main.service_settings', - service_id=SERVICE_ONE_ID, - ) - - div = page.find_all('tr')[10].find_all('td')[1].div - assert div.text.strip() == 'Not set' - assert 'default' in div.attrs['class'][0] - - -@pytest.mark.skip(reason="Skipping letter-specific test") -def test_escapes_letter_contact_block( - client_request, - service_one, - mocker, - single_reply_to_email_address, - single_sms_sender, - injected_letter_contact_block, - mock_get_service_settings_page_common, -): - service_one['permissions'] = ['letter'] - page = client_request.get( - 'main.service_settings', - service_id=SERVICE_ONE_ID, - ) - - div = str(page.find_all('tr')[10].find_all('td')[1].div) - assert 'foo
    bar' in div - assert '', - 'is_default': True, - 'created_at': datetime.utcnow(), - 'updated_at': None - } - ] - - return mocker.patch('app.service_api_client.get_letter_contacts', side_effect=_get) - - -@pytest.fixture(scope='function') -def get_default_letter_contact_block(mocker): - def _get(service_id, letter_contact_id): - return { - 'id': '1234', - 'service_id': service_id, - 'contact_block': '1 Example Street', - 'is_default': True, - 'created_at': datetime.utcnow(), - 'updated_at': None - } - - return mocker.patch('app.service_api_client.get_letter_contact', side_effect=_get) - - -@pytest.fixture(scope='function') -def mock_add_letter_contact(mocker): - def _add_letter_contact(service_id, contact_block, is_default=False): - return {'data': { - 'id': '1234', - 'service_id': service_id, - 'contact_block': '1 Example Street', - 'is_default': True, - 'created_at': str(datetime.utcnow()), - 'updated_at': None - }} - - return mocker.patch('app.service_api_client.add_letter_contact', side_effect=_add_letter_contact) - - -@pytest.fixture(scope='function') -def mock_update_letter_contact(mocker): - def _update_letter_contact(service_id, letter_contact_id, contact_block, is_default=False): - return - - return mocker.patch('app.service_api_client.update_letter_contact', side_effect=_update_letter_contact) - - @pytest.fixture(scope='function') def multiple_sms_senders(mocker): def _get(service_id): @@ -506,7 +395,6 @@ def mock_get_service_statistics(mocker, api_user_active): return { 'email': {'requested': 0, 'delivered': 0, 'failed': 0}, 'sms': {'requested': 0, 'delivered': 0, 'failed': 0}, - 'letter': {'requested': 0, 'delivered': 0, 'failed': 0} } return mocker.patch('app.service_api_client.get_service_statistics', side_effect=_get) @@ -533,13 +421,11 @@ def mock_get_detailed_services(mocker, fake_uuid): service_one['statistics'] = { 'email': {'requested': 0, 'delivered': 0, 'failed': 0}, 'sms': {'requested': 0, 'delivered': 0, 'failed': 0}, - 'letter': {'requested': 0, 'delivered': 0, 'failed': 0} } service_two['statistics'] = { 'email': {'requested': 0, 'delivered': 0, 'failed': 0}, 'sms': {'requested': 0, 'delivered': 0, 'failed': 0}, - 'letter': {'requested': 0, 'delivered': 0, 'failed': 0} } services = {'data': [service_one, service_two]} @@ -833,44 +719,6 @@ def mock_get_service_email_template_without_placeholders(mocker): 'app.service_api_client.get_service_template', side_effect=_get) -@pytest.fixture(scope='function') -def mock_get_service_letter_template(mocker): - def _get(service_id, template_id, version=None, postage='second'): - template = template_json( - service_id, - template_id, - name="Two week reminder", - type_="letter", - content="Template content with & entity", - subject="Subject", - postage=postage, - ) - return {'data': template} - - return mocker.patch( - 'app.service_api_client.get_service_template', side_effect=_get - ) - - -@pytest.fixture(scope='function') -def mock_get_service_letter_template_with_placeholders(mocker): - def _get(service_id, template_id, version=None, postage='second'): - template = template_json( - service_id, - template_id, - name="Two week reminder", - type_="letter", - content="Hello ((name)) your thing is due on ((date))", - subject="Subject", - postage=postage, - ) - return {'data': template} - - return mocker.patch( - 'app.service_api_client.get_service_template', side_effect=_get - ) - - @pytest.fixture(scope='function') def mock_create_service_template(mocker, fake_uuid): def _create(name, type_, content, service, subject=None, process_type=None, parent_folder_id=None): @@ -884,8 +732,8 @@ def mock_create_service_template(mocker, fake_uuid): @pytest.fixture(scope='function') def mock_update_service_template(mocker): - def _update(id_, name, type_, content, service, subject=None, process_type=None, postage=None): - template = template_json(service, id_, name, type_, content, subject, process_type, postage) + def _update(id_, name, type_, content, service, subject=None, process_type=None): + template = template_json(service, id_, name, type_, content, subject, process_type) return {'data': template} return mocker.patch( @@ -913,7 +761,7 @@ def mock_create_service_template_content_too_big(mocker): @pytest.fixture(scope='function') def mock_update_service_template_400_content_too_big(mocker): - def _update(id_, name, type_, content, service, subject=None, process_type=None, postage=None): + def _update(id_, name, type_, content, service, subject=None, process_type=None): json_mock = Mock(return_value={ 'message': {'content': ["Content has a character count greater than the limit of 459"]}, 'result': 'error' @@ -929,13 +777,13 @@ def mock_update_service_template_400_content_too_big(mocker): side_effect=_update) -def create_service_templates(service_id, number_of_templates=6): - template_types = ["sms", "sms", "email", "email", "letter", "letter"] +def create_service_templates(service_id, number_of_templates=4): + template_types = ["sms", "sms", "email", "email"] service_templates = [] for _ in range(1, number_of_templates + 1): template_number = "two" if _ % 2 == 0 else "one" - template_type = template_types[(_ % 6) - 1] + template_type = template_types[(_ % 4) - 1] service_templates.append(template_json( service_id, @@ -944,7 +792,7 @@ def create_service_templates(service_id, number_of_templates=6): template_type, "{} template {} content".format(template_type, template_number), subject="{} template {} subject".format(template_type, template_number) - if template_type in ["email", "letter"] else None + if template_type == "email" else None )) return {'data': service_templates} @@ -1045,7 +893,6 @@ def platform_admin_user(fake_uuid): return create_platform_admin_user(permissions={SERVICE_ONE_ID: [ 'send_texts', 'send_emails', - 'send_letters', 'manage_users', 'manage_templates', 'manage_settings', @@ -1102,7 +949,6 @@ def active_user_with_permission_to_two_services(fake_uuid): permissions = [ 'send_texts', 'send_emails', - 'send_letters', 'manage_users', 'manage_templates', 'manage_settings', @@ -1447,14 +1293,6 @@ def mock_get_job(mocker, api_user_active): return mocker.patch('app.job_api_client.get_job', side_effect=_get_job) -@pytest.fixture(scope='function') -def mock_get_letter_job(mocker, api_user_active): - def _get_job(service_id, job_id): - return {"data": job_json(service_id, api_user_active, job_id=job_id, template_type='letter')} - - return mocker.patch('app.job_api_client.get_job', side_effect=_get_job) - - @pytest.fixture def mock_get_job_doesnt_exist(mocker): def _get_job(service_id, job_id): @@ -1517,20 +1355,6 @@ def mock_get_job_with_sending_limits_exceeded(mocker, api_user_active): return mocker.patch('app.job_api_client.get_job', side_effect=_get_job) -@pytest.fixture(scope='function') -def mock_get_letter_job_in_progress(mocker, api_user_active): - def _get_job(service_id, job_id): - return {"data": job_json( - service_id, api_user_active, job_id=job_id, - notification_count=10, - notifications_requested=5, - job_status='processing', - template_type='letter', - )} - - return mocker.patch('app.job_api_client.get_job', side_effect=_get_job) - - @pytest.fixture(scope='function') def mock_has_jobs(mocker): return mocker.patch('app.job_api_client.has_jobs', return_value=True) @@ -1592,16 +1416,6 @@ def mock_get_scheduled_job_stats(mocker, api_user_active): def mock_get_uploads(mocker, api_user_active): def _get_uploads(service_id, limit_days=None, statuses=None, page=1): uploads = [ - { - 'id': None, - 'original_file_name': 'Uploaded letters', - 'recipient': None, - 'notification_count': 33, - 'template_type': 'letter', - 'created_at': '2017-10-10 16:30:00', - 'statistics': [], - 'upload_type': 'letter_day', - }, { 'id': 'job_id_1', 'original_file_name': 'some.csv', @@ -1615,21 +1429,6 @@ def mock_get_uploads(mocker, api_user_active): 'template_type': 'sms', 'recipient': None, }, - { - 'id': 'letter_id_1', - 'original_file_name': 'some.pdf', - 'notification_count': 1, - 'created_at': '2016-01-01 11:09:00.061258', - 'statistics': [{'count': 1, 'status': 'delivered'}], - 'upload_type': 'letter', - 'template_type': None, - 'recipient': ( - 'Firstname Lastname\n' - '123 Example Street\n' - 'City of Town\n' - 'XM4 5QQ' - ), - }, ] return { 'data': uploads, @@ -1784,7 +1583,6 @@ def mock_get_notifications( id_=str(generate_uuid()), type_=template_type[0], redact_personalisation=False, - is_precompiled_letter=False, ) else: template = template_json( @@ -2023,7 +1821,7 @@ def sample_invite(mocker, service_one): from_user = service_one['users'][0] email_address = 'invited_user@test.gsa.gov' service_id = service_one['id'] - permissions = 'view_activity,send_emails,send_letters,send_texts,manage_settings,manage_users,manage_api_keys' + permissions = 'view_activity,send_emails,send_texts,manage_settings,manage_users,manage_api_keys' created_at = str(datetime.utcnow()) auth_type = 'sms_auth' folder_permissions = [] @@ -2112,7 +1910,6 @@ def mock_get_template_statistics(mocker, service_one, fake_uuid): "template_name": template['name'], "template_type": template['template_type'], "template_id": template['id'], - "is_precompiled_letter": False, "status": "delivered" } @@ -2153,10 +1950,6 @@ def mock_get_monthly_notification_stats(mocker, service_one, fake_uuid): "sending": 1, "delivered": 1, }, - "letter": { - "sending": 1, - "delivered": 1, - } } }} return mocker.patch( @@ -2193,14 +1986,6 @@ def mock_get_annual_usage_for_service(mocker, service_one, fake_uuid): "rate": 0.017, "cost": 5.1 }, - { - "notification_type": "letter", - "chargeable_units": 300, - "notifications_sent": 100, - "charged_units": 300, - "rate": 0.1, - "cost": 30 - }, ] return mocker.patch( @@ -2217,7 +2002,6 @@ def mock_get_monthly_usage_for_service(mocker): 'rate': 0.017, 'chargeable_units': 1230, 'notifications_sent': 1234, - 'postage': 'none', 'charged_units': 1230, 'free_allowance_used': 0, 'cost': 20.91, @@ -2228,7 +2012,6 @@ def mock_get_monthly_usage_for_service(mocker): 'rate': 0.017, 'chargeable_units': 33, 'notifications_sent': 1234, - 'postage': 'none', 'charged_units': 33, 'free_allowance_used': 0, 'cost': 0.561, @@ -2239,7 +2022,6 @@ def mock_get_monthly_usage_for_service(mocker): 'rate': 0.0165, 'chargeable_units': 1100, 'notifications_sent': 1234, - 'postage': 'none', 'charged_units': 960, 'free_allowance_used': 140, 'cost': 15.84, @@ -2250,7 +2032,6 @@ def mock_get_monthly_usage_for_service(mocker): 'rate': 0.017, 'chargeable_units': 249860, 'notifications_sent': 1234, - 'postage': 'none', 'charged_units': 0, 'free_allowance_used': 249860, 'cost': 0, @@ -2347,45 +2128,6 @@ def mock_get_all_email_branding(mocker): ) -@pytest.fixture(scope='function') -def mock_get_all_letter_branding(mocker): - def _get_letter_branding(): - return [ - { - 'id': str(UUID(int=0)), - 'name': 'HM Government', - 'filename': 'hm-government', - }, - { - 'id': str(UUID(int=1)), - 'name': 'Land Registry', - 'filename': 'land-registry', - }, - { - 'id': str(UUID(int=2)), - 'name': 'Animal and Plant Health Agency', - 'filename': 'animal', - } - ] - - return mocker.patch( - 'app.letter_branding_client.get_all_letter_branding', side_effect=_get_letter_branding - ) - - -@pytest.fixture -def mock_get_letter_branding_by_id(mocker): - def _get_branding_by_id(_id): - return { - 'id': _id, - 'name': 'HM Government', - 'filename': 'hm-government', - } - return mocker.patch( - 'app.letter_branding_client.get_letter_branding', side_effect=_get_branding_by_id - ) - - @pytest.fixture(scope='function') def mock_no_email_branding(mocker): def _get_email_branding(): @@ -3371,14 +3113,6 @@ def mock_get_service_history(mocker): }) -@pytest.fixture(scope='function') -def mock_get_returned_letter_summary_with_no_returned_letters(mocker): - return mocker.patch( - 'app.service_api_client.get_returned_letter_summary', - return_value=[], - ) - - @pytest.fixture def mock_template_preview(mocker): content = b'{"count":1}' @@ -3392,17 +3126,6 @@ def mock_template_preview(mocker): mocker.patch('app.template_previews.TemplatePreview.from_utils_template', return_value=example_response) -@pytest.fixture(scope='function') -def mock_get_returned_letter_statistics_with_no_returned_letters(mocker): - return mocker.patch( - 'app.service_api_client.get_returned_letter_statistics', - return_value={ - 'returned_letter_count': 0, - 'most_recent_report': None, - }, - ) - - def create_api_user_active(with_unique_id=False): return create_user( id=str(uuid4()) if with_unique_id else sample_uuid(), @@ -3437,7 +3160,6 @@ def create_active_caseworking_user(with_unique_id=False): permissions={SERVICE_ONE_ID: [ 'send_texts', 'send_emails', - 'send_letters', ]}, services=[SERVICE_ONE_ID], ) @@ -3496,7 +3218,6 @@ def create_service_one_admin(**overrides): 'permissions': {SERVICE_ONE_ID: [ 'send_texts', 'send_emails', - 'send_letters', 'manage_users', 'manage_templates', 'manage_settings', @@ -3635,51 +3356,6 @@ def create_multiple_sms_senders(service_id='abcd'): ] -def create_letter_contact_block( - id_='1234', - service_id='abcd', - contact_block='1 Example Street', - is_default=True, - created_at=None, - updated_at=None, -): - return { - 'id': id_, - 'service_id': service_id, - 'contact_block': contact_block, - 'is_default': is_default, - 'created_at': created_at, - 'updated_at': updated_at - } - - -def create_multiple_letter_contact_blocks(service_id='abcd'): - return [ - { - 'id': '1234', - 'service_id': service_id, - 'contact_block': '1 Example Street', - 'is_default': True, - 'created_at': datetime.utcnow(), - 'updated_at': None - }, { - 'id': '5678', - 'service_id': service_id, - 'contact_block': '2 Example Street', - 'is_default': False, - 'created_at': datetime.utcnow(), - 'updated_at': None - }, { - 'id': '9457', - 'service_id': service_id, - 'contact_block': 'foo\n\n\n\nbaz', - 'is_default': False, - 'created_at': datetime.utcnow(), - 'updated_at': None - } - ] - - def create_notification( notifification_id=None, service_id='abcd', @@ -3687,9 +3363,7 @@ def create_notification( redact_personalisation=False, template_type=None, template_name='sample template', - is_precompiled_letter=False, key_type=None, - postage=None, sent_one_off=True, reply_to_text=None, ): @@ -3698,7 +3372,6 @@ def create_notification( rows=1, status=notification_status, template_type=template_type, - postage=postage, reply_to_text=reply_to_text, )['notifications'][0] @@ -3717,7 +3390,6 @@ def create_notification( subject='blah', redact_personalisation=redact_personalisation, type_=template_type, - is_precompiled_letter=is_precompiled_letter, name=template_name ) if key_type: @@ -3735,8 +3407,6 @@ def create_notifications( client_reference=None, personalisation=None, redact_personalisation=False, - is_precompiled_letter=False, - postage=None, to=None ): template = template_json( @@ -3746,7 +3416,6 @@ def create_notifications( subject=subject, content=content, redact_personalisation=redact_personalisation, - is_precompiled_letter=is_precompiled_letter ) return notification_json( @@ -3758,7 +3427,6 @@ def create_notifications( client_reference=client_reference, status=status, created_by_name='Firstname Lastname', - postage=postage, to=to ) @@ -3779,7 +3447,6 @@ def create_template( content='Template content', subject='Template subject', redact_personalisation=False, - postage=None, folder=None ): return template_json( @@ -3790,7 +3457,6 @@ def create_template( content=content, subject=subject, redact_personalisation=redact_personalisation, - postage=postage, folder=folder, )