Files
notifications-admin/app/models/contact_list.py
Chris Hill-Scott 06108de0f7 Allow international addresses in spreadsheets
For services with permission, they can now put international addresses
into their spreadsheets without getting a postcode error.

This also means they can start using address line 7 instead of postcode,
since it doesn’t make sense to put a country in a field called
‘postcode’. But this will be undocumented to start with, because we’re
not giving any real users the permission.

It does now mean that the number of possible placeholders (7 + postcode)
is greater than the number of allowed placeholders (7), so we have to
account for that in the one-off address flow where we’re populating the
placeholders automatically. We’re sticking with 6 + postcode here for
backwards compatibility.
2020-04-29 16:19:57 +01:00

158 lines
4.1 KiB
Python

from functools import partial
from os import path
from flask import abort, current_app
from notifications_utils.formatters import strip_whitespace
from notifications_utils.recipients import RecipientCSV
from werkzeug.utils import cached_property
from app.models import JSONModel, ModelList
from app.notify_client.contact_list_api_client import contact_list_api_client
from app.s3_client.s3_csv_client import (
get_csv_metadata,
s3download,
s3upload,
set_metadata_on_csv_upload,
)
from app.utils import get_sample_template
class ContactList(JSONModel):
ALLOWED_PROPERTIES = {
'id',
'created_at',
'created_by',
'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_name():
return current_app.config['CONTACT_LIST_UPLOAD_BUCKET_NAME']
@staticmethod
def upload(service_id, file_dict):
return s3upload(
service_id,
file_dict,
current_app.config['AWS_REGION'],
bucket=ContactList.get_bucket_name(),
)
@staticmethod
def download(service_id, upload_id):
return strip_whitespace(s3download(
service_id,
upload_id,
bucket=ContactList.get_bucket_name(),
))
@staticmethod
def set_metadata(service_id, upload_id, **kwargs):
return set_metadata_on_csv_upload(
service_id,
upload_id,
bucket=ContactList.get_bucket_name(),
**kwargs,
)
@staticmethod
def get_metadata(service_id, upload_id):
return get_csv_metadata(
service_id,
upload_id,
bucket=ContactList.get_bucket_name(),
)
def copy_to_uploads(self):
metadata = self.get_metadata(self.service_id, self.id)
new_upload_id = s3upload(
self.service_id,
{'data': self.contents},
current_app.config['AWS_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'
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(),
)