diff --git a/.github/actions/deploy-proxy/action.yml b/.github/actions/deploy-proxy/action.yml
index ff9d1cbe8..13bdc494f 100644
--- a/.github/actions/deploy-proxy/action.yml
+++ b/.github/actions/deploy-proxy/action.yml
@@ -36,7 +36,7 @@ runs:
- name: Copy config files
shell: bash
run: cp ./deploy-config/egress_proxy/${{ inputs.app }}.*.acl ${{ steps.create-temp-dir.outputs.path }}
- - name: Build and deploy proxy
+ - name: Deploy proxy
shell: bash
working-directory: ${{ steps.create-temp-dir.outputs.path }}
- run: make && ./bin/cf-deployproxy -a ${{ inputs.app }} -p egress-proxy -e egress_proxy
+ run: ./bin/cf-deployproxy -a ${{ inputs.app }} -p egress-proxy -e egress_proxy
diff --git a/app/__init__.py b/app/__init__.py
index 062f5b892..d2232343a 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
@@ -155,35 +154,27 @@ def _csp(config):
"'self'",
asset_domain
],
+ "frame-ancestors": "'none'",
+ "form-action": "'self'",
"script-src": [
"'self'",
- "'unsafe-eval'",
asset_domain,
- "*.google-analytics.com",
+ "'unsafe-eval'",
"https://js-agent.newrelic.com",
- "https://*.nr-data.net",
- "data:"
+ "https://gov-bam.nr-data.net",
],
"connect-src": [
"'self'",
- "*.google-analytics.com",
- "https://*.nr-data.net"
+ "https://gov-bam.nr-data.net"
],
"style-src": [
"'self'",
asset_domain
],
- "font-src": [
- "'self'",
- asset_domain,
- "data:"
- ],
"img-src": [
"'self'",
asset_domain,
- logo_domain,
- "*.google-analytics.com",
- "data:"
+ logo_domain
]
}
@@ -216,7 +207,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,
@@ -247,6 +237,22 @@ def create_app(application):
application,
content_security_policy=_csp(application.config),
content_security_policy_nonce_in=['style-src', 'script-src'],
+ permissions_policy={
+ 'accelerometer': '()',
+ 'ambient-light-sensor': '()',
+ 'autoplay': '()',
+ 'battery': '()',
+ 'camera': '()',
+ 'document-domain': '()',
+ 'geolocation': '()',
+ 'gyroscope': '()',
+ 'local-fonts': '()',
+ 'magnetometer': '()',
+ 'microphone': '()',
+ 'midi': '()',
+ 'payment': '()',
+ 'screen-wake-lock': '()'
+ },
frame_options='deny',
force_https=(application.config['HTTP_PROTOCOL'] == 'https')
)
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 @@
, except where otherwise stated
-
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/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..13c3a93a5 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')
@@ -33,9 +31,7 @@ def service_agreement(service_id):
@main.route('/services//agreement.pdf')
@user_has_permissions('manage_service')
def service_download_agreement(service_id):
- return send_file(**get_mou(
- current_service.organisation.crown_status_or_404
- ))
+ return send_file(**get_mou())
@main.route('/services//agreement/accept', methods=['GET', 'POST'])
@@ -85,14 +81,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 send_file(**get_mou())
return render_template(
'views/agreement/agreement-public.html',
diff --git a/app/main/views/organisations.py b/app/main/views/organisations.py
index 82d98fc05..3c059fb22 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):
@@ -499,6 +469,4 @@ def organisation_billing(org_id):
@main.route('/organisations//agreement.pdf')
@user_is_platform_admin
def organisation_download_agreement(org_id):
- return send_file(**get_mou(
- current_organisation.crown_status_or_404
- ))
+ return send_file(**get_mou())
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/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/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..ef29424f4 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',
},
}
@@ -276,7 +264,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/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/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..108d23758 100644
--- a/app/s3_client/s3_mou_client.py
+++ b/app/s3_client/s3_mou_client.py
@@ -4,17 +4,15 @@ 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'
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..20ffec2a5 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,8 @@
background: transparent;
}
- // Hide the inverted crown when printing in browsers that don't support SVG.
- .govuk-header__logotype-crown-fallback-image {
+ // Hide the inverted logo when printing in browsers that don't support SVG.
+ .govuk-header__logotype-fallback-image {
display: none;
}
@@ -289,7 +283,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 @@