mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 10:28:41 -04:00
Merge branch 'master' into enable-download-link
This commit is contained in:
@@ -52,7 +52,8 @@
|
||||
'height': this.nativeHeight,
|
||||
'top': this.topOffset
|
||||
})
|
||||
);
|
||||
)
|
||||
.css('position', 'absolute');
|
||||
|
||||
this.$scrollableTable = this.$component.find('.fullscreen-scrollable-table');
|
||||
this.$fixedTable = this.$component.find('.fullscreen-fixed-table');
|
||||
@@ -100,6 +101,11 @@
|
||||
this.$scrollableTable.scrollLeft() < (this.$table.width() - this.$scrollableTable.width())
|
||||
);
|
||||
|
||||
setTimeout(
|
||||
() => this.$component.find('.fullscreen-right-shadow').addClass('with-transition'),
|
||||
3000
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
z-index: 10;
|
||||
overflow-y: hidden;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
margin: 5px 0 $gutter 0;
|
||||
margin: 0 0 $gutter 0;
|
||||
padding: 0 0 0 0;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid $border-colour;
|
||||
@@ -42,8 +41,13 @@
|
||||
z-index: 200;
|
||||
|
||||
&.visible {
|
||||
transition: box-shadow 0.3s ease-in-out;
|
||||
|
||||
&.with-transition {
|
||||
transition: box-shadow 0.6s ease-out;
|
||||
}
|
||||
|
||||
box-shadow: inset -1px 0 0 0 $border-colour, inset -3px 0 0 0 rgba($border-colour, 0.2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.radio-select {
|
||||
|
||||
min-height: 39px;
|
||||
|
||||
&-column {
|
||||
|
||||
display: inline-block;
|
||||
|
||||
@@ -129,8 +129,31 @@
|
||||
}
|
||||
|
||||
&-index {
|
||||
|
||||
@include bold-16;
|
||||
width: 15px;
|
||||
|
||||
a {
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
|
||||
&:before {
|
||||
background: $yellow;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
|
||||
+3
-9
@@ -534,15 +534,9 @@ class RequestToGoLiveForm(StripWhitespaceForm):
|
||||
'Will the number of messages increase and when will that start?',
|
||||
validators=[DataRequired(message='Can’t be empty')]
|
||||
)
|
||||
upload_or_api = RadioField(
|
||||
'How are you going to send messages?',
|
||||
choices=[
|
||||
('File upload', 'Upload a spreadsheet of recipients'),
|
||||
('API', 'Integrate with the GOV.UK Notify API'),
|
||||
('API and file upload', 'Both')
|
||||
],
|
||||
validators=[DataRequired()]
|
||||
)
|
||||
method_one_off = BooleanField('One at a time')
|
||||
method_upload = BooleanField('Upload a spreadsheet of recipients')
|
||||
method_api = BooleanField('Integrate with the GOV.UK Notify API')
|
||||
|
||||
|
||||
class ProviderForm(StripWhitespaceForm):
|
||||
|
||||
@@ -20,17 +20,10 @@ from app.main.forms import (
|
||||
PermissionsForm
|
||||
)
|
||||
from app import (user_api_client, current_service, service_api_client, invite_api_client)
|
||||
from app.notify_client.models import roles
|
||||
from app.utils import user_has_permissions
|
||||
|
||||
|
||||
roles = {
|
||||
'send_messages': ['send_texts', 'send_emails', 'send_letters'],
|
||||
'manage_templates': ['manage_templates'],
|
||||
'manage_service': ['manage_users', 'manage_settings'],
|
||||
'manage_api_keys': ['manage_api_keys']
|
||||
}
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/users")
|
||||
@login_required
|
||||
@user_has_permissions('view_activity', admin_override=True)
|
||||
@@ -92,10 +85,9 @@ def edit_user_permissions(service_id, user_id):
|
||||
user_has_no_mobile_number = user.mobile_number is None
|
||||
|
||||
form = PermissionsForm(
|
||||
**{role: user.has_permissions(permissions=permissions) for role, permissions in roles.items()},
|
||||
**{role: user.has_permissions(*permissions) for role, permissions in roles.items()},
|
||||
login_authentication=user.auth_type
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
user_api_client.set_user_permissions(
|
||||
user_id, service_id,
|
||||
@@ -122,7 +114,7 @@ def remove_user_from_service(service_id, user_id):
|
||||
# Need to make the email address read only, or a disabled field?
|
||||
# Do it through the template or the form class?
|
||||
form = PermissionsForm(**{
|
||||
role: user.has_permissions(permissions=permissions) for role, permissions in roles.items()
|
||||
role: user.has_permissions(*permissions) for role, permissions in roles.items()
|
||||
})
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
+10
-6
@@ -523,9 +523,12 @@ def _check_messages(service_id, template_type, upload_id, preview_row, letters_a
|
||||
|
||||
count_of_recipients = len(list(recipients.rows))
|
||||
|
||||
if preview_row < count_of_recipients:
|
||||
template.values = recipients[preview_row]
|
||||
elif preview_row > 0:
|
||||
if preview_row < 2:
|
||||
abort(404)
|
||||
|
||||
if preview_row < count_of_recipients + 2:
|
||||
template.values = recipients[preview_row - 2]
|
||||
elif preview_row > 2:
|
||||
abort(404)
|
||||
|
||||
session['upload_data']['notification_count'] = count_of_recipients
|
||||
@@ -553,7 +556,8 @@ def _check_messages(service_id, template_type, upload_id, preview_row, letters_a
|
||||
template.template_type == 'letter',
|
||||
not request.args.get('from_test'),
|
||||
)),
|
||||
required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns
|
||||
required_recipient_columns=OrderedSet(recipients.recipient_column_headers) - optional_address_columns,
|
||||
preview_row=preview_row,
|
||||
)
|
||||
|
||||
|
||||
@@ -561,7 +565,7 @@ def _check_messages(service_id, template_type, upload_id, preview_row, letters_a
|
||||
@main.route("/services/<service_id>/<template_type>/check/<upload_id>/row-<int:row_index>", methods=['GET'])
|
||||
@login_required
|
||||
@user_has_permissions('send_texts', 'send_emails', 'send_letters')
|
||||
def check_messages(service_id, template_type, upload_id, row_index=0):
|
||||
def check_messages(service_id, template_type, upload_id, row_index=2):
|
||||
|
||||
data = _check_messages(service_id, template_type, upload_id, row_index)
|
||||
|
||||
@@ -589,7 +593,7 @@ def check_messages(service_id, template_type, upload_id, row_index=0):
|
||||
@main.route("/services/<service_id>/<template_type>/check/<upload_id>/row-<int:row_index>.<filetype>", methods=['GET'])
|
||||
@login_required
|
||||
@user_has_permissions('send_texts', 'send_emails', 'send_letters')
|
||||
def check_messages_preview(service_id, template_type, upload_id, filetype, row_index=0):
|
||||
def check_messages_preview(service_id, template_type, upload_id, filetype, row_index=2):
|
||||
if filetype not in ('pdf', 'png'):
|
||||
abort(404)
|
||||
|
||||
|
||||
@@ -153,7 +153,6 @@ def service_request_to_go_live(service_id):
|
||||
form = RequestToGoLiveForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
|
||||
data = {
|
||||
'person_email': current_user.email_address,
|
||||
'person_name': current_user.name,
|
||||
@@ -161,13 +160,17 @@ def service_request_to_go_live(service_id):
|
||||
'agent_team_id': current_app.config.get('DESKPRO_ASSIGNED_AGENT_TEAM_ID'),
|
||||
'subject': 'Request to go live - {}'.format(current_service['name']),
|
||||
'message': (
|
||||
'On behalf of {} ({})\n\nExpected usage\n---'
|
||||
'On behalf of {} ({})\n'
|
||||
'\n---'
|
||||
'\nOrganisation type: {}'
|
||||
'\nMOU in place: {}'
|
||||
'\nChannel: {}\nStart date: {}\nStart volume: {}'
|
||||
'\nPeak volume: {}\nUpload or API: {}'
|
||||
'\nPeak volume: {}'
|
||||
'\nFeatures: {}'
|
||||
).format(
|
||||
current_service['name'],
|
||||
url_for('main.service_dashboard', service_id=current_service['id'], _external=True),
|
||||
current_service['organisation_type'],
|
||||
form.mou.data,
|
||||
formatted_list(filter(None, (
|
||||
'email' if form.channel_email.data else None,
|
||||
@@ -177,7 +180,11 @@ def service_request_to_go_live(service_id):
|
||||
form.start_date.data,
|
||||
form.start_volume.data,
|
||||
form.peak_volume.data,
|
||||
form.upload_or_api.data
|
||||
formatted_list(filter(None, (
|
||||
'one off' if form.method_one_off.data else None,
|
||||
'file upload' if form.method_upload.data else None,
|
||||
'API' if form.method_api.data else None,
|
||||
)), before_each='', after_each='')
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ def add_service_template(service_id, template_type):
|
||||
|
||||
|
||||
def abort_403_if_not_admin_user():
|
||||
if not current_user.has_permissions([], admin_override=True):
|
||||
if not current_user.has_permissions(admin_override=True):
|
||||
abort(403)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
from itertools import chain
|
||||
from flask_login import UserMixin, AnonymousUserMixin
|
||||
from flask import session
|
||||
|
||||
|
||||
roles = {
|
||||
'send_messages': ['send_texts', 'send_emails', 'send_letters'],
|
||||
'manage_templates': ['manage_templates'],
|
||||
'manage_service': ['manage_users', 'manage_settings'],
|
||||
'manage_api_keys': ['manage_api_keys']
|
||||
}
|
||||
|
||||
all_permissions = set(chain.from_iterable(roles.values())) | {'view_activity'}
|
||||
|
||||
|
||||
class User(UserMixin):
|
||||
def __init__(self, fields, max_failed_login_count=3):
|
||||
self._id = fields.get('id')
|
||||
@@ -91,7 +102,13 @@ class User(UserMixin):
|
||||
def permissions(self, permissions):
|
||||
raise AttributeError("Read only property")
|
||||
|
||||
def has_permissions(self, permissions=[], any_=False, admin_override=False):
|
||||
def has_permissions(self, *permissions, any_=False, admin_override=False):
|
||||
|
||||
unknown_permissions = set(permissions) - all_permissions
|
||||
|
||||
if unknown_permissions:
|
||||
raise TypeError('{} are not valid permissions'.format(unknown_permissions))
|
||||
|
||||
# Only available to the platform admin user
|
||||
if admin_override and self.platform_admin:
|
||||
return True
|
||||
@@ -166,7 +183,7 @@ class InvitedUser(object):
|
||||
self.created_at = created_at
|
||||
self.auth_type = auth_type
|
||||
|
||||
def has_permissions(self, permissions):
|
||||
def has_permissions(self, *permissions):
|
||||
return set(self.permissions) > set(permissions)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
||||
@@ -44,17 +44,17 @@
|
||||
<nav class="navigation">
|
||||
<ul>
|
||||
<li><a href="{{ url_for('.service_dashboard', service_id=current_service.id) }}">Dashboard</a></li>
|
||||
{% if current_user.has_permissions(['view_activity', 'manage_templates', 'manage_api_keys'], admin_override=True, any_=True) %}
|
||||
{% if current_user.has_permissions('view_activity', 'manage_templates', 'manage_api_keys', admin_override=True, any_=True) %}
|
||||
<li><a href="{{ url_for('.choose_template', service_id=current_service.id) }}">Templates</a></li>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['manage_users', 'manage_settings'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_users', 'manage_settings', admin_override=True) %}
|
||||
<li><a href="{{ url_for('.manage_users', service_id=current_service.id) }}">Team members</a></li>
|
||||
<li><a href="{{ url_for('.usage', service_id=current_service.id) }}">Usage</a></li>
|
||||
<li><a href="{{ url_for('.service_settings', service_id=current_service.id) }}">Settings</a></li>
|
||||
{% elif current_user.has_permissions(['view_activity']) %}
|
||||
{% elif current_user.has_permissions('view_activity') %}
|
||||
<li><a href="{{ url_for('.manage_users', service_id=current_service.id) }}">Team members</a></li>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(['manage_api_keys'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_api_keys', admin_override=True) %}
|
||||
<li><a href="{{ url_for('.api_integration', service_id=current_service.id) }}">API integration</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
@@ -30,4 +30,8 @@
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
</div>
|
||||
{{ page_footer(
|
||||
secondary_link=url_for('.api_integration', service_id=current_service.id),
|
||||
secondary_link_text='Back to API integration'
|
||||
) }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -59,8 +59,12 @@
|
||||
] + recipients.column_headers
|
||||
) %}
|
||||
{% call index_field() %}
|
||||
<span class="{% if item.index in recipients.rows_with_errors %}table-field-error{% endif %}">
|
||||
{{ item.index + 2 }}
|
||||
<span>
|
||||
{% if (item.index + 2) == preview_row %}
|
||||
{{ item.index + 2 }}
|
||||
{% else %}
|
||||
<a href="{{ url_for('.check_messages', service_id=current_service.id, template_type=template.template_type, upload_id=upload_id, row_index=(item.index + 2)) }}">{{ item.index + 2 }}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endcall %}
|
||||
{% for column in recipients.column_headers %}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
'messages',
|
||||
) }}
|
||||
|
||||
{% if current_user.has_permissions(['send_texts'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('send_texts', admin_override=True) %}
|
||||
<p class="sms-message-reply-link">
|
||||
<a href="{{ url_for('.conversation_reply', service_id=current_service.id, notification_id=notification_id) }}">Send a text message to this phone number</a>
|
||||
</p>
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
<div class="dashboard">
|
||||
|
||||
<h1 class="visuallyhidden">Dashboard</h1>
|
||||
{% if current_user.has_permissions(['manage_templates'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_templates', admin_override=True) %}
|
||||
{% if not templates %}
|
||||
{% include 'views/dashboard/write-first-messages.html' %}
|
||||
{% endif %}
|
||||
{% elif not current_user.has_permissions(['send_texts', 'send_emails', 'send_letters', 'manage_api_keys'], any_=True) %}
|
||||
{% elif not current_user.has_permissions('send_texts', 'send_emails', 'send_letters', 'manage_api_keys', any_=True) %}
|
||||
{% include 'views/dashboard/no-permissions-banner.html' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this', rows=10) }}
|
||||
{{ textbox(form.subject, width='1-1', highlight_tags=True, rows=2) }}
|
||||
{{ textbox(form.template_content, highlight_tags=True, width='1-1', rows=8) }}
|
||||
{% if current_user.has_permissions([], admin_override=True) %}
|
||||
{% if current_user.has_permissions(admin_override=True) %}
|
||||
{{ radios(form.process_type) }}
|
||||
{% endif %}
|
||||
{{ page_footer(
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div class="column-two-thirds">
|
||||
{{ textbox(form.template_content, highlight_tags=True, width='1-1', rows=5) }}
|
||||
{% if current_user.has_permissions([], admin_override=True) %}
|
||||
{% if current_user.has_permissions(admin_override=True) %}
|
||||
{{ radios(form.process_type) }}
|
||||
{% endif %}
|
||||
{{ page_footer(
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
Team members
|
||||
</h1>
|
||||
</div>
|
||||
{% if current_user.has_permissions(['manage_users'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_users', admin_override=True) %}
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.invite_user', service_id=current_service.id) }}" class="button align-with-heading">Invite team member</a>
|
||||
</div>
|
||||
@@ -48,19 +48,19 @@
|
||||
<ul class="tick-cross-list">
|
||||
<div class="tick-cross-list-permissions">
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters']),
|
||||
user.has_permissions('send_texts', 'send_emails', 'send_letters'),
|
||||
'Send messages'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_templates']),
|
||||
user.has_permissions('manage_templates'),
|
||||
'Add and edit templates'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_users', 'manage_settings']),
|
||||
user.has_permissions('manage_users', 'manage_settings'),
|
||||
'Manage service'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_api_keys']),
|
||||
user.has_permissions('manage_api_keys'),
|
||||
'Access API keys'
|
||||
) }}
|
||||
{% if 'email_auth' in current_service['permissions'] %}
|
||||
@@ -73,7 +73,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if current_user.has_permissions(['manage_users'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_users', admin_override=True) %}
|
||||
{% if current_user.id != user.id %}
|
||||
<li class="tick-cross-list-edit-link">
|
||||
<a href="{{ url_for('.edit_user_permissions', service_id=current_service.id, user_id=user.id)}}">Edit permissions</a>
|
||||
@@ -98,19 +98,19 @@
|
||||
<ul class="tick-cross-list">
|
||||
<div class="tick-cross-list-permissions">
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters']),
|
||||
user.has_permissions('send_texts', 'send_emails', 'send_letters'),
|
||||
'Send messages'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_templates']),
|
||||
user.has_permissions('manage_templates'),
|
||||
'Add and edit templates'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_users', 'manage_settings']),
|
||||
user.has_permissions('manage_users', 'manage_settings'),
|
||||
'Manage service'
|
||||
) }}
|
||||
{{ tick_cross(
|
||||
user.has_permissions(permissions=['manage_api_keys']),
|
||||
user.has_permissions('manage_api_keys'),
|
||||
'Access API keys'
|
||||
) }}
|
||||
{% if 'email_auth' in current_service['permissions'] %}
|
||||
@@ -124,7 +124,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<li class="tick-cross-list-edit-link">
|
||||
{% if user.status == 'pending' and current_user.has_permissions(['manage_users']) %}
|
||||
{% if user.status == 'pending' and current_user.has_permissions('manage_users') %}
|
||||
<a href="{{ url_for('.cancel_invited_user', service_id=current_service.id, invited_user_id=user.id)}}">Cancel invitation</a>
|
||||
{% else %}
|
||||
{{ user.status|title }}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{{ ajax_block(partials, updates_url, 'status', finished=finished) }}
|
||||
{% endif %}
|
||||
|
||||
{% if current_user.has_permissions(['send_texts'], admin_override=True) and template.template_type == 'sms' and can_receive_inbound %}
|
||||
{% if current_user.has_permissions('send_texts', admin_override=True) and template.template_type == 'sms' and can_receive_inbound %}
|
||||
<p>
|
||||
<a href="{{ url_for('.conversation', service_id=current_service.id, notification_id=notification_id, _anchor='n{}'.format(notification_id)) }}">See all text messages sent to this phone number</a>
|
||||
</p>
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if current_user.has_permissions([], admin_override=True) %}
|
||||
{% if current_user.has_permissions(admin_override=True) %}
|
||||
|
||||
<h2 class="heading-medium">Platform admin settings</h2>
|
||||
|
||||
|
||||
@@ -23,12 +23,8 @@
|
||||
specified your reply to email address or text message sender in your
|
||||
<a href="{{ url_for('main.service_settings', service_id=current_service.id) }}">settings</a> page</li>
|
||||
<li>
|
||||
added the templates you want to start with, making sure they follow our
|
||||
<a href="https://www.gov.uk/service-manual/design/using-adapting-and-creating-patterns" rel="external">design patterns</a>,
|
||||
<a href="https://www.gov.uk/guidance/style-guide" rel="external">style guide</a>
|
||||
and
|
||||
<a href="https://www.gov.uk/service-manual/technology/securing-your-information" rel="external">information security guidelines</a>
|
||||
</li>
|
||||
added the templates you want to start with, making sure they follow the GOV.UK Service Manual standards for
|
||||
<a href="https://www.gov.uk/service-manual/design/sending-emails-and-text-messages">writing text messages and emails</a></li>
|
||||
</ul>
|
||||
|
||||
<form method="post">
|
||||
@@ -48,9 +44,12 @@
|
||||
{{ textbox(form.start_date, width='1-1') }}
|
||||
{{ textbox(form.start_volume, width='1-1', hint='For example, ‘1000 a month’.') }}
|
||||
{{ textbox(form.peak_volume, width='1-1', hint='For example, ‘Messages will increase to 20,000 a month in January’.') }}
|
||||
{{ radios(form.upload_or_api) }}
|
||||
</div>
|
||||
|
||||
{{ checkbox_group('How are you going to send messages?', [
|
||||
form.method_one_off,
|
||||
form.method_upload,
|
||||
form.method_api
|
||||
]) }}
|
||||
<p>
|
||||
Once you’ve completed the tasks needed to set up, we’ll make your service live. We’ll do this within one working day.
|
||||
</p>
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
If you want to turn this feature off,
|
||||
<a href="{{ url_for('.support') }}">get in touch with the GOV.UK Notify team</a>.
|
||||
</p>
|
||||
{% if current_user.has_permissions('manage_api_keys', admin_override=True) %}
|
||||
<p>
|
||||
You can set up callbacks for received text messages on the
|
||||
<a href="{{ url_for('.api_callbacks', service_id=current_service.id) }}">API integration page</a>.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>
|
||||
Receiving text messages from your users is an
|
||||
|
||||
@@ -120,12 +120,12 @@
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-half">
|
||||
<h3 class="visually-hidden">Services</h3>
|
||||
<div class="product-page-big-number">131</div>
|
||||
<div class="product-page-big-number">135</div>
|
||||
services
|
||||
</div>
|
||||
<div class="column-half">
|
||||
<h3 class="visually-hidden">Organisations</h3>
|
||||
<div class="product-page-big-number">55</div>
|
||||
<div class="product-page-big-number">58</div>
|
||||
organisations
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% else %}
|
||||
<div class="bottom-gutter-2-3">
|
||||
<div class="grid-row">
|
||||
{% if current_user.has_permissions(permissions=['send_texts', 'send_emails', 'send_letters']) %}
|
||||
{% if current_user.has_permissions('send_texts', 'send_emails', 'send_letters') %}
|
||||
<div class="{{ 'column-half' if template.template_type == 'letter' else 'column-third' }}">
|
||||
<a href="{{ url_for(".send_messages", service_id=current_service.id, template_id=template.id) }}" class="pill-separate-item">
|
||||
Upload recipients
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if
|
||||
current_user.has_permissions(permissions=['manage_templates'], admin_override=True) and
|
||||
current_user.has_permissions('manage_templates', admin_override=True) and
|
||||
template.template_type != 'letter'
|
||||
%}
|
||||
<div class="column-one-third">
|
||||
@@ -33,7 +33,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="column-whole template-container">
|
||||
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) and template.template_type == 'letter' %}
|
||||
{% if current_user.has_permissions('manage_templates', admin_override=True) and template.template_type == 'letter' %}
|
||||
<a href="{{ url_for(".edit_service_template", service_id=current_service.id, template_id=template.id) }}" class="edit-template-link-letter-body">Edit</a>
|
||||
<a href="{{ url_for(".set_template_sender", service_id=current_service.id, template_id=template.id) }}" class="edit-template-link-letter-contact">Edit</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
{% if not templates %}
|
||||
|
||||
{% if current_user.has_permissions(permissions=['manage_templates'], any_=True) %}
|
||||
{% if current_user.has_permissions('manage_templates', any_=True) %}
|
||||
<p class="bottom-gutter">
|
||||
You need a template before you can send text messages.
|
||||
</p>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<h1 class="heading-large">Templates</h1>
|
||||
|
||||
{% if current_user.has_permissions(permissions=['manage_templates'], any_=True) %}
|
||||
{% if current_user.has_permissions('manage_templates', any_=True) %}
|
||||
<p class="bottom-gutter">
|
||||
You need a template before you can send
|
||||
{% if 'letter' in current_service.permissions %}
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">Templates</h1>
|
||||
</div>
|
||||
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_templates', admin_override=True) %}
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.add_template_by_type', service_id=current_service.id) }}" class="button align-with-heading">Add new template</a>
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
 
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
|
||||
{% if current_user.has_permissions('manage_templates', admin_override=True) %}
|
||||
{% if not template._template.archived %}
|
||||
<span class="page-footer-delete-link page-footer-delete-link-without-button bottom-gutter-2-3">
|
||||
<a href="{{ url_for('.delete_service_template', service_id=current_service.id, template_id=template.id) }}">Delete this template</a>
|
||||
|
||||
@@ -39,7 +39,7 @@ Terms of use
|
||||
<li>get the right levels of consent (to send messages and to use data)</li>
|
||||
<li>not send unsolicited messages, only ones related to a transaction or something the user has subscribed to be updated about (<a href="https://www.gov.uk/service-manual/design/sending-emails-and-text-messages">check the Service Manual</a> if you’re not sure)</li>
|
||||
<li>
|
||||
send messages that meet the GOV.UK <a href="https://www.gov.uk/service-manual/design/using-adapting-and-creating-patterns">design patterns</a>, <a href="https://www.gov.uk/guidance/style-guide">style guide</a> and <a href="https://www.gov.uk/service-manual/technology/securing-your-information">information security guidelines</a></li>
|
||||
send messages that meet the GOV.UK Service Manual standards for <a href="https://www.gov.uk/service-manual/design/sending-emails-and-text-messages">writing text messages and emails</a></li>
|
||||
<li>not send messages containing any personally or commercially sensitive information</li>
|
||||
<li>check that the data you add to Notify is accurate and complies with Data Protection Act principles</li>
|
||||
</ul>
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ def user_has_permissions(*permissions, admin_override=False, any_=False):
|
||||
def wrap_func(*args, **kwargs):
|
||||
if current_user and current_user.is_authenticated:
|
||||
if current_user.has_permissions(
|
||||
permissions=permissions,
|
||||
*permissions,
|
||||
admin_override=admin_override,
|
||||
any_=any_
|
||||
):
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ Flask-Login==0.4.1
|
||||
|
||||
boto3==1.5.12
|
||||
blinker==1.4
|
||||
pyexcel==0.5.6
|
||||
pyexcel-io==0.5.5
|
||||
pyexcel==0.5.7
|
||||
pyexcel-io==0.5.6
|
||||
pyexcel-xls==0.5.5
|
||||
pyexcel-xlsx==0.5.5
|
||||
pyexcel-ods3==0.5.2
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
pytest==3.3.2
|
||||
pytest-mock==1.6.3
|
||||
pytest-cov==2.5.1
|
||||
pytest-xdist==1.21.0
|
||||
pytest-xdist==1.22.0
|
||||
coveralls==1.2.0
|
||||
httpretty==0.8.14
|
||||
beautifulsoup4==4.6.0
|
||||
|
||||
@@ -56,7 +56,6 @@ def service_json(
|
||||
service_callback_api=None,
|
||||
permissions=None,
|
||||
organisation_type='central',
|
||||
free_sms_fragment_limit=250000,
|
||||
prefix_sms=True,
|
||||
):
|
||||
if users is None:
|
||||
@@ -70,7 +69,6 @@ def service_json(
|
||||
'name': name,
|
||||
'users': users,
|
||||
'message_limit': message_limit,
|
||||
'free_sms_fragment_limit': free_sms_fragment_limit,
|
||||
'active': active,
|
||||
'restricted': restricted,
|
||||
'email_from': email_from,
|
||||
|
||||
@@ -38,7 +38,7 @@ def test_user_has_permissions_on_endpoint_fail(
|
||||
_test_permissions(
|
||||
client,
|
||||
user,
|
||||
['something'],
|
||||
['send_texts'],
|
||||
'',
|
||||
False)
|
||||
|
||||
@@ -66,7 +66,7 @@ def test_user_has_permissions_or(
|
||||
_test_permissions(
|
||||
client,
|
||||
user,
|
||||
['something', 'manage_users'],
|
||||
['send_texts', 'manage_users'],
|
||||
'',
|
||||
True,
|
||||
any_=True)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import pytest
|
||||
from app.notify_client.user_api_client import User
|
||||
|
||||
|
||||
@@ -25,3 +26,6 @@ def test_user():
|
||||
# set failed logins to threshold
|
||||
user.failed_login_count = 3
|
||||
assert user.is_locked()
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
user.has_permissions('to_do_bad_things')
|
||||
|
||||
@@ -464,19 +464,22 @@ def test_upload_valid_csv_redirects_to_check_page(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra_args, expected_recipient, expected_message', [
|
||||
@pytest.mark.parametrize('extra_args, expected_link_in_first_row, expected_recipient, expected_message', [
|
||||
(
|
||||
{},
|
||||
'To: 07700900001',
|
||||
'Test Service: A, Template <em>content</em> with & entity',
|
||||
),
|
||||
(
|
||||
{'row_index': 0},
|
||||
None,
|
||||
'To: 07700900001',
|
||||
'Test Service: A, Template <em>content</em> with & entity',
|
||||
),
|
||||
(
|
||||
{'row_index': 2},
|
||||
None,
|
||||
'To: 07700900001',
|
||||
'Test Service: A, Template <em>content</em> with & entity',
|
||||
),
|
||||
(
|
||||
{'row_index': 4},
|
||||
True,
|
||||
'To: 07700900003',
|
||||
'Test Service: C, Template <em>content</em> with & entity',
|
||||
),
|
||||
@@ -490,6 +493,7 @@ def test_upload_valid_csv_shows_preview_and_table(
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
extra_args,
|
||||
expected_link_in_first_row,
|
||||
expected_recipient,
|
||||
expected_message,
|
||||
):
|
||||
@@ -516,8 +520,16 @@ def test_upload_valid_csv_shows_preview_and_table(
|
||||
assert page.select_one('.sms-message-recipient').text.strip() == expected_recipient
|
||||
assert page.select_one('.sms-message-wrapper').text.strip() == expected_message
|
||||
|
||||
assert page.select_one('.table-field-index').text.strip() == '2'
|
||||
|
||||
if expected_link_in_first_row:
|
||||
assert page.select_one('.table-field-index a')['href'] == url_for(
|
||||
'main.check_messages', service_id=SERVICE_ONE_ID, template_type='sms', upload_id=fake_uuid, row_index=2
|
||||
)
|
||||
else:
|
||||
assert not page.select_one('.table-field-index').select_one('a')
|
||||
|
||||
for index, cell in enumerate([
|
||||
'<td class="table-field-index"> <span class=""> 2 </span> </td>',
|
||||
'<td class="table-field-center-aligned "> <div class=""> 07700900001 </div> </td>',
|
||||
'<td class="table-field-center-aligned "> <div class=""> A </div> </td>',
|
||||
(
|
||||
@@ -530,13 +542,16 @@ def test_upload_valid_csv_shows_preview_and_table(
|
||||
'</td>'
|
||||
),
|
||||
]):
|
||||
assert normalize_spaces(str(page.select('table tbody td')[index])) == cell
|
||||
assert normalize_spaces(str(page.select('table tbody td')[index + 1])) == cell
|
||||
|
||||
|
||||
@pytest.mark.parametrize('row_index, expected_status', [
|
||||
(0, 200),
|
||||
(0, 404),
|
||||
(1, 404),
|
||||
(2, 200),
|
||||
(3, 404),
|
||||
(3, 200),
|
||||
(4, 200),
|
||||
(5, 404),
|
||||
])
|
||||
def test_404_for_previewing_a_row_out_of_range(
|
||||
client_request,
|
||||
@@ -1468,11 +1483,11 @@ def test_can_start_letters_job(
|
||||
{'postcode': 'abc123', 'addressline1': '123 street'},
|
||||
),
|
||||
(
|
||||
{'row_index': 0},
|
||||
{'row_index': 2},
|
||||
{'postcode': 'abc123', 'addressline1': '123 street'},
|
||||
),
|
||||
(
|
||||
{'row_index': 1},
|
||||
{'row_index': 3},
|
||||
{'postcode': 'cba321', 'addressline1': '321 avenue'},
|
||||
),
|
||||
])
|
||||
|
||||
@@ -11,6 +11,7 @@ from app.utils import email_safe
|
||||
from tests import validate_route_permission, service_json
|
||||
from tests.conftest import (
|
||||
active_user_with_permissions,
|
||||
active_user_no_api_key_permission,
|
||||
platform_admin_user,
|
||||
normalize_spaces,
|
||||
multiple_reply_to_email_addresses,
|
||||
@@ -433,6 +434,14 @@ def test_should_show_request_to_go_live(
|
||||
assert normalize_spaces(
|
||||
page.select_one('label[for=channel_{}]'.format(channel)).text
|
||||
) == label
|
||||
for feature, label in (
|
||||
('one_off', 'One at a time'),
|
||||
('upload', 'Upload a spreadsheet of recipients'),
|
||||
('api', 'Integrate with the GOV.UK Notify API'),
|
||||
):
|
||||
assert normalize_spaces(
|
||||
page.select_one('label[for=method_{}]'.format(feature)).text
|
||||
) == label
|
||||
|
||||
|
||||
def test_should_redirect_after_request_to_go_live(
|
||||
@@ -458,7 +467,9 @@ def test_should_redirect_after_request_to_go_live(
|
||||
'start_date': '01/01/2017',
|
||||
'start_volume': '100,000',
|
||||
'peak_volume': '2,000,000',
|
||||
'upload_or_api': 'API'
|
||||
'method_one_off': 'y',
|
||||
'method_upload': 'y',
|
||||
'method_api': 'y',
|
||||
},
|
||||
_follow_redirects=True
|
||||
)
|
||||
@@ -476,11 +487,13 @@ def test_should_redirect_after_request_to_go_live(
|
||||
)
|
||||
|
||||
returned_message = mock_post.call_args[1]['data']['message']
|
||||
assert 'On behalf of service one' in returned_message
|
||||
assert 'Organisation type: central' in returned_message
|
||||
assert 'Channel: email and text messages' in returned_message
|
||||
assert 'Start date: 01/01/2017' in returned_message
|
||||
assert 'Start volume: 100,000' in returned_message
|
||||
assert 'Peak volume: 2,000,000' in returned_message
|
||||
assert 'Upload or API: API' in returned_message
|
||||
assert 'Features: one off, file upload and API' in returned_message
|
||||
|
||||
assert normalize_spaces(page.select_one('.banner-default').text) == (
|
||||
'We’ve received your request to go live'
|
||||
@@ -1927,6 +1940,41 @@ def test_set_inbound_sms_when_inbound_number_is_not_set(
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user, expected_paragraphs', [
|
||||
(active_user_with_permissions, [
|
||||
'Your service can receive text messages sent to 07700900123.',
|
||||
'If you want to turn this feature off, get in touch with the GOV.UK Notify team.',
|
||||
'You can set up callbacks for received text messages on the API integration page.',
|
||||
]),
|
||||
(active_user_no_api_key_permission, [
|
||||
'Your service can receive text messages sent to 07700900123.',
|
||||
'If you want to turn this feature off, get in touch with the GOV.UK Notify team.',
|
||||
]),
|
||||
])
|
||||
def test_set_inbound_sms_when_inbound_number_is_set(
|
||||
client,
|
||||
service_one,
|
||||
mocker,
|
||||
fake_uuid,
|
||||
user,
|
||||
expected_paragraphs,
|
||||
):
|
||||
service_one['permissions'] = ['inbound_sms']
|
||||
mocker.patch('app.inbound_number_client.get_inbound_sms_number_for_service', return_value={
|
||||
'data': {'number': '07700900123'}
|
||||
})
|
||||
client.login(user(fake_uuid), mocker, service_one)
|
||||
response = client.get(url_for(
|
||||
'main.service_set_inbound_sms', service_id=SERVICE_ONE_ID
|
||||
))
|
||||
paragraphs = BeautifulSoup(response.data.decode('utf-8'), 'html.parser').select('main p')
|
||||
|
||||
assert len(paragraphs) == len(expected_paragraphs)
|
||||
|
||||
for index, p in enumerate(expected_paragraphs):
|
||||
assert normalize_spaces(paragraphs[index].text) == p
|
||||
|
||||
|
||||
def test_empty_letter_contact_block_returns_error(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
|
||||
+26
-1
@@ -1236,6 +1236,31 @@ def active_user_manage_template_permission(fake_uuid):
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def active_user_no_api_key_permission(fake_uuid):
|
||||
from app.notify_client.user_api_client import User
|
||||
|
||||
user_data = {
|
||||
'id': fake_uuid,
|
||||
'name': 'Test User With Permissions',
|
||||
'password': 'somepassword',
|
||||
'password_changed_at': str(datetime.utcnow()),
|
||||
'email_address': 'test@user.gov.uk',
|
||||
'mobile_number': '07700 900762',
|
||||
'state': 'active',
|
||||
'failed_login_count': 0,
|
||||
'permissions': {SERVICE_ONE_ID: [
|
||||
'manage_templates',
|
||||
'manage_settings',
|
||||
'view_activity',
|
||||
]},
|
||||
'platform_admin': False,
|
||||
'auth_type': 'sms_auth'
|
||||
}
|
||||
user = User(user_data)
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def api_user_locked(fake_uuid):
|
||||
from app.notify_client.user_api_client import User
|
||||
@@ -1855,7 +1880,7 @@ def mock_no_inbound_number_for_service(mocker):
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_has_permissions(mocker):
|
||||
def _has_permission(permissions=None, any_=False, admin_override=False):
|
||||
def _has_permission(*permissions, any_=False, admin_override=False):
|
||||
return True
|
||||
|
||||
return mocker.patch(
|
||||
|
||||
Reference in New Issue
Block a user