diff --git a/app/__init__.py b/app/__init__.py
index d4211a033..e2852b6b3 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -12,7 +12,9 @@ from flask import (
make_response,
current_app,
request,
- g)
+ g,
+ url_for
+)
from flask._compat import string_types
from flask.globals import _lookup_req_object
from flask_login import LoginManager
@@ -112,6 +114,7 @@ def create_app():
application.add_template_filter(format_date_short)
application.add_template_filter(format_notification_status)
application.add_template_filter(format_notification_status_as_field_status)
+ application.add_template_filter(format_notification_status_as_url)
application.after_request(useful_headers_after_request)
application.after_request(save_service_after_request)
@@ -235,16 +238,16 @@ def format_notification_status(status, template_type):
'email': {
'failed': 'Failed',
'technical-failure': 'Technical failure',
- 'temporary-failure': 'Temporary failure',
- 'permanent-failure': 'Email address does not exist',
+ 'temporary-failure': 'Inbox not accepting messages right now',
+ 'permanent-failure': 'Email address doesn’t exist',
'delivered': 'Delivered',
'sending': 'Sending'
},
'sms': {
'failed': 'Failed',
'technical-failure': 'Technical failure',
- 'temporary-failure': 'Temporary failure',
- 'permanent-failure': 'Phone number does not exist',
+ 'temporary-failure': 'Phone not accepting messages right now',
+ 'permanent-failure': 'Phone number doesn’t exist',
'delivered': 'Delivered',
'sending': 'Sending'
}
@@ -262,6 +265,15 @@ def format_notification_status_as_field_status(status):
}.get(status, 'error')
+def format_notification_status_as_url(status):
+ url = partial(url_for, "main.delivery_and_failure")
+ return {
+ 'technical-failure': url(_anchor='technical-failure'),
+ 'temporary-failure': url(_anchor='not-accepting-messages'),
+ 'permanent-failure': url(_anchor='does-not-exist')
+ }.get(status)
+
+
@login_manager.user_loader
def load_user(user_id):
return user_api_client.get_user(user_id)
diff --git a/app/assets/images/cross-grey.png b/app/assets/images/cross-grey.png
new file mode 100644
index 000000000..3c665adb9
Binary files /dev/null and b/app/assets/images/cross-grey.png differ
diff --git a/app/assets/stylesheets/components/tick-cross.scss b/app/assets/stylesheets/components/tick-cross.scss
new file mode 100644
index 000000000..a44aa023c
--- /dev/null
+++ b/app/assets/stylesheets/components/tick-cross.scss
@@ -0,0 +1,46 @@
+%tick-cross {
+ @include core-16;
+ display: inline-block;
+ background-size: 19px 19px;
+ background-repeat: no-repeat;
+ background-position: 0 0;
+ padding: 1px 0 0 25px;
+}
+
+.tick-cross {
+
+ &-tick {
+ @extend %tick-cross;
+ background-image: file-url('tick.png');
+ }
+
+ &-cross {
+ @extend %tick-cross;
+ background-image: file-url('cross-grey.png');
+ color: $secondary-text-colour;
+ }
+
+ &-list {
+
+ @extend %grid-row;
+ margin-top: 5px;
+
+ &-permissions {
+
+ @include grid-column(3/4);
+
+ li {
+ display: inline-block;
+ margin-right: 0.5em;
+ }
+
+ }
+
+ &-edit-link {
+ @include grid-column(1/4);
+ text-align: right;
+ }
+
+ }
+
+}
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index b1e27910b..a6d147629 100644
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -54,11 +54,13 @@ $path: '/static/images/';
@import 'components/message';
@import 'components/phone';
@import 'components/research-mode';
+@import 'components/tick-cross';
@import 'views/job';
@import 'views/edit-template';
@import 'views/documenation';
@import 'views/dashboard';
+@import 'views/users';
// TODO: break this up
@import 'app';
diff --git a/app/assets/stylesheets/views/users.scss b/app/assets/stylesheets/views/users.scss
new file mode 100644
index 000000000..93a4631c3
--- /dev/null
+++ b/app/assets/stylesheets/views/users.scss
@@ -0,0 +1,16 @@
+.user-list {
+
+ @include core-16;
+
+ &-item {
+
+ padding: $gutter-half 0;
+ border-top: 1px solid $border-colour;
+
+ &:last-child {
+ border-bottom: 1px solid $border-colour;
+ }
+
+ }
+
+}
diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py
index 4d6e71a60..e1baa38c4 100644
--- a/app/main/views/jobs.py
+++ b/app/main/views/jobs.py
@@ -28,6 +28,7 @@ from app.utils import (
user_has_permissions,
generate_notifications_csv)
from app.statistics_utils import sum_of_statistics, statistics_by_state, add_rate_to_jobs
+from app.utils import get_help_argument
def _parse_filter_args(filter_dict):
@@ -98,7 +99,8 @@ def view_job(service_id, job_id):
job_id=job['id'],
status=request.args.get('status', '')
),
- partials=get_job_partials(job)
+ partials=get_job_partials(job),
+ help=get_help_argument()
)
@@ -311,7 +313,8 @@ def get_job_partials(job):
notifications=notification_api_client.get_notifications_for_service(
job['service'], job['id'], status=filter_args.get('status')
)['notifications'],
- status=request.args.get('status', '')
+ status=request.args.get('status', ''),
+ help=get_help_argument()
),
'status': render_template(
'partials/jobs/status.html',
diff --git a/app/main/views/send.py b/app/main/views/send.py
index faeb3acf4..07aa0eb52 100644
--- a/app/main/views/send.py
+++ b/app/main/views/send.py
@@ -29,7 +29,7 @@ from app.main.uploader import (
s3download
)
from app import job_api_client, service_api_client, current_service, user_api_client, statistics_api_client
-from app.utils import user_has_permissions, get_errors_for_csv, Spreadsheet
+from app.utils import user_has_permissions, get_errors_for_csv, Spreadsheet, get_help_argument
def get_page_headings(template_type):
@@ -181,7 +181,8 @@ def send_test(service_id, template_id):
'views/send-test.html',
template=template,
recipient_column=first_column_heading[template.template_type],
- example=[get_example_csv_rows(template, use_example_as_example=False)]
+ example=[get_example_csv_rows(template, use_example_as_example=False)],
+ help=get_help_argument()
)
@@ -278,7 +279,8 @@ def check_messages(service_id, template_type, upload_id):
upload_id=upload_id,
form=CsvUploadForm(),
statistics=statistics,
- back_link=back_link
+ back_link=back_link,
+ help=get_help_argument()
)
diff --git a/app/templates/components/tick-cross.html b/app/templates/components/tick-cross.html
new file mode 100644
index 000000000..6467b38ca
--- /dev/null
+++ b/app/templates/components/tick-cross.html
@@ -0,0 +1,15 @@
+{% macro tick_cross(yes, label) %}
+
+ {% if yes %}
+
+ Can
+ {{ label}}
+
+ {% else %}
+
+ Can’t
+ {{ label}}
+
+ {% endif %}
+
+{% endmacro %}
diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html
index f812e1977..f8fe1ba0e 100644
--- a/app/templates/main_nav.html
+++ b/app/templates/main_nav.html
@@ -1,9 +1,9 @@
{% from "components/banner.html" import banner_wrapper %}
-{% if request.args['help'] and request.args['help'] != '0' %}
+{% if help %}
{% call banner_wrapper(type='tour') %}
Try this example
-
-
-
+
@@ -31,7 +31,7 @@
Notify delivers the message
- {% if request.args['help'] == '3' %}
+ {% if help == '3' %}
Now go to your dashboard
diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html
index 0ba32b741..74971d1d8 100644
--- a/app/templates/partials/jobs/notifications.html
+++ b/app/templates/partials/jobs/notifications.html
@@ -4,7 +4,7 @@
{% endif %}
- {% if notifications %}
+ {% if notifications and not help %}
Download as a CSV file
@@ -34,7 +34,13 @@
align='right',
status=item.status|format_notification_status_as_field_status
) %}
+ {% if item.status|format_notification_status_as_url %}
+
+ {% endif %}
{{ item.status|format_notification_status(item.template.template_type) }}
+ {% if item.status|format_notification_status_as_url %}
+
+ {% endif %}
{% endcall %}
{% endcall %}
diff --git a/app/templates/views/check.html b/app/templates/views/check.html
index 9f3571dad..ab638153b 100644
--- a/app/templates/views/check.html
+++ b/app/templates/views/check.html
@@ -174,7 +174,7 @@
{% else %}
diff --git a/app/templates/views/delivery-and-failure.html b/app/templates/views/delivery-and-failure.html
index eb409e73f..e5de2bc10 100644
--- a/app/templates/views/delivery-and-failure.html
+++ b/app/templates/views/delivery-and-failure.html
@@ -16,18 +16,17 @@ Delivery and failure – GOV.UK Notify
-
Our delivery states are the same for both email and text message.
-
Sending
-
All new messages start with the state ‘Sending’.
+
All messages start in the ‘Sending’ state.
-
This means that we have accepted the message, the message is waiting in a queue to be sent to our email or text message delivery partners.
+
This means that we have accepted the message. It’s waiting in a queue to be sent to our email or text message delivery partners.
Delivered
@@ -35,23 +34,27 @@ Delivery and failure – GOV.UK Notify
We can’t tell you if they’ve read it – to do so would require invasive and unreliable tracking techniques.
-
Permanently failed
+
Phone number or email address does not exist
-
This means the email address or mobile number doesn’t exist or is blacklisted – also known as a ‘hard bounce’.
+
You’re still billed for text messages to non-existant phone numbers.
-
You’re still billed for these text messages.
+
You need to remove these email addresses or phone numbers from your database.
-
You need to remove this email address or mobile number from your database.
+
-
Temporarily failed
+
Inbox not accepting messages right now
-
This means the email address or mobile number was full, or the mobile phone was switched off – also known as a ‘soft bounce’.
+
This can happen for a number of reasons, eg the user’s inbox was full.
-
We mark messages as ‘Temporarily failed’.
+
You can choose to retry these messages later or not.
+
+
Phone not accepting messages right now
+
+
This means the user’s phone was full or hasn’t been switched on in the last 72 hours.
You’re still billed for these messages.
-
You can choose to retry this message later or not.
+
You can choose to retry these messages later or not.
Technical failure
@@ -61,7 +64,7 @@ Delivery and failure – GOV.UK Notify
You won’t be billed for these messages.
-
You need to retry this message yourself later.
+
You need to retry these messages yourself later.
diff --git a/app/templates/views/manage-users.html b/app/templates/views/manage-users.html
index 2448a4409..34dc100ab 100644
--- a/app/templates/views/manage-users.html
+++ b/app/templates/views/manage-users.html
@@ -1,6 +1,7 @@
{% extends "withnav_template.html" %}
{% from "components/table.html" import list_table, row, field, boolean_field, hidden_field_heading %}
{% from "components/page-footer.html" import page_footer %}
+{% from "components/tick-cross.html" import tick_cross %}
{% set table_options = {
'field_headings': [
@@ -29,49 +30,84 @@ Manage users – GOV.UK Notify
{% endif %}
- {% call(item, row_number) list_table(
- users, caption='Active', **table_options
- ) %}
- {% call field() %}
- {{ item.name }}
- {%- if item.email_address == current_user.email_address -%}
- (you)
- {% endif %}
- {% endcall %}
- {{ boolean_field(item.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters'])) }}
- {{ boolean_field(item.has_permissions(permissions=['manage_users', 'manage_templates', 'manage_settings'])) }}
- {{ boolean_field(item.has_permissions(permissions=['manage_api_keys'])) }}
- {% call field(align='right') %}
- {% if current_user.has_permissions(['manage_users']) %}
- {% if current_user.id != item.id %}
- Edit
- {% endif %}
- {% endif %}
- {% endcall %}
- {% endcall %}
+
+ Active
+
+
+ {% for user in users %}
+
+
+ {{ user.name }}
+ {%- if user.email_address == current_user.email_address -%}
+ (you)
+ {% else %}
+ {{ user.email_address }}
+ {% endif %}
+
+
+
+
+ {{ tick_cross(
+ user.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters']),
+ 'Send messages'
+ ) }}
+ {{ tick_cross(
+ user.has_permissions(permissions=['manage_users', 'manage_templates', 'manage_settings']),
+ 'Manage service'
+ ) }}
+ {{ tick_cross(
+ user.has_permissions(permissions=['manage_api_keys']),
+ 'Access API keys'
+ ) }}
+
+ {% if current_user.has_permissions(['manage_users']) %}
+ {% if current_user.id != user.id %}
+ -
+ Edit permissions
+
+ {% endif %}
+ {% endif %}
+
+
+ {% endfor %}
+
{% if invited_users %}
- {% call(item, row_number) list_table(
- invited_users, caption='Invited', **table_options
- ) %}
- {% call field() %}
- {{ item.email_address }}
- {% endcall %}
- {{ boolean_field(item.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters'])) }}
- {{ boolean_field(item.has_permissions(permissions=['manage_users', 'manage_templates', 'manage_settings'])) }}
- {{ boolean_field(item.has_permissions(permissions=['manage_api_keys'])) }}
- {% if item.status == 'pending' %}
- {% call field(align='right') %}
- {% if current_user.has_permissions(['manage_users']) %}
- Cancel invitation
- {% endif %}
- {% endcall %}
- {% else %}
- {% call field() %}
- {{ item.status }}
- {% endcall %}
- {% endif %}
- {% endcall %}
+
+ Invited
+
+
+ {% for user in invited_users %}
+
+
+ {{ user.email_address }}
+
+
+
+ {{ tick_cross(
+ user.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters']),
+ 'Send messages'
+ ) }}
+ {{ tick_cross(
+ user.has_permissions(permissions=['manage_users', 'manage_templates', 'manage_settings']),
+ 'Manage service'
+ ) }}
+ {{ tick_cross(
+ user.has_permissions(permissions=['manage_api_keys']),
+ 'Access API keys'
+ ) }}
+
+ -
+ {% if user.status == 'pending' and current_user.has_permissions(['manage_users']) %}
+ Cancel invitation
+ {% else %}
+ {{ user.status|title }}
+ {% endif %}
+
+
+
+ {% endfor %}
+
{% endif %}
{% endblock %}
diff --git a/app/templates/views/notifications.html b/app/templates/views/notifications.html
index 592eb3ec1..69d8ed40e 100644
--- a/app/templates/views/notifications.html
+++ b/app/templates/views/notifications.html
@@ -73,7 +73,13 @@
) }}
{% call field(status=item.status|format_notification_status_as_field_status, align='right') %}
+ {% if item.status|format_notification_status_as_url %}
+
+ {% endif %}
{{ item.status|format_notification_status(item.template.template_type) }}
+ {% if item.status|format_notification_status_as_url %}
+
+ {% endif %}
{% endcall %}
{% endcall %}
diff --git a/app/templates/views/send-test.html b/app/templates/views/send-test.html
index 980ba2a1b..d564730fc 100644
--- a/app/templates/views/send-test.html
+++ b/app/templates/views/send-test.html
@@ -55,7 +55,7 @@
{% endcall %}
{{ page_footer("Preview", back_link=(
- url_for('.choose_template', service_id=current_service.id, template_type=template.template_type)) if not request.args['help'] else None
+ url_for('.send_messages', service_id=current_service.id, template_id=template.id)) if not help else None
) }}
diff --git a/app/utils.py b/app/utils.py
index b5ab7f305..6f2c9e3ec 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -89,7 +89,7 @@ def get_errors_for_csv(recipients, template_type):
def generate_notifications_csv(json_list):
- from app import format_datetime
+ from app import format_datetime, format_notification_status
content = StringIO()
retval = None
with content as csvfile:
@@ -102,7 +102,7 @@ def generate_notifications_csv(json_list):
x['template']['name'],
x['template']['template_type'],
x['job']['original_file_name'] if x['job'] else '',
- x['status'],
+ format_notification_status(x['status'], x['template']['template_type']),
format_datetime(x['created_at'])])
retval = content.getvalue()
return retval
@@ -186,3 +186,7 @@ class Spreadsheet():
file_type=extension,
file_content=file_content.getvalue()
).to_array(), filename)
+
+
+def get_help_argument():
+ return request.args.get('help') if request.args.get('help') in ('1', '2', '3') else None
diff --git a/docs/index.md b/docs/index.md
index 6b61b15f7..23a603249 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -2,12 +2,12 @@
This document is for central government developers and technical architects who want to use the GOV.UK Notify platform to send notifications to users of their digital service.
-* [About GOV.UK Notify](#about_Notify)
-* [Before you start](#beforestart)
* [Integrate the GOV.UK Notify API into your service](#integrate_Notify)
* [Authenticate requests](#AuthRequests)
* [JSON Web Tokens: claims](#JWT_claims)
* [API client libraries](#client_libraries)
+* [Test your integration with GOV.UK Notify](#test_integ)
+ * [API keys](#API_keys)
* [API endpoints](#API_endpoints)
* [Send notifications: POST](#sendnotifications)
* [Retrieve notifications: GET](#getnotifications)
@@ -17,47 +17,14 @@ This document is for central government developers and technical architects who
-About GOV.UK Notify
-GOV.UK Notify is a cross-government platform that lets government services send notifications by text or email. It's currently in beta.
-
-There are 2 ways to send notifications:
-
-* use the [GOV.UK Notify](https://www.notifications.service.gov.uk/) web application
-* [integrate your web applications or back office systems](#integrate_Notify) with the GOV.UK Notify API
-
-The GOV.UK Notify allows you to [send notifications (POST)](#sendnotifications) and [get the status of notifications (GET)](#getnotifications) you have sent.
-
-To find out more about GOV.UK Notify, see the [Government as a Platform](https://governmentasaplatform.blog.gov.uk/) blog.
-
-Before you start
-
- 1. Register for a [GOV.UK Notify](https://www.notifications.service.gov.uk/) account.
-
- You'll need an email address from a local or central government organisation and your mobile phone for 2-factor authentication.
-
- 2. Add a template so you can send text and email notifications.
-
- **Note:** A template is required even if you send notifications with the GOV.UK Notify API.
-
- You can personalise the template using double brackets for placeholders. For example:
-
- > Dear ((name)),
- >
- > Your ((item)) is due for renewal on ((date)).
-
- 3. Create an API key. This will be used to connect to the GOV.UK Notify API.
-
- Each service can have multiple API keys. This allows you to integrate several systems, each with its own key. You can also have separate keys for your development and test environments.
-
- **Important:** API keys are secret, so save them somewhere safe. Don't commit API keys to public source code repositories.
Integrate the GOV.UK Notify API into your service
There are 2 ways to integrate the API into your service:
* use one of the client libraries provided by GOV.UK Notify:
-
+
* [Python library](https://github.com/alphagov/notifications-python-client/blob/master/README.md#usage)
* [PHP library](https://github.com/alphagov/notifications-php-client/blob/master/README.md#usage)
* [Java library](https://github.com/alphagov/notifications-java-client)
@@ -111,6 +78,57 @@ GOV.UK Notify supports the following client libraries:
These provide example code for calling the API and for creating API tokens.
+Test your integration with GOV.UK Notify
+
+Service teams should do all their testing within the GOV.UK Notify production environment (https://api.notifications.service.gov.uk).
+
+You don’t need different service accounts or environments. Instead, there are 3 types of API key that let you do functional and performance integration testing.
+
+API keys
+
+The 3 types of API key that you can create within GOV.UK Notify are:
+
+* [normal keys](#normal_keys)
+* [team keys](#team_keys)
+* [test keys](#test_keys)
+
+Type of key | Sends real messages? | Appears in activity and statistics? | Daily service limit
+--- | --- | --- | ---
+Normal key | Yes | Yes | 50 (trial), unlimited (live)
+Team key | Yes (only to team members) | Yes | 50 (trial), unlimited (live)
+Test key | No | No | Unlimited
+
+Normal keys
+
+Normal keys have the same permissions as the service:
+
+* when the service is in trial mode, you can send only to members of your team and you are restricted to 50 messages per day
+* when the service is live, you can use the key to send messages to anyone
+* three
+
+Messages sent with a normal key show up on your dashboard and count against your text message and email allowances.
+
+There is no need to generate a new key when the service moves from trial to live.
+
+Don’t use your normal key for automated testing.
+
+Team keys
+
+Use team keys for end-to-end functional testing.
+
+A team key lets you send real messages to members of your team. You get an error if you try to send messages to anyone else.
+
+Messages sent with a team key show up on your dashboard and count against your text message and email allowances.
+
+
+Test keys
+
+Use test keys to test the performance of your service and its integration with GOV.UK Notify under load.
+
+Test keys don’t send real messages but they do generate realistic responses. There’s no restriction on who you can send to or how many messages you can send per day.
+
+Messages sent using a test key don’t show up on your dashboard or count against your text message and email allowances.
+
API endpoints
You can use the GOV.UK Notify API to:
diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh
index 82274e091..c4d81cb44 100755
--- a/scripts/bootstrap.sh
+++ b/scripts/bootstrap.sh
@@ -21,7 +21,7 @@ function display_result {
}
if [ ! $VIRTUAL_ENV ]; then
- virtualenv ./venv
+ virtualenv -p python3 ./venv
. ./venv/bin/activate
fi
diff --git a/tests/__init__.py b/tests/__init__.py
index 79dfd64f1..df6d357fb 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -149,13 +149,15 @@ def job_json(service_id,
original_file_name="thisisatest.csv",
notification_count=1,
notifications_sent=1,
- status=''):
+ status=None):
if job_id is None:
job_id = str(generate_uuid())
if template_id is None:
template_id = str(generate_uuid())
if created_at is None:
created_at = str(datetime.utcnow().time())
+ if status is None:
+ status = 'Delivered'
data = {
'id': job_id,
'service': service_id,
@@ -174,16 +176,19 @@ def job_json(service_id,
return data
-def notification_json(service_id,
- job=None,
- template=None,
- to='07123456789',
- status='delivered',
- sent_at=None,
- job_row_number=None,
- created_at=None,
- updated_at=None,
- with_links=False):
+def notification_json(
+ service_id,
+ job=None,
+ template=None,
+ to='07123456789',
+ status=None,
+ sent_at=None,
+ job_row_number=None,
+ created_at=None,
+ updated_at=None,
+ with_links=False,
+ rows=5
+):
if template is None:
template = template_json(service_id, str(generate_uuid()))
if sent_at is None:
@@ -192,6 +197,8 @@ def notification_json(service_id,
created_at = str(datetime.utcnow().time())
if updated_at is None:
updated_at = str((datetime.utcnow() + timedelta(minutes=1)).time())
+ if status is None:
+ status = 'delivered'
links = {}
if with_links:
links = {
@@ -213,7 +220,7 @@ def notification_json(service_id,
'updated_at': updated_at,
'job_row_number': job_row_number,
'template_version': template['version']
- } for i in range(5)],
+ } for i in range(rows)],
'total': 5,
'page_size': 50,
'links': links
diff --git a/tests/app/main/views/test_jobs.py b/tests/app/main/views/test_jobs.py
index d6922f0a3..b7fcc6460 100644
--- a/tests/app/main/views/test_jobs.py
+++ b/tests/app/main/views/test_jobs.py
@@ -99,6 +99,34 @@ def test_should_show_page_for_one_job(
)
+def test_should_show_not_show_csv_download_in_tour(
+ app_,
+ service_one,
+ active_user_with_permissions,
+ mock_get_service_template,
+ mock_get_service_statistics,
+ mock_get_job,
+ mocker,
+ mock_get_notifications,
+ fake_uuid
+):
+ with app_.test_request_context(), app_.test_client() as client:
+ client.login(active_user_with_permissions, mocker, service_one)
+ response = client.get(url_for(
+ 'main.view_job',
+ service_id=service_one['id'],
+ job_id=fake_uuid,
+ help=3
+ ))
+
+ assert response.status_code == 200
+ assert url_for(
+ 'main.view_job_csv',
+ service_id=service_one['id'],
+ job_id=fake_uuid
+ ) not in response.get_data(as_text=True)
+
+
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_updates_for_one_job_as_json(
app_,
@@ -124,7 +152,7 @@ def test_should_show_updates_for_one_job_as_json(
assert 'Recipient' in content['notifications']
assert '07123456789' in content['notifications']
assert 'Status' in content['notifications']
- assert job_json['status'] in content['status']
+ print(content['notifications'])
assert 'Delivered' in content['notifications']
assert '11:10' in content['notifications']
assert 'Uploaded by Test User on 1 January at 11:09' in content['status']
diff --git a/tests/app/main/views/test_manage_users.py b/tests/app/main/views/test_manage_users.py
index e090d443d..767fb752e 100644
--- a/tests/app/main/views/test_manage_users.py
+++ b/tests/app/main/views/test_manage_users.py
@@ -205,10 +205,9 @@ def test_manage_users_shows_invited_user(app_,
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Team members'
- invites_table = page.find_all('table')[1]
- cols = invites_table.find_all('td')
- assert cols[0].text.strip() == 'invited_user@test.gov.uk'
- assert cols[4].text.strip() == 'Cancel invitation'
+ invited_users_list = page.find_all('div', {'class': 'user-list'})[1]
+ assert invited_users_list.find_all('h3')[0].text.strip() == 'invited_user@test.gov.uk'
+ assert invited_users_list.find_all('a')[0].text.strip() == 'Cancel invitation'
def test_manage_users_does_not_show_accepted_invite(app_,
@@ -232,8 +231,8 @@ def test_manage_users_does_not_show_accepted_invite(app_,
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Team members'
- tables = page.find_all('table')
- assert len(tables) == 1
+ user_lists = page.find_all('div', {'class': 'user-list'})
+ assert len(user_lists) == 1
assert not page.find(text='invited_user@test.gov.uk')
diff --git a/tests/app/test_utils.py b/tests/app/test_utils.py
index edb400a33..4f64a5a09 100644
--- a/tests/app/test_utils.py
+++ b/tests/app/test_utils.py
@@ -1,4 +1,8 @@
-from app.utils import email_safe
+import pytest
+from io import StringIO
+from app.utils import email_safe, generate_notifications_csv
+from csv import DictReader
+from freezegun import freeze_time
def test_email_safe_return_dot_separated_email_domain():
@@ -6,3 +10,41 @@ def test_email_safe_return_dot_separated_email_domain():
expected = 'some.service.withstuff.b123'
actual = email_safe(test_name)
assert actual == expected
+
+
+@pytest.mark.parametrize(
+ "status, template_type, expected_status",
+ [
+ ('sending', None, 'Sending'),
+ ('delivered', None, 'Delivered'),
+ ('failed', None, 'Failed'),
+ ('technical-failure', None, 'Technical failure'),
+ ('temporary-failure', 'email', 'Inbox not accepting messages right now'),
+ ('permanent-failure', 'email', 'Email address doesn’t exist'),
+ ('temporary-failure', 'sms', 'Phone not accepting messages right now'),
+ ('permanent-failure', 'sms', 'Phone number doesn’t exist')
+ ]
+)
+@freeze_time("2016-01-01 11:09:00.061258")
+def test_generate_csv_from_notifications(
+ app_,
+ service_one,
+ active_user_with_permissions,
+ mock_get_notifications,
+ status,
+ template_type,
+ expected_status
+):
+ with app_.test_request_context():
+ csv_content = generate_notifications_csv(
+ mock_get_notifications(
+ service_one['id'],
+ rows=1,
+ set_template_type=template_type,
+ set_status=status
+ )['notifications']
+ )
+
+ for row in DictReader(StringIO(csv_content)):
+ assert row['Time'] == 'Friday 01 January 2016 at 11:09'
+ assert row['Status'] == expected_status
diff --git a/tests/conftest.py b/tests/conftest.py
index f54853382..35c881a18 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -870,17 +870,36 @@ def mock_get_jobs(mocker, api_user_active):
@pytest.fixture(scope='function')
def mock_get_notifications(mocker, api_user_active):
- def _get_notifications(service_id,
- job_id=None,
- page=1,
- page_size=50,
- template_type=None,
- status=None,
- limit_days=None):
+ def _get_notifications(
+ service_id,
+ job_id=None,
+ page=1,
+ page_size=50,
+ template_type=None,
+ status=None,
+ limit_days=None,
+ rows=5,
+ set_template_type=None,
+ set_status=None
+ ):
job = None
if job_id is not None:
job = job_json(service_id, api_user_active, job_id=job_id)
- return notification_json(service_id, job=job)
+ if set_template_type:
+ return notification_json(
+ service_id,
+ template={'template_type': set_template_type, 'name': 'name', 'id': 'id', 'version': 1},
+ rows=rows,
+ status=set_status,
+ job=job
+ )
+ else:
+ return notification_json(
+ service_id,
+ rows=rows,
+ status=set_status,
+ job=job
+ )
return mocker.patch(
'app.notification_api_client.get_notifications_for_service',