From fe1de02954ffcf8b3afe145ad3f0ca1e75462efe Mon Sep 17 00:00:00 2001 From: Alex Pandel Date: Mon, 10 Apr 2023 16:46:36 -0700 Subject: [PATCH 01/10] Formatting updates for Notify 1-pager adjusting some heading sizes --- docs/notify-pilot-info.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/notify-pilot-info.md b/docs/notify-pilot-info.md index 2ae0240ff..500bd98f2 100644 --- a/docs/notify-pilot-info.md +++ b/docs/notify-pilot-info.md @@ -1,4 +1,4 @@ -### The Public Benefits Studio +# The Public Benefits Studio The Public Benefits Studio is a team inside of GSA’s Technology Transformation Services (TTS), home to innovative programs like 18F and @@ -11,7 +11,7 @@ We’re a cross-functional team of technologists with specialized experience working across public benefits programs like Medicaid, SNAP, and unemployment insurance. -### WHAT WE’RE CURRENTLY EXPLORING +## WHAT WE’RE CURRENTLY EXPLORING @@ -34,7 +34,7 @@ agency money.
-OUR FIRST BET: U.S. Notify +### OUR FIRST BET: U.S. Notify @@ -63,7 +63,7 @@ send thousands of customized-to-the-user text messages per year at little-to-no-cost. The easy interface requires no technical expertise to use and the setup process takes only ten minutes. -### WHERE WE’RE AT +## WHERE WE’RE AT **We’re in the early stages of assessing this product’s market fit and targeting to pilot** this shared service with at least 3 partners in @@ -79,7 +79,7 @@ additional features based on partner needs. | Message send/failure analytics | Application status page | Multilingual interface and content library options | | 1-day records deletion | Scheduled send option | Recurring scheduled send | -### OPPORTUNITIES TO GET INVOLVED +## OPPORTUNITIES TO GET INVOLVED To get involved, email us at [notify-support@gsa.gov](mailto:notify-support@gsa.gov) with the following in the subject line! @@ -98,7 +98,7 @@ To get involved, email us at [notify-support@gsa.gov](mailto:notify-support@gsa. Early adopters will have wrap-around set-up support from the Studio and an opportunity to shape the future of this product. -### US Notify Demo +## US Notify Demo From de668d7aba7f0ef3999f7f1b47afff480538b1dc Mon Sep 17 00:00:00 2001 From: Ryan Ahearn Date: Wed, 12 Apr 2023 15:35:14 -0400 Subject: [PATCH 02/10] Remove contact-list references from code --- app/__init__.py | 2 - app/config.py | 3 - app/main/views/send.py | 43 -- app/main/views/uploads.py | 211 +----- app/models/contact_list.py | 195 ----- app/models/job.py | 3 +- app/models/service.py | 5 - app/navigation.py | 12 - app/notify_client/contact_list_api_client.py | 37 - app/notify_client/job_api_client.py | 12 +- app/templates/views/check/ok.html | 5 +- app/templates/views/dashboard/_jobs.html | 26 +- app/templates/views/jobs/jobs.html | 10 - app/templates/views/send-contact-list.html | 78 -- app/templates/views/send-test.html | 5 +- .../uploads/contact-list/column-errors.html | 83 -- .../uploads/contact-list/contact-list.html | 142 ---- .../views/uploads/contact-list/ok.html | 64 -- .../uploads/contact-list/row-errors.html | 102 --- .../contact-list/too-many-columns.html | 104 --- .../views/uploads/contact-list/upload.html | 96 --- manifest.yml | 1 - terraform/development/main.tf | 14 - tests/__init__.py | 25 - tests/app/main/views/test_send.py | 238 ------ .../views/uploads/test_upload_contact_list.py | 714 ------------------ .../app/main/views/uploads/test_upload_hub.py | 78 -- tests/app/models/test_contact_list.py | 24 - tests/app/notify_client/test_job_client.py | 15 - tests/app/test_navigation.py | 8 - tests/conftest.py | 97 +-- 31 files changed, 11 insertions(+), 2441 deletions(-) delete mode 100644 app/models/contact_list.py delete mode 100644 app/notify_client/contact_list_api_client.py delete mode 100644 app/templates/views/send-contact-list.html delete mode 100644 app/templates/views/uploads/contact-list/column-errors.html delete mode 100644 app/templates/views/uploads/contact-list/contact-list.html delete mode 100644 app/templates/views/uploads/contact-list/ok.html delete mode 100644 app/templates/views/uploads/contact-list/row-errors.html delete mode 100644 app/templates/views/uploads/contact-list/too-many-columns.html delete mode 100644 app/templates/views/uploads/contact-list/upload.html delete mode 100644 tests/app/main/views/uploads/test_upload_contact_list.py delete mode 100644 tests/app/models/test_contact_list.py diff --git a/app/__init__.py b/app/__init__.py index 062f5b892..8d172b5b5 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -94,7 +94,6 @@ from app.notify_client import InviteTokenError from app.notify_client.api_key_api_client import api_key_api_client from app.notify_client.billing_api_client import billing_api_client from app.notify_client.complaint_api_client import complaint_api_client -from app.notify_client.contact_list_api_client import contact_list_api_client from app.notify_client.email_branding_client import email_branding_client from app.notify_client.events_api_client import events_api_client from app.notify_client.inbound_number_client import inbound_number_client @@ -216,7 +215,6 @@ def create_app(application): # API clients api_key_api_client, billing_api_client, - contact_list_api_client, complaint_api_client, email_branding_client, events_api_client, diff --git a/app/config.py b/app/config.py index f873d5b8f..2779364df 100644 --- a/app/config.py +++ b/app/config.py @@ -94,7 +94,6 @@ class Development(Config): # Buckets CSV_UPLOAD_BUCKET = _s3_credentials_from_env('CSV') - CONTACT_LIST_BUCKET = _s3_credentials_from_env('CONTACT') LOGO_UPLOAD_BUCKET = _s3_credentials_from_env('LOGO') # credential overrides @@ -127,8 +126,6 @@ class Production(Config): # buckets CSV_UPLOAD_BUCKET = cloud_config.s3_credentials( f"notify-api-csv-upload-bucket-{getenv('NOTIFY_ENVIRONMENT')}") - CONTACT_LIST_BUCKET = cloud_config.s3_credentials( - f"notify-api-contact-list-bucket-{getenv('NOTIFY_ENVIRONMENT')}") LOGO_UPLOAD_BUCKET = cloud_config.s3_credentials( f"notify-admin-logo-upload-bucket-{getenv('NOTIFY_ENVIRONMENT')}") diff --git a/app/main/views/send.py b/app/main/views/send.py index cc37f5427..764b3daee 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -35,7 +35,6 @@ from app.main.forms import ( SetSenderForm, get_placeholder_form_instance, ) -from app.models.contact_list import ContactList, ContactListsAlphabetical from app.models.user import Users from app.s3_client.s3_csv_client import ( get_csv_metadata, @@ -390,47 +389,6 @@ def send_one_off_step(service_id, template_id, step_index): ) -@main.route( - '/services//send/' - '/from-contact-list' -) -@user_has_permissions('send_messages') -def choose_from_contact_list(service_id, template_id): - db_template = current_service.get_template_with_user_permission_or_403( - template_id, current_user - ) - template = get_template( - db_template, current_service, - ) - return render_template( - 'views/send-contact-list.html', - contact_lists=ContactListsAlphabetical( - current_service.id, - template_type=template.template_type, - ), - template=template, - ) - - -@main.route( - '/services//send/' - '/from-contact-list/' -) -@user_has_permissions('send_messages') -def send_from_contact_list(service_id, template_id, contact_list_id): - contact_list = ContactList.from_id( - contact_list_id, - service_id=current_service.id, - ) - return redirect(url_for( - 'main.check_messages', - service_id=current_service.id, - template_id=template_id, - upload_id=contact_list.copy_to_uploads(), - contact_list_id=contact_list.id, - )) - - 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 @@ -573,7 +531,6 @@ def start_job(service_id, upload_id): upload_id, service_id, scheduled_for=request.form.get('scheduled_for', ''), - contact_list_id=request.form.get('contact_list_id', ''), ) session.pop('sender_id', None) diff --git a/app/main/views/uploads.py b/app/main/views/uploads.py index 7cbe73410..0fcc6184d 100644 --- a/app/main/views/uploads.py +++ b/app/main/views/uploads.py @@ -1,23 +1,10 @@ -import itertools from datetime import datetime -from io import BytesIO -from zipfile import BadZipFile -from flask import flash, redirect, render_template, request, send_file, url_for -from notifications_utils.insensitive_dict import InsensitiveDict -from notifications_utils.recipients import RecipientCSV -from notifications_utils.sanitise_text import SanitiseASCII -from xlrd.biffh import XLRDError -from xlrd.xldate import XLDateError +from flask import render_template, request from app import current_service from app.main import main -from app.main.forms import CsvUploadForm -from app.models.contact_list import ContactList -from app.utils import unicode_truncate -from app.utils.csv import Spreadsheet, get_errors_for_csv from app.utils.pagination import generate_next_dict, generate_previous_dict -from app.utils.templates import get_sample_template from app.utils.user import user_has_permissions MAX_FILE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB @@ -39,7 +26,6 @@ def uploads(service_id): if uploads.current_page == 1: listed_uploads = ( - current_service.contact_lists + current_service.scheduled_jobs + uploads ) @@ -53,198 +39,3 @@ def uploads(service_id): next_page=next_page, now=datetime.utcnow().isoformat(), ) - - -@main.route("/services//upload-contact-list", methods=['GET', 'POST']) -@user_has_permissions('send_messages') -def upload_contact_list(service_id): - form = CsvUploadForm() - - if form.validate_on_submit(): - try: - upload_id = ContactList.upload( - current_service.id, - Spreadsheet.from_file_form(form).as_dict, - ) - file_name_metadata = unicode_truncate( - SanitiseASCII.encode(form.file.data.filename), - 1600 - ) - ContactList.set_metadata( - current_service.id, - upload_id, - original_file_name=file_name_metadata - ) - return redirect(url_for( - '.check_contact_list', - service_id=service_id, - upload_id=upload_id, - )) - except (UnicodeDecodeError, BadZipFile, XLRDError): - flash('Could not read {}. Try using a different file format.'.format( - form.file.data.filename - )) - except (XLDateError): - flash(( - '{} contains numbers or dates that Notify cannot understand. ' - 'Try formatting all columns as ‘text’ or export your file as CSV.' - ).format( - form.file.data.filename - )) - elif form.errors: - # just show the first error, as we don't expect the form to have more - # than one, since it only has one field - first_field_errors = list(form.errors.values())[0] - flash(first_field_errors[0]) - - return render_template( - 'views/uploads/contact-list/upload.html', - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS, - ) - - -@main.route( - "/services//check-contact-list/", - methods=['GET', 'POST'], -) -@user_has_permissions('send_messages') -def check_contact_list(service_id, upload_id): - - form = CsvUploadForm() - - contents = ContactList.download(service_id, upload_id) - first_row = contents.splitlines()[0].strip().rstrip(',') if contents else '' - original_file_name = ContactList.get_metadata(service_id, upload_id).get('original_file_name', '') - - template_type = InsensitiveDict({ - 'email address': 'email', - 'phone number': 'sms', - }).get(first_row) - - recipients = RecipientCSV( - contents, - template=get_sample_template(template_type or 'sms'), - guestlist=itertools.chain.from_iterable( - [user.name, user.mobile_number, user.email_address] - for user in current_service.active_users - ) if current_service.trial_mode else None, - allow_international_sms=current_service.has_permission('international_sms'), - max_initial_rows_shown=50, - max_errors_shown=50, - ) - - non_empty_column_headers = list(filter(None, recipients.column_headers)) - - if len(non_empty_column_headers) > 1 or not template_type or not recipients: - return render_template( - 'views/uploads/contact-list/too-many-columns.html', - recipients=recipients, - original_file_name=original_file_name, - template_type=template_type, - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS - ) - - if recipients.too_many_rows or not len(recipients): - return render_template( - 'views/uploads/contact-list/column-errors.html', - recipients=recipients, - original_file_name=original_file_name, - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS - ) - - row_errors = get_errors_for_csv(recipients, template_type) - if row_errors: - return render_template( - 'views/uploads/contact-list/row-errors.html', - recipients=recipients, - original_file_name=original_file_name, - row_errors=row_errors, - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS - ) - - if recipients.has_errors: - return render_template( - 'views/uploads/contact-list/column-errors.html', - recipients=recipients, - original_file_name=original_file_name, - form=form, - allowed_file_extensions=Spreadsheet.ALLOWED_FILE_EXTENSIONS - ) - - metadata_kwargs = { - 'row_count': len(recipients), - 'valid': True, - 'original_file_name': original_file_name, - 'template_type': template_type - } - - ContactList.set_metadata(service_id, upload_id, **metadata_kwargs) - - return render_template( - 'views/uploads/contact-list/ok.html', - recipients=recipients, - original_file_name=original_file_name, - upload_id=upload_id, - ) - - -@main.route("/services//save-contact-list/", methods=['POST']) -@user_has_permissions('send_messages') -def save_contact_list(service_id, upload_id): - ContactList.create(current_service.id, upload_id) - return redirect(url_for( - '.uploads', - service_id=current_service.id, - )) - - -@main.route("/services//contact-list/", methods=['GET']) -@user_has_permissions('send_messages') -def contact_list(service_id, contact_list_id): - contact_list = ContactList.from_id(contact_list_id, service_id=service_id) - return render_template( - 'views/uploads/contact-list/contact-list.html', - contact_list=contact_list, - jobs=contact_list.get_jobs( - page=1, - limit_days=current_service.get_days_of_retention(contact_list.template_type), - ), - ) - - -@main.route("/services//contact-list//delete", methods=['GET', 'POST']) -@user_has_permissions('manage_templates') -def delete_contact_list(service_id, contact_list_id): - contact_list = ContactList.from_id(contact_list_id, service_id=service_id) - - if request.method == 'POST': - contact_list.delete() - return redirect(url_for( - '.uploads', - service_id=service_id, - )) - - flash([ - f"Are you sure you want to delete ‘{contact_list.original_file_name}’?", - ], 'delete') - - return render_template( - 'views/uploads/contact-list/contact-list.html', - contact_list=contact_list, - confirm_delete_banner=True, - ) - - -@main.route("/services//contact-list/.csv", methods=['GET']) -@user_has_permissions('send_messages') -def download_contact_list(service_id, contact_list_id): - contact_list = ContactList.from_id(contact_list_id, service_id=service_id) - return send_file( - path_or_file=BytesIO(contact_list.contents.encode('utf-8')), - download_name=contact_list.saved_file_name, - as_attachment=True, - ) diff --git a/app/models/contact_list.py b/app/models/contact_list.py deleted file mode 100644 index dfecaf50a..000000000 --- a/app/models/contact_list.py +++ /dev/null @@ -1,195 +0,0 @@ -from functools import partial -from os import path -from uuid import uuid4 - -from flask import abort, current_app -from notifications_utils.formatters import strip_all_whitespace -from notifications_utils.recipients import RecipientCSV -from notifications_utils.s3 import s3upload as utils_s3upload -from werkzeug.utils import cached_property - -from app.models import JSONModel, ModelList -from app.models.job import PaginatedJobsAndScheduledJobs -from app.notify_client.contact_list_api_client import contact_list_api_client -from app.s3_client import ( - get_s3_contents, - get_s3_metadata, - get_s3_object, - set_s3_metadata, -) -from app.s3_client.s3_csv_client import s3upload, set_metadata_on_csv_upload -from app.utils.templates import get_sample_template - - -class ContactList(JSONModel): - - ALLOWED_PROPERTIES = { - 'id', - 'created_at', - 'created_by', - 'has_jobs', - 'recent_job_count', - 'service_id', - 'original_file_name', - 'row_count', - 'template_type', - } - - upload_type = 'contact_list' - - @classmethod - def from_id(cls, contact_list_id, *, service_id): - return cls(contact_list_api_client.get_contact_list( - service_id=service_id, - contact_list_id=contact_list_id, - )) - - @staticmethod - def get_bucket_credentials(key): - return current_app.config['CONTACT_LIST_BUCKET'][key] - - @staticmethod - def get_bucket_name(): - return ContactList.get_bucket_credentials('bucket') - - @staticmethod - def get_access_key(): - return ContactList.get_bucket_credentials('access_key_id') - - @staticmethod - def get_secret_key(): - return ContactList.get_bucket_credentials('secret_access_key') - - @staticmethod - def get_region(): - return ContactList.get_bucket_credentials('region') - - @staticmethod - def get_filename(service_id, upload_id): - return f"service-{service_id}-notify/{upload_id}.csv" - - @staticmethod - def get_s3_arguments(service_id, upload_id): - return ( - ContactList.get_bucket_name(), - ContactList.get_filename(service_id, upload_id), - ContactList.get_access_key(), - ContactList.get_secret_key(), - ContactList.get_region(), - ) - - @staticmethod - def upload(service_id, file_dict): - upload_id = str(uuid4()) - utils_s3upload( - filedata=file_dict['data'], - region=ContactList.get_region(), - bucket_name=ContactList.get_bucket_name(), - file_location=ContactList.get_filename(service_id, upload_id), - access_key=ContactList.get_access_key(), - secret_key=ContactList.get_secret_key(), - ) - return upload_id - - @staticmethod - def download(service_id, upload_id): - return strip_all_whitespace( - get_s3_contents( - get_s3_object(*ContactList.get_s3_arguments(service_id, upload_id)))) - - @staticmethod - def set_metadata(service_id, upload_id, **kwargs): - return set_s3_metadata(get_s3_object(*ContactList.get_s3_arguments(service_id, upload_id)), **kwargs) - - @staticmethod - def get_metadata(service_id, upload_id): - return get_s3_metadata(get_s3_object(*ContactList.get_s3_arguments(service_id, upload_id))) - - def copy_to_uploads(self): - raise RuntimeError("RCA probably an issue with copying between buckets") - metadata = self.get_metadata(self.service_id, self.id) - new_upload_id = s3upload( - self.service_id, - {'data': self.contents}, - ContactList.get_region(), - ) - set_metadata_on_csv_upload( - self.service_id, - new_upload_id, - **metadata, - ) - return new_upload_id - - @classmethod - def create(cls, service_id, upload_id): - - metadata = cls.get_metadata(service_id, upload_id) - - if not metadata.get('valid'): - abort(403) - - return cls(contact_list_api_client.create_contact_list( - service_id=service_id, - upload_id=upload_id, - original_file_name=metadata['original_file_name'], - row_count=int(metadata['row_count']), - template_type=metadata['template_type'], - )) - - def delete(self): - contact_list_api_client.delete_contact_list( - service_id=self.service_id, - contact_list_id=self.id, - ) - - @property - def contents(self): - return self.download(self.service_id, self.id) - - @cached_property - def recipients(self): - return RecipientCSV( - self.contents, - template=get_sample_template(self.template_type), - allow_international_sms=True, - max_initial_rows_shown=50, - ) - - @property - def saved_file_name(self): - file_name, extention = path.splitext(self.original_file_name) - return f'{file_name}.csv' - - def get_jobs(self, *, page, limit_days=None): - return PaginatedJobsAndScheduledJobs( - self.service_id, - contact_list_id=self.id, - page=page, - limit_days=limit_days, - ) - - -class ContactLists(ModelList): - - client_method = contact_list_api_client.get_contact_lists - model = ContactList - sort_function = partial( - sorted, - key=lambda item: item['created_at'], - reverse=True, - ) - - def __init__(self, service_id, template_type=None): - super().__init__(service_id) - self.items = self.sort_function([ - item for item in self.items - if template_type in {item['template_type'], None} - ]) - - -class ContactListsAlphabetical(ContactLists): - - sort_function = partial( - sorted, - key=lambda item: item['original_file_name'].lower(), - ) diff --git a/app/models/job.py b/app/models/job.py index 237452965..3fa1f7d33 100644 --- a/app/models/job.py +++ b/app/models/job.py @@ -172,10 +172,9 @@ class PaginatedJobs(PaginatedModelList, ImmediateJobs): client_method = job_api_client.get_page_of_jobs statuses = None - def __init__(self, service_id, *, contact_list_id=None, page=None, limit_days=None): + def __init__(self, service_id, *, page=None, limit_days=None): super().__init__( service_id, - contact_list_id=contact_list_id, statuses=self.statuses, page=page, limit_days=limit_days, diff --git a/app/models/service.py b/app/models/service.py index 3ea3d75aa..b16faae37 100644 --- a/app/models/service.py +++ b/app/models/service.py @@ -3,7 +3,6 @@ from notifications_utils.serialised_model import SerialisedModelCollection from werkzeug.utils import cached_property from app.models import JSONModel, SortByNameMixin -from app.models.contact_list import ContactLists from app.models.job import ( ImmediateJobs, PaginatedJobs, @@ -527,10 +526,6 @@ class Service(JSONModel, SortByNameMixin): } ) - @property - def contact_lists(self): - return ContactLists(self.id) - class Services(SerialisedModelCollection): model = Service diff --git a/app/navigation.py b/app/navigation.py index 65c97deb3..cbb80a622 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -141,7 +141,6 @@ class MainNavigation(Navigation): 'add_service_template', 'check_messages', 'check_notification', - 'choose_from_contact_list', 'choose_template', 'choose_template_to_copy', 'confirm_redact_template', @@ -161,11 +160,6 @@ class MainNavigation(Navigation): 'view_template_versions', }, 'uploads': { - 'upload_contact_list', - 'check_contact_list', - 'save_contact_list', - 'contact_list', - 'delete_contact_list', 'uploads', 'view_job', 'view_jobs', @@ -244,7 +238,6 @@ class CaseworkNavigation(Navigation): mapping = { 'send-one-off': { - 'choose_from_contact_list', 'choose_template', 'send_one_off', 'send_one_off_step', @@ -257,11 +250,6 @@ class CaseworkNavigation(Navigation): 'uploads': { 'view_jobs', 'view_job', - 'upload_contact_list', - 'check_contact_list', - 'save_contact_list', - 'contact_list', - 'delete_contact_list', 'uploads', }, } diff --git a/app/notify_client/contact_list_api_client.py b/app/notify_client/contact_list_api_client.py deleted file mode 100644 index 9f7c04dc7..000000000 --- a/app/notify_client/contact_list_api_client.py +++ /dev/null @@ -1,37 +0,0 @@ -from app.notify_client import NotifyAdminAPIClient, _attach_current_user - - -class ContactListApiClient(NotifyAdminAPIClient): - - def create_contact_list( - self, - *, - service_id, - upload_id, - original_file_name, - row_count, - template_type, - ): - data = { - "id": upload_id, - "original_file_name": original_file_name, - "row_count": row_count, - "template_type": template_type, - } - - data = _attach_current_user(data) - job = self.post(url='/service/{}/contact-list'.format(service_id), data=data) - - return job - - def get_contact_lists(self, service_id): - return self.get(f'/service/{service_id}/contact-list') - - def get_contact_list(self, *, service_id, contact_list_id): - return self.get(f'/service/{service_id}/contact-list/{contact_list_id}') - - def delete_contact_list(self, *, service_id, contact_list_id): - return self.delete(f'/service/{service_id}/contact-list/{contact_list_id}') - - -contact_list_api_client = ContactListApiClient() diff --git a/app/notify_client/job_api_client.py b/app/notify_client/job_api_client.py index 7fd8af213..c54220657 100644 --- a/app/notify_client/job_api_client.py +++ b/app/notify_client/job_api_client.py @@ -25,14 +25,12 @@ class JobApiClient(NotifyAdminAPIClient): return job - def get_jobs(self, service_id, *, limit_days=None, contact_list_id=None, statuses=None, page=1): + def get_jobs(self, service_id, *, limit_days=None, statuses=None, page=1): params = {'page': page} if limit_days is not None: params['limit_days'] = limit_days if statuses is not None: params['statuses'] = ','.join(statuses) - if contact_list_id is not None: - params['contact_list_id'] = contact_list_id return self.get(url='/service/{}/job'.format(service_id), params=params) @@ -53,12 +51,11 @@ class JobApiClient(NotifyAdminAPIClient): if job['job_status'] != 'cancelled' ) - def get_page_of_jobs(self, service_id, *, page, statuses=None, contact_list_id=None, limit_days=None): + def get_page_of_jobs(self, service_id, *, page, statuses=None, limit_days=None): return self.get_jobs( service_id, statuses=statuses or self.NON_SCHEDULED_JOB_STATUSES, page=page, - contact_list_id=contact_list_id, limit_days=limit_days, ) @@ -88,15 +85,12 @@ class JobApiClient(NotifyAdminAPIClient): def has_jobs(self, service_id): return bool(self.get_jobs(service_id)['data']) - def create_job(self, job_id, service_id, scheduled_for=None, contact_list_id=None): + def create_job(self, job_id, service_id, scheduled_for=None): data = {"id": job_id} if scheduled_for: data.update({'scheduled_for': scheduled_for}) - if contact_list_id: - data.update({'contact_list_id': contact_list_id}) - data = _attach_current_user(data) job = self.post(url='/service/{}/job'.format(service_id), data=data) diff --git a/app/templates/views/check/ok.html b/app/templates/views/check/ok.html index f933099ab..b584b6930 100644 --- a/app/templates/views/check/ok.html +++ b/app/templates/views/check/ok.html @@ -30,7 +30,6 @@
- {% if choose_time_form %} {{ choose_time_form.scheduled_for(param_extensions={ 'formGroup': {'classes': 'bottom-gutter-2-3'}, @@ -41,12 +40,12 @@ } }) }} {% endif %} - + {% set button_text %} Send {{ count_of_recipients|message_count(template.template_type) }} {% endset %} {{ govukButton({ "text": button_text }) }} - +
diff --git a/app/templates/views/dashboard/_jobs.html b/app/templates/views/dashboard/_jobs.html index 0c50a57e1..eaa8d026d 100644 --- a/app/templates/views/dashboard/_jobs.html +++ b/app/templates/views/dashboard/_jobs.html @@ -17,31 +17,13 @@ ) %} {% call row_heading() %}
- {% if item.upload_type == 'contact_list' %} - {{ item.original_file_name }} - {% else %} - {{ item.original_file_name }} - {% endif %} + {{ item.original_file_name }} {% if item.scheduled %} Sending {{ item.scheduled_for|format_datetime_relative }} - {% elif item.upload_type == 'contact_list' %} - - {% if item.recent_job_count %} - Used {{ item.recent_job_count|iteration_count }} - in the last - {{ current_service.get_days_of_retention(item.template_type) }} - days - {% elif item.has_jobs %} - Not used in the last - {{ current_service.get_days_of_retention(item.template_type) }} - days - {% else %} - Not used yet - {% endif %} {% else %} Sent {{ @@ -62,12 +44,6 @@ suffix='waiting to send' ) ) }} - {% 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)) - ) }} {% else %}
diff --git a/app/templates/views/jobs/jobs.html b/app/templates/views/jobs/jobs.html index 27b907506..a647c3a25 100644 --- a/app/templates/views/jobs/jobs.html +++ b/app/templates/views/jobs/jobs.html @@ -17,15 +17,5 @@

