Add a page to choose a contact list

You’ll be able to use a contact list by first choosing a template, then
choosing the list you want to use.

At the moment this shows all lists, not just the ones that are
compatible with your template.
This commit is contained in:
Chris Hill-Scott
2020-03-13 17:51:22 +00:00
parent aa85870ee1
commit e24083ce9d
6 changed files with 115 additions and 8 deletions

View File

@@ -42,7 +42,7 @@ from app.main.forms import (
SetSenderForm, SetSenderForm,
get_placeholder_form_instance, get_placeholder_form_instance,
) )
from app.models.contact_list import ContactList from app.models.contact_list import ContactList, ContactLists
from app.models.user import Users from app.models.user import Users
from app.s3_client.s3_csv_client import ( from app.s3_client.s3_csv_client import (
s3download, s3download,
@@ -492,6 +492,19 @@ def send_test_preview(service_id, template_id, filetype):
return TemplatePreview.from_utils_template(template, filetype, page=request.args.get('page')) return TemplatePreview.from_utils_template(template, filetype, page=request.args.get('page'))
@main.route(
'/services/<uuid:service_id>/send/<uuid:template_id>'
'/from-contact-list'
)
@user_has_permissions('send_messages')
def choose_from_contact_list(service_id, template_id):
return render_template(
'views/send-contact-list.html',
contact_lists=ContactLists(current_service.id),
template=current_service.get_template(template_id),
)
@main.route( @main.route(
'/services/<uuid:service_id>/send/<uuid:template_id>' '/services/<uuid:service_id>/send/<uuid:template_id>'
'/from-contact-list/<uuid:contact_list_id>' '/from-contact-list/<uuid:contact_list_id>'

View File

@@ -3,7 +3,7 @@ from notifications_utils.formatters import strip_whitespace
from notifications_utils.recipients import RecipientCSV from notifications_utils.recipients import RecipientCSV
from werkzeug.utils import cached_property from werkzeug.utils import cached_property
from app.models import JSONModel from app.models import JSONModel, ModelList
from app.notify_client.contact_list_api_client import contact_list_api_client from app.notify_client.contact_list_api_client import contact_list_api_client
from app.s3_client.s3_csv_client import ( from app.s3_client.s3_csv_client import (
get_csv_metadata, get_csv_metadata,
@@ -28,9 +28,9 @@ class ContactList(JSONModel):
@classmethod @classmethod
def from_id(cls, contact_list_id, *, service_id): def from_id(cls, contact_list_id, *, service_id):
# This is temporary until we have a get single list endpoint # This is temporary until we have a get single list endpoint
for contact_list in contact_list_api_client.get_contact_lists(service_id): for contact_list in ContactLists(service_id):
if contact_list['id'] == contact_list_id: if contact_list.id == contact_list_id:
return cls(contact_list) return contact_list
abort(404) abort(404)
@staticmethod @staticmethod
@@ -77,7 +77,7 @@ class ContactList(JSONModel):
metadata = ContactList.get_metadata(service_id, upload_id) metadata = ContactList.get_metadata(service_id, upload_id)
new_upload_id = s3upload( new_upload_id = s3upload(
service_id, service_id,
contents, {'data': contents},
current_app.config['AWS_REGION'], current_app.config['AWS_REGION'],
) )
set_metadata_on_csv_upload( set_metadata_on_csv_upload(
@@ -111,3 +111,8 @@ class ContactList(JSONModel):
international_sms=True, international_sms=True,
max_initial_rows_shown=50, max_initial_rows_shown=50,
) )
class ContactLists(ModelList):
client_method = contact_list_api_client.get_contact_lists
model = ContactList

View File

@@ -149,6 +149,7 @@ class HeaderNavigation(Navigation):
'check_notification', 'check_notification',
'no_cookie.check_notification_preview', 'no_cookie.check_notification_preview',
'choose_account', 'choose_account',
'choose_from_contact_list',
'choose_service', 'choose_service',
'choose_template', 'choose_template',
'choose_template_to_copy', 'choose_template_to_copy',
@@ -368,6 +369,7 @@ class MainNavigation(Navigation):
'add_service_template', 'add_service_template',
'check_messages', 'check_messages',
'check_notification', 'check_notification',
'choose_from_contact_list',
'choose_template', 'choose_template',
'choose_template_to_copy', 'choose_template_to_copy',
'confirm_redact_template', 'confirm_redact_template',
@@ -658,6 +660,7 @@ class CaseworkNavigation(Navigation):
mapping = { mapping = {
'send-one-off': { 'send-one-off': {
'choose_from_contact_list',
'choose_template', 'choose_template',
'send_one_off', 'send_one_off',
'send_one_off_step', 'send_one_off_step',
@@ -1018,6 +1021,7 @@ class OrgNavigation(Navigation):
'check_notification', 'check_notification',
'no_cookie.check_notification_preview', 'no_cookie.check_notification_preview',
'choose_account', 'choose_account',
'choose_from_contact_list',
'choose_service', 'choose_service',
'choose_template', 'choose_template',
'choose_template_to_copy', 'choose_template_to_copy',

View File

@@ -0,0 +1,53 @@
{% extends "withnav_template.html" %}
{% from "components/big-number.html" import big_number -%}
{% from "components/message-count-label.html" import recipient_count_label %}
{% from "components/page-header.html" import page_header %}
{% from "components/table.html" import list_table, field, right_aligned_field_heading, row_heading %}
{% block service_page_title %}
Choose a saved contact list
{% endblock %}
{% block maincolumn_content %}
{{ page_header(
'Choose a saved contact list',
back_link=url_for('.send_one_off', service_id=current_service.id, template_id=template.id)
) }}
<div class='dashboard-table ajax-block-container'>
{% call(item, row_number) list_table(
contact_lists,
caption="Existing contact lists",
caption_visible=False,
empty_message=(
'You dont have any contact lists yet'
),
field_headings=[
'File',
'Status'
],
field_headings_visible=False
) %}
{% call row_heading() %}
<div class="file-list">
<a class="file-list-filename-large govuk-link govuk-link--no-visited-state" href="{{ url_for('main.send_from_contact_list', service_id=current_service.id, template_id=template.id, contact_list_id=item.id) }}">{{ item.original_file_name }}</a>
<span class="file-list-hint">
Uploaded {{ item.created_at|format_datetime_relative }}
</span>
</div>
{% endcall %}
{% call field() %}
{{ big_number(
item.row_count,
smallest=True,
label=recipient_count_label(
item.row_count,
item.template_type
)
) }}
{% endcall %}
{% endcall %}
</div>
{% endblock %}

View File

@@ -13,6 +13,7 @@ from zipfile import BadZipFile
import pytest import pytest
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from flask import url_for from flask import url_for
from freezegun import freeze_time
from notifications_python_client.errors import HTTPError from notifications_python_client.errors import HTTPError
from notifications_utils.recipients import RecipientCSV from notifications_utils.recipients import RecipientCSV
from notifications_utils.template import ( from notifications_utils.template import (
@@ -3783,6 +3784,37 @@ def test_redirects_to_template_if_job_exists_already(
) )
@freeze_time('2020-03-13 13:00')
def test_choose_from_contact_list(
mocker,
client_request,
mock_get_service_template,
mock_get_contact_lists,
fake_uuid,
):
page = client_request.get(
'main.choose_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert len(page.select('.file-list-filename-large')) == 2
assert normalize_spaces(page.select_one('.file-list-filename-large').text) == (
'EmergencyContactList.xls'
)
assert page.select_one('a.file-list-filename-large')['href'] == url_for(
'main.send_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
contact_list_id=fake_uuid,
)
assert normalize_spaces(page.select_one('.file-list-hint').text) == (
'Uploaded today at 10:59am'
)
assert normalize_spaces(page.select_one('.big-number-smallest').text) == (
'100 email addresses'
)
def test_send_from_contact_list( def test_send_from_contact_list(
mocker, mocker,
client_request, client_request,
@@ -3816,7 +3848,7 @@ def test_send_from_contact_list(
SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list' SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list'
) )
mock_upload.assert_called_once_with( mock_upload.assert_called_once_with(
SERVICE_ONE_ID, 'contents', ANY SERVICE_ONE_ID, {'data': 'contents'}, ANY
) )
mock_set_metadata.assert_called_once_with( mock_set_metadata.assert_called_once_with(
SERVICE_ONE_ID, new_uuid, example_key='example value' SERVICE_ONE_ID, new_uuid, example_key='example value'

View File

@@ -1864,7 +1864,7 @@ def mock_get_contact_lists(mocker, api_user_active, fake_uuid):
}] }]
return mocker.patch( return mocker.patch(
'app.contact_list_api_client.get_contact_lists', 'app.models.contact_list.ContactLists.client_method',
side_effect=_get, side_effect=_get,
) )