{% endif %} {{ previous_next_navigation(prev_page, next_page) }} - {% if current_user.has_permissions('send_messages') %} -
- {{ govukButton({ - "element": "a", - "text": "Upload an emergency contact list", - "href": url_for('.upload_contact_list', service_id=current_service.id), - "classes": "govuk-button--secondary" - }) }} -
- {% endif %}
{% endblock %} diff --git a/app/templates/views/send-contact-list.html b/app/templates/views/send-contact-list.html deleted file mode 100644 index 13c4b667c..000000000 --- a/app/templates/views/send-contact-list.html +++ /dev/null @@ -1,78 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/big-number.html" import big_number -%} -{% from "components/list.html" import list_of_placeholders %} -{% from "components/page-header.html" import page_header %} -{% from "components/table.html" import list_table, field, right_aligned_field_heading, row_heading %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Choose an emergency contact list -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('.send_one_off', service_id=current_service.id, template_id=template.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header('Choose an emergency contact list') }} - - {% if template.placeholders %} -
-
-

- You cannot use an emergency contact list with this template because it - is personalized with {{ list_of_placeholders(template.placeholders) }}. -

-

- Emergency contact lists can only include email addresses or phone - numbers. -

-
-
- {% elif contact_lists %} -
- {% call(item, row_number) list_table( - contact_lists, - caption="Emergency contact lists", - caption_visible=False, - empty_message=( - 'You have not saved any contact lists yet.' - ), - field_headings=[ - 'File', - 'Status' - ], - field_headings_visible=False - ) %} - {% call row_heading() %} -
- {{ item.original_file_name }} - - Uploaded {{ item.created_at|format_datetime_relative }} - -
- {% endcall %} - {% call field() %} - {{ big_number( - item.row_count, - smallest=True, - label=item.row_count|recipient_count_label(item.template_type), - ) }} - {% endcall %} - {% endcall %} -
- {% else %} -
-
-

- You have not saved any lists of {{ 99|recipient_count_label(template.template_type) }} yet. -

-

- To upload and save an emergency contact list, go to the uploads page. -

-
-
- {% endif %} - -{% endblock %} diff --git a/app/templates/views/send-test.html b/app/templates/views/send-test.html index f2c029ce5..db9de5dc2 100644 --- a/app/templates/views/send-test.html +++ b/app/templates/views/send-test.html @@ -31,9 +31,6 @@
{% if link_to_upload %} Upload a list of {{ 999|recipient_count_label(template.template_type) }} - {% if current_service.contact_lists %} - Use an emergency list - {% endif %} {% endif %} {% if skip_link %} {{ skip_link[0] }} @@ -49,6 +46,6 @@ {{ page_footer('Continue') }} {% endcall %} - + {% endblock %} diff --git a/app/templates/views/uploads/contact-list/column-errors.html b/app/templates/views/uploads/contact-list/column-errors.html deleted file mode 100644 index bdee61af8..000000000 --- a/app/templates/views/uploads/contact-list/column-errors.html +++ /dev/null @@ -1,83 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %} -{% from "components/file-upload.html" import file_upload %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Error -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.upload_contact_list', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
- {% call banner_wrapper(type='dangerous') %} - - {% if recipients.too_many_rows %} - -

- Your file has too many rows -

-

- Notify can store files up to - {{ "{:,}".format(recipients.max_rows) }} rows in size. Your - file has {{ "{:,}".format(recipients|length) }} rows. -

- - {% elif not recipients.allowed_to_send_to %} - -

- You cannot save - {{ 'this' if recipients|length == 1 else 'these' }} - {{ recipients|length|recipient_count_label(recipients.template_type) }} -

-

- In trial mode you can only - send to yourself and members of your team -

- - {% endif %} - {% endcall %} -
- - -
-
- {{ file_upload( - form.file, - allowed_file_extensions=allowed_file_extensions, - action=url_for('.upload_contact_list', service_id=current_service.id), - button_text='Upload your file again' - ) }} -
- Back to top -
- -

{{ original_file_name }}

- - {% call(item, row_number) list_table( - recipients.displayed_rows, - caption=original_file_name, - caption_visible=False, - field_headings=[ - 'Row in file '|safe - ] + recipients.column_headers - ) %} - {{ index_field(item.index + 2) }} - {% for column in recipients.column_headers %} - {{ text_field(item[column].data or '') }} - {% endfor %} - {% endcall %} - - {% if recipients.displayed_rows|list|length < recipients|length %} - - {% endif %} - -{% endblock %} diff --git a/app/templates/views/uploads/contact-list/contact-list.html b/app/templates/views/uploads/contact-list/contact-list.html deleted file mode 100644 index 578a0b5f2..000000000 --- a/app/templates/views/uploads/contact-list/contact-list.html +++ /dev/null @@ -1,142 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/big-number.html" import big_number %} -{% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading, row, row_heading %} -{% from "components/page-header.html" import page_header %} -{% from "components/uk_components/button/macro.njk" import govukButton %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - {{ contact_list.original_file_name }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.uploads', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header(contact_list.original_file_name) }} - -

- Uploaded by {{ contact_list.created_by }} {{ contact_list.created_at|format_datetime_human }}. -

- - {% if jobs %} -

- Used {{ jobs|length|iteration_count }} - in the last {{ current_service.get_days_of_retention(contact_list.template_type) }} - days. -

-
- {% call(item, row_number) list_table( - jobs, - caption="Messages sent from this contact list", - caption_visible=False, - empty_message='', - field_headings=[ - 'Template', - 'Status' - ], - field_headings_visible=False - ) %} - {% call row_heading() %} -
- {{ item.template_name }} - {% if item.scheduled %} - - Sending {{ - item.scheduled_for|format_datetime_relative - }} - - {% else %} - - Sent {{ - (item.scheduled_for or item.created_at)|format_datetime_relative - }} - - {% endif %} - -
- {% endcall %} - {% call field() %} - {% if item.scheduled %} - {{ big_number( - item.notification_count, - smallest=True, - label=item.notification_count|message_count_label( - item.template_type, - suffix='waiting to send' - ) - ) }} - {% else %} -
-
- {{ big_number( - item.notifications_sending, - smallest=True, - label='sending', - ) }} -
-
- {{ big_number(item.notifications_delivered, smallest=True, label='delivered') }} -
-
- {{ big_number(item.notifications_failed, smallest=True, label='failed') }} -
-
- {% endif %} - {% endcall %} - {% endcall %} -
- {% else %} -

- {% if contact_list.has_jobs %} - Not used in the last {{ current_service.get_days_of_retention(contact_list.template_type) }} days. - {% else %} - Not used yet. - {% endif %} -

- {% endif %} - -

- {{ contact_list.recipients|length|format_thousands }} saved {{ contact_list.recipients|length|recipient_count_label(contact_list.template_type) }} -

- - {% set recipient_column = contact_list.recipients.column_headers[0] %} - -
- {% call(item, row_number) list_table( - contact_list.recipients.displayed_rows, - caption=contact_list.recipients|length|recipient_count_label(contact_list.template_type)|capitalize, - caption_visible=False, - field_headings=[recipient_column], - field_headings_visible=False, - ) %} - {% if not loop.first %} - {{ text_field(item[recipient_column].data) }} - {% endif %} - {% endcall %} - - {% if contact_list.recipients.displayed_rows|list|length < contact_list.recipients|length %} - - {% endif %} -
- - -
- -
- - -{% endblock %} diff --git a/app/templates/views/uploads/contact-list/ok.html b/app/templates/views/uploads/contact-list/ok.html deleted file mode 100644 index f0d71c4ac..000000000 --- a/app/templates/views/uploads/contact-list/ok.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %} -{% from "components/page-header.html" import page_header %} -{% from "components/uk_components/button/macro.njk" import govukButton %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - {{ original_file_name }} -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.upload_contact_list', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - - {{ page_header(original_file_name) }} - -

- {{ recipients|length|recipient_count(recipients.template_type) }} found -

- -
-
- - {{ govukButton({ "text": "Save contact list" }) }} - -
- -

- File preview -

- {% call(item, row_number) list_table( - recipients.displayed_rows, - caption=original_file_name, - caption_visible=False, - field_headings=[ - 'Row in file '|safe - ] + recipients.column_headers - ) %} - {{ index_field(item.index + 2) }} - {% for column in recipients.column_headers %} - {% if item[column].ignore %} - {{ text_field(item[column].data or '', status='default') }} - {% else %} - {{ text_field(item[column].data or '') }} - {% endif %} - {% endfor %} - {% if item[None].data %} - {% for column in item[None].data %} - {{ text_field(column, status='default') }} - {% endfor %} - {% endif %} - {% endcall %} - - {% if recipients.displayed_rows|list|length < recipients|length %} - - {% endif %} - -{% endblock %} diff --git a/app/templates/views/uploads/contact-list/row-errors.html b/app/templates/views/uploads/contact-list/row-errors.html deleted file mode 100644 index 27e95165d..000000000 --- a/app/templates/views/uploads/contact-list/row-errors.html +++ /dev/null @@ -1,102 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %} -{% from "components/file-upload.html" import file_upload %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Error -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.upload_contact_list', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
- {% call banner_wrapper(type='dangerous') %} - {% if row_errors|length == 1 %} -

- There’s a problem with {{ original_file_name }} -

-

- You need to {{ row_errors[0] }}. -

- {% else %} -

- There are some problems with {{ original_file_name }} -

-

- You need to: -

-
    - {% for error in row_errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} - {% endcall %} -
- -
-
- {{ file_upload( - form.file, - allowed_file_extensions=allowed_file_extensions, - action=url_for('.upload_contact_list', service_id=current_service.id), - button_text='Upload your file again' - ) }} -
- Back to top -
- - {% call(item, row_number) list_table( - recipients.displayed_rows, - caption=original_file_name, - caption_visible=False, - field_headings=[ - 'Row in file '|safe - ] + recipients.column_headers - ) %} - {% call index_field() %} - - {{ item.index + 2 }} - - {% endcall %} - {% for column in recipients.column_headers %} - {% if item[column].error and not recipients.missing_column_headers %} - {% call field() %} - - {{ item[column].error }} - {{ item[column].data if item[column].data != None }} - - {% endcall %} - {% elif item[column].ignore %} - {{ text_field(item[column].data or '', status='default') }} - {% else %} - {{ text_field(item[column].data or '') }} - {% endif %} - {% endfor %} - {% if item[None].data %} - {% for column in item[None].data %} - {{ text_field(column, status='default') }} - {% endfor %} - {% endif %} - {% endcall %} - - {% if recipients.displayed_rows|list|length < recipients|length %} - {% if recipients.displayed_rows|list|length < recipients.rows_with_errors|list|length %} - - {% else %} - - {% endif %} - {% endif %} - - -{% endblock %} diff --git a/app/templates/views/uploads/contact-list/too-many-columns.html b/app/templates/views/uploads/contact-list/too-many-columns.html deleted file mode 100644 index 0be946b71..000000000 --- a/app/templates/views/uploads/contact-list/too-many-columns.html +++ /dev/null @@ -1,104 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %} -{% from "components/file-upload.html" import file_upload %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Error -{% endblock %} - -{% block backLink %} - {{ govukBackLink({ "href": url_for('main.upload_contact_list', service_id=current_service.id) }) }} -{% endblock %} - -{% block maincolumn_content %} - -
- {% call banner_wrapper(type='dangerous') %} - - {% if not recipients|length %} - -

- Your file is missing some rows -

-

- It needs at least one row of data - {%- if template_type %}.{% else %}, in a column called ‘email address’ or ‘phone number’.{% endif %} -

- - {% elif recipients.column_headers|length == 1 %} - -

- Your file needs a column called ‘email address’ or ‘phone number’. -

-

- Right now it has 1 column called ‘{{ recipients._raw_column_headers[0] }}’. -

- - {% else %} - -

- Your file has too many columns -

-

- It needs to have 1 column, called ‘email address’ or ‘phone number’. -

-

- Right now it has {{ recipients._raw_column_headers|length }} columns called {{ recipients._raw_column_headers | formatted_list }}. -

- - {% endif %} - {% endcall %} -
- - -
-
- {{ file_upload( - form.file, - allowed_file_extensions=allowed_file_extensions, - action=url_for('.upload_contact_list', service_id=current_service.id), - button_text='Upload your file again' - ) }} -
- Back to top -
- - {% set column_headers = recipients._raw_column_headers if recipients.duplicate_recipient_column_headers else recipients.column_headers %} - -

{{ original_file_name }}

- -
- {% call(item, row_number) list_table( - recipients.displayed_rows, - caption=original_file_name, - caption_visible=False, - field_headings=[ - 'Row in file '|safe - ] + recipients._raw_column_headers - ) %} - {{ index_field(item.index + 2) }} - {% for column in column_headers %} - {% if item[column].ignore %} - {{ text_field(item[column].data or '', status='default') }} - {% else %} - {{ text_field(item[column].data or '') }} - {% endif %} - {% endfor %} - {% if item[None].data %} - {% for column in item[None].data %} - {{ text_field(column, status='default') }} - {% endfor %} - {% endif %} - {% endcall %} -
- - {% if recipients.displayed_rows|list|length < recipients|length %} - - {% endif %} - -{% endblock %} diff --git a/app/templates/views/uploads/contact-list/upload.html b/app/templates/views/uploads/contact-list/upload.html deleted file mode 100644 index d446d3db5..000000000 --- a/app/templates/views/uploads/contact-list/upload.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends "withnav_template.html" %} -{% from "components/banner.html" import banner_wrapper %} -{% from "components/file-upload.html" import file_upload %} -{% from "components/page-header.html" import page_header %} -{% from "components/table.html" import list_table, text_field, index_field, index_field_heading %} -{% from "components/uk_components/back-link/macro.njk" import govukBackLink %} - -{% block service_page_title %} - Upload an emergency contact list -{% endblock %} - -{% block backLink %} - {% if not error %} - {{ govukBackLink({ "href": url_for('main.uploads', service_id=current_service.id) }) }} - {% endif %} -{% endblock %} - -{% block maincolumn_content %} - {% if error %} - {% call banner_wrapper(type='dangerous') %} -

{{ error.title }}

- {% if error.detail %} -

{{ error.detail | safe }}

- {% endif %} - {% endcall %} - {% else %} - {{ page_header('Upload an emergency contact list') }} -

- Save a list of staff email addresses or phone numbers in Notify. -

-

- In an emergency, you can send a message to everyone on the list. -

-

- Do not include contact details for members of the public. -

- {% endif %} - -
- {{ file_upload( - form.file, - allowed_file_extensions=allowed_file_extensions, - button_text='Choose file', - show_errors=False, - )}} -
- -

Your file needs to look like one of these examples

- -

- Save your file as a - CSV, - TSV, - ODS, - or Microsoft Excel spreadsheet -

- -
-
-
- {% call(item, row_number) list_table( - [ - ['email address'], - ['test@example.gsa.gov'], - ], - caption="Example", - caption_visible=False, - field_headings=['', 'A'] - ) %} - {{ index_field(row_number - 1) }} - {% for column in item %} - {{ text_field(column) }} - {% endfor %} - {% endcall %} -
-
-
-
- {% call(item, row_number) list_table( - [ - ['phone number'], - ['555-867-5309'], - ], - caption="Example", - caption_visible=False, - field_headings=['', 'A'] - ) %} - {{ index_field(row_number - 1) }} - {% for column in item %} - {{ text_field(column) }} - {% endfor %} - {% endcall %} -
-
-
-{% endblock %} diff --git a/manifest.yml b/manifest.yml index 47a351009..743a0e251 100644 --- a/manifest.yml +++ b/manifest.yml @@ -14,7 +14,6 @@ applications: services: - notify-admin-redis-((env)) - notify-api-csv-upload-bucket-((env)) - - notify-api-contact-list-bucket-((env)) - notify-admin-logo-upload-bucket-((env)) env: diff --git a/terraform/development/main.tf b/terraform/development/main.tf index 60a541abc..8e3c16a9c 100644 --- a/terraform/development/main.tf +++ b/terraform/development/main.tf @@ -32,15 +32,6 @@ resource "cloudfoundry_service_key" "csv_key" { service_instance = data.cloudfoundry_service_instance.csv_bucket.id } -data "cloudfoundry_service_instance" "contact_list_bucket" { - name_or_id = "${var.username}-contact-list-bucket" - space = data.cloudfoundry_space.dev.id -} -resource "cloudfoundry_service_key" "contact_list_key" { - name = local.key_name - service_instance = data.cloudfoundry_service_instance.contact_list_bucket.id -} - locals { credentials = < Date: Wed, 12 Apr 2023 16:13:02 -0400 Subject: [PATCH 03/10] Force redeploy of egress proxies --- deploy-config/egress_proxy/notify-admin-demo.deploy.acl | 3 +++ deploy-config/egress_proxy/notify-admin-staging.deploy.acl | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 deploy-config/egress_proxy/notify-admin-demo.deploy.acl diff --git a/deploy-config/egress_proxy/notify-admin-demo.deploy.acl b/deploy-config/egress_proxy/notify-admin-demo.deploy.acl new file mode 100644 index 000000000..a05cd401b --- /dev/null +++ b/deploy-config/egress_proxy/notify-admin-demo.deploy.acl @@ -0,0 +1,3 @@ +Update this file to force a re-deploy of the egress proxy even when notify-admin-demo..acl haven't changed + +20230412: Redeploy to re-calculate the list of allowed s3 buckets diff --git a/deploy-config/egress_proxy/notify-admin-staging.deploy.acl b/deploy-config/egress_proxy/notify-admin-staging.deploy.acl index 4dd64b327..ee2d68acc 100644 --- a/deploy-config/egress_proxy/notify-admin-staging.deploy.acl +++ b/deploy-config/egress_proxy/notify-admin-staging.deploy.acl @@ -1 +1,3 @@ Update this file to force a re-deploy of the egress proxy even when notify-admin-staging..acl haven't changed + +20230412: Redeploy to re-calculate the list of allowed s3 buckets From 65ea2484293ea07c8522372f6737a4084fd7b5b0 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 13 Apr 2023 07:13:04 -0700 Subject: [PATCH 04/10] #446 remove crown --- app/assets/error_pages/5xx.html | 9 +-- app/main/forms.py | 17 +----- app/main/views/agreement.py | 9 +-- app/main/views/organisations.py | 32 +---------- app/models/organisation.py | 17 +----- app/navigation.py | 1 - app/notify_client/organisations_api_client.py | 3 +- app/s3_client/s3_mou_client.py | 9 ++- .../uk_components/header/_header.scss | 13 +---- .../uk_components/header/template.njk | 2 +- .../support-tickets/go-live-request.txt | 2 +- .../agreement/service-agreement-choose.html | 41 ------------- .../views/organisations/add-organisation.html | 1 - .../settings/edit-crown-status.html | 25 -------- .../organisation/settings/index.html | 16 ------ tests/__init__.py | 2 - .../views/organisations/test_organisations.py | 57 ++++--------------- .../service_settings/test_service_settings.py | 6 +- tests/app/main/views/test_agreement.py | 45 +++++---------- tests/app/main/views/test_index.py | 4 +- tests/app/models/test_user.py | 1 - tests/app/test_assets.py | 10 ---- tests/app/test_navigation.py | 1 - 23 files changed, 47 insertions(+), 276 deletions(-) delete mode 100644 app/templates/views/agreement/service-agreement-choose.html delete mode 100644 app/templates/views/organisations/organisation/settings/edit-crown-status.html diff --git a/app/assets/error_pages/5xx.html b/app/assets/error_pages/5xx.html index 4787a9393..13adac296 100644 --- a/app/assets/error_pages/5xx.html +++ b/app/assets/error_pages/5xx.html @@ -41,14 +41,14 @@ - + class="govuk-header__logotype-fallback-image" width="36" height="32"> US @@ -108,11 +108,6 @@ Government Licence v3.0, except where otherwise stated
-
diff --git a/app/main/forms.py b/app/main/forms.py index cb2d72f45..fed38965b 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1145,18 +1145,6 @@ class OrganisationOrganisationTypeForm(StripWhitespaceForm): organisation_type = OrganisationTypeField('What type of organization is this?') -class OrganisationCrownStatusForm(StripWhitespaceForm): - crown_status = GovukRadiosField( - 'Is this organization a crown body?', - choices=[ - ('crown', 'Yes'), - ('non-crown', 'No'), - ('unknown', 'Not sure'), - ], - thing='whether this organization is a crown body', - ) - - class OrganisationAgreementSignedForm(StripWhitespaceForm): agreement_signed = GovukRadiosField( 'Has this organization signed the agreement?', @@ -1209,13 +1197,10 @@ class CreateServiceForm(StripWhitespaceForm): class AdminNewOrganisationForm( RenameOrganisationForm, - OrganisationOrganisationTypeForm, - OrganisationCrownStatusForm, + OrganisationOrganisationTypeForm ): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - # Don’t offer the ‘not sure’ choice - self.crown_status.choices = self.crown_status.choices[:-1] class AdminServiceSMSAllowanceForm(StripWhitespaceForm): diff --git a/app/main/views/agreement.py b/app/main/views/agreement.py index 930185924..3dd878526 100644 --- a/app/main/views/agreement.py +++ b/app/main/views/agreement.py @@ -23,8 +23,6 @@ def service_agreement(service_id): return redirect( url_for('main.add_organisation_from_nhs_local_service', service_id=current_service.id) ) - if current_service.organisation.crown is None: - return render_template('views/agreement/service-agreement-choose.html') if current_service.organisation.agreement_signed: return render_template('views/agreement/service-agreement-signed.html') return render_template('views/agreement/service-agreement.html') @@ -34,7 +32,6 @@ def service_agreement(service_id): @user_has_permissions('manage_service') def service_download_agreement(service_id): return send_file(**get_mou( - current_service.organisation.crown_status_or_404 )) @@ -85,13 +82,13 @@ def service_confirm_agreement(service_id): @main.route('/agreement/', endpoint='public_agreement') @main.route('/agreement/.pdf', endpoint='public_download_agreement') def public_agreement(variant): - - if variant not in {'crown', 'non-crown'}: + # originally we returned 404 if variant was not in ['crown', 'not_crown']. Will we be using agreement.pdf? + # for now this is just to keep tests working as expected. + if variant != "agreement": abort(404) if request.endpoint == 'main.public_download_agreement': return send_file(**get_mou( - organisation_is_crown=(variant == 'crown') )) return render_template( diff --git a/app/main/views/organisations.py b/app/main/views/organisations.py index 82d98fc05..12eb7de98 100644 --- a/app/main/views/organisations.py +++ b/app/main/views/organisations.py @@ -23,7 +23,6 @@ from app.main.forms import ( AdminSetEmailBrandingForm, InviteOrgUserForm, OrganisationAgreementSignedForm, - OrganisationCrownStatusForm, OrganisationOrganisationTypeForm, RenameOrganisationForm, SearchByNameForm, @@ -278,35 +277,6 @@ def edit_organisation_type(org_id): ) -@main.route("/organisations//settings/edit-crown-status", methods=['GET', 'POST']) -@user_is_platform_admin -def edit_organisation_crown_status(org_id): - - form = OrganisationCrownStatusForm( - crown_status={ - True: 'crown', - False: 'non-crown', - None: 'unknown', - }.get(current_organisation.crown) - ) - - if form.validate_on_submit(): - organisations_client.update_organisation( - current_organisation.id, - crown={ - 'crown': True, - 'non-crown': False, - 'unknown': None, - }.get(form.crown_status.data), - ) - return redirect(url_for('.organisation_settings', org_id=org_id)) - - return render_template( - 'views/organisations/organisation/settings/edit-crown-status.html', - form=form, - ) - - @main.route("/organisations//settings/edit-agreement", methods=['GET', 'POST']) @user_is_platform_admin def edit_organisation_agreement(org_id): @@ -500,5 +470,5 @@ def organisation_billing(org_id): @user_is_platform_admin def organisation_download_agreement(org_id): return send_file(**get_mou( - current_organisation.crown_status_or_404 + )) diff --git a/app/models/organisation.py b/app/models/organisation.py index 0492c6897..282c1a851 100644 --- a/app/models/organisation.py +++ b/app/models/organisation.py @@ -1,6 +1,5 @@ from collections import OrderedDict -from flask import abort from werkzeug.utils import cached_property from app.models import ( @@ -29,7 +28,6 @@ class Organisation(JSONModel, SortByNameMixin): 'id', 'name', 'active', - 'crown', 'organisation_type', 'email_branding_id', 'agreement_signed', @@ -66,19 +64,13 @@ class Organisation(JSONModel, SortByNameMixin): def create_from_form(cls, form): return cls.create( name=form.name.data, - crown={ - 'crown': True, - 'non-crown': False, - 'unknown': None, - }.get(form.crown_status.data), organisation_type=form.organisation_type.data, ) @classmethod - def create(cls, name, crown, organisation_type, agreement_signed=False): + def create(cls, name, organisation_type, agreement_signed=False): return cls(organisations_client.create_organisation( name=name, - crown=crown, organisation_type=organisation_type, agreement_signed=agreement_signed, )) @@ -89,7 +81,6 @@ class Organisation(JSONModel, SortByNameMixin): if self._dict == {}: self.name = None - self.crown = None self.agreement_signed = None self.domains = [] self.organisation_type = None @@ -100,12 +91,6 @@ class Organisation(JSONModel, SortByNameMixin): def organisation_type_label(self): return self.TYPE_LABELS.get(self.organisation_type) - @property - def crown_status_or_404(self): - if self.crown is None: - abort(404) - return self.crown - @property def billing_details(self): billing_details = [ diff --git a/app/navigation.py b/app/navigation.py index 65c97deb3..44b6395d2 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -276,7 +276,6 @@ class OrgNavigation(Navigation): 'settings': { 'edit_organisation_agreement', 'edit_organisation_billing_details', - 'edit_organisation_crown_status', 'edit_organisation_domains', 'edit_organisation_email_branding', 'edit_organisation_domains', diff --git a/app/notify_client/organisations_api_client.py b/app/notify_client/organisations_api_client.py index c073ba9b2..85128dc28 100644 --- a/app/notify_client/organisations_api_client.py +++ b/app/notify_client/organisations_api_client.py @@ -37,12 +37,11 @@ class OrganisationsClient(NotifyAdminAPIClient): raise error @cache.delete('organisations') - def create_organisation(self, name, crown, organisation_type, agreement_signed): + def create_organisation(self, name, organisation_type, agreement_signed): return self.post( url="/organisations", data={ "name": name, - "crown": crown, "organisation_type": organisation_type, "agreement_signed": agreement_signed, } diff --git a/app/s3_client/s3_mou_client.py b/app/s3_client/s3_mou_client.py index b18c5c968..1aeec1cdf 100644 --- a/app/s3_client/s3_mou_client.py +++ b/app/s3_client/s3_mou_client.py @@ -4,17 +4,16 @@ from flask import current_app from app.s3_client.s3_logo_client import get_s3_object -def get_mou(organisation_is_crown): +def get_mou(): bucket = current_app.config['MOU_BUCKET_NAME'] - filename = 'crown.pdf' if organisation_is_crown else 'non-crown.pdf' - attachment_filename = 'U.S. Notify data sharing and financial agreement{}.pdf'.format( - '' if organisation_is_crown else ' (non-crown)' + filename = 'agreement.pdf' + attachment_filename = 'U.S. Notify data sharing and financial agreement.pdf'.format( ) try: key = get_s3_object(bucket, filename) return { 'path_or_file': key.get()['Body'], - 'attachment_filename': attachment_filename, + 'download_name': attachment_filename, 'as_attachment': True, } except botocore.exceptions.ClientError as exception: diff --git a/app/templates/components/uk_components/header/_header.scss b/app/templates/components/uk_components/header/_header.scss index ed1cbbb86..23f769997 100644 --- a/app/templates/components/uk_components/header/_header.scss +++ b/app/templates/components/uk_components/header/_header.scss @@ -45,13 +45,7 @@ margin-right: govuk-spacing(1); } - .govuk-header__logotype-crown { - margin-right: 1px; - fill: currentColor; - vertical-align: middle; - } - - .govuk-header__logotype-crown-fallback-image { + .govuk-header__logotype-fallback-image { width: 36px; height: 32px; border: 0; @@ -269,8 +263,7 @@ background: transparent; } - // Hide the inverted crown when printing in browsers that don't support SVG. - .govuk-header__logotype-crown-fallback-image { + .govuk-header__logotype-fallback-image { display: none; } @@ -289,7 +282,7 @@ // Begin adjustments for font baseline offset // These should be removed when the font is updated with the correct baseline - .govuk-header__logotype-crown { + .govuk-header__logotype { position: relative; top: -4px; } diff --git a/app/templates/components/uk_components/header/template.njk b/app/templates/components/uk_components/header/template.njk index 1cd625c83..c4097c5b0 100644 --- a/app/templates/components/uk_components/header/template.njk +++ b/app/templates/components/uk_components/header/template.njk @@ -5,7 +5,7 @@