Add feature to mark a template as redacted

Works similarly to the delete template flow, because it’s a destructive,
one-way action.

Not on the edit template page, because it’s not something you want to be
considering every time you’re editing a template. And we saw that people
couldn’t find the delete button when it was on this page.

Adds a bit more CSS for the `dangerous` banner type, because the content
here is quite complicated. Breaking it into a list helps, but the
spacing didn’t look right, so needed some tweaking.

Can ship independently of the code that shows the redaction, but needs
the API first.
This commit is contained in:
Chris Hill-Scott
2017-06-26 14:41:00 +01:00
parent 1dbd6a122d
commit 9569521142
8 changed files with 143 additions and 18 deletions

View File

@@ -252,3 +252,7 @@ details .arrow {
color: $secondary-text-colour;
cursor: default;
}
.heading-inline {
display: inline-block;
}

View File

@@ -76,6 +76,10 @@
}
.list {
margin-bottom: 0;
}
}
.banner-tour {

View File

@@ -40,6 +40,7 @@
}
&-delete-link-without-button {
@include core-19;
padding-left: 0;
}

View File

@@ -383,6 +383,44 @@ def delete_service_template(service_id, template_id):
)
@main.route("/services/<service_id>/templates/<template_id>/redact", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_templates', admin_override=True)
def redact_template(service_id, template_id):
if request.method == 'POST':
service_api_client.redact_service_template(service_id, template_id)
flash(
'Personalised content will be hidden for messages sent with this template',
'default_with_tick'
)
return redirect(url_for(
'.view_template',
service_id=service_id,
template_id=template_id,
))
return render_template(
'views/templates/template.html',
template=get_template(
service_api_client.get_service_template(service_id, template_id)['data'],
current_service,
expand_emails=True,
letter_preview_url=url_for(
'.view_letter_template_preview',
service_id=service_id,
template_id=template_id,
filetype='png',
),
show_recipient=True,
),
show_redaction_message=True,
)
@main.route('/services/<service_id>/templates/<template_id>/versions')
@login_required
@user_has_permissions(

View File

@@ -168,6 +168,12 @@ class ServiceAPIClient(NotifyAdminAPIClient):
endpoint = "/service/{0}/template/{1}".format(service_id, id_)
return self.post(endpoint, data)
def redact_service_template(self, service_id, id_):
return self.post(
"/service/{}/template/{}".format(service_id, id_),
{'redact_personalisation': True}
)
def get_service_template(self, service_id, template_id, version=None, *params):
"""
Retrieve a service template.

View File

@@ -1,4 +1,5 @@
{% extends "withnav_template.html" %}
{% from "components/banner.html" import banner_wrapper %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/textbox.html" import textbox %}
{% from "components/api-key.html" import api_key %}
@@ -9,6 +10,24 @@
{% block maincolumn_content %}
{% if show_redaction_message %}
<div class="bottom-gutter">
{% call banner_wrapper(type='dangerous', subhead='Are you sure you want to hide personalisation after sending?') %}
<ul class="list list-bullet">
<li>
You wont be able to see personalised content in Notify for this template
</li>
<li>
You cant undo this
</li>
</ul>
<form method='post'>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="submit" class="button" name="delete" value="Confirm" />
</form>
{% endcall %}
</div>
{% endif %}
<h1 class="heading-large">{{ template.name }}</h1>
@@ -18,26 +37,29 @@
{% endwith %}
</div>
<div class="bottom-gutter">
<div class="bottom-gutter-1-2">
{{ api_key(template.id, name="Template ID", thing='template ID') }}
</div>
{% if template._template.updated_at %}
<div class="bottom-gutter-1-2">
<h2 class="heading-small">Last edited {{ template._template.updated_at|format_delta }}</h2>
<p>
<a href="{{ url_for('.view_template_versions', service_id=current_service.id, template_id=template.id) }}">See previous versions</a>
</p>
</div>
{% endif %}
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
<div class="bottom-gutter">
{{ page_footer(
delete_link=url_for('.delete_service_template', service_id=current_service.id, template_id=template.id),
delete_link_text='Delete this template'
) }}
</div>
{% endif %}
<div class="bottom-gutter-1-2">
{% if template._template.updated_at %}
<h2 class="heading-small bottom-gutter-2-3 heading-inline">Last edited {{ template._template.updated_at|format_delta }}</h2>
&emsp;
<a href="{{ url_for('.view_template_versions', service_id=current_service.id, template_id=template.id) }}">See previous versions</a>
&emsp;
<br/>
{% endif %}
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
<span class="page-footer-delete-link page-footer-delete-link-without-button">
<a href="{{ url_for('.delete_service_template', service_id=current_service.id, template_id=template.id) }}">Delete this template</a>
</span>
&emsp;
{% if not template.redact_personalisation %}
<span class="page-footer-delete-link page-footer-delete-link-without-button">
<a href="{{ url_for('.redact_template', service_id=current_service.id, template_id=template.id) }}">Hide personalisation after sending</a>
</span>
{% endif %}
{% endif %}
</div>
{% endblock %}

View File

@@ -942,3 +942,48 @@ def test_should_create_sms_template_without_downgrading_unicode_characters(
ANY # process_type
)
assert resp.status_code == 302
def test_should_show_message_before_redacting_template(
client_request,
mock_get_service_template,
service_one,
fake_uuid,
):
page = client_request.get(
'main.redact_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert (
'Are you sure you want to hide personalisation after sending?'
) in page.select('.banner-dangerous')[0].text
form = page.select('.banner-dangerous form')[0]
assert 'action' not in form
assert form['method'] == 'post'
def test_should_show_redact_template(
client_request,
mock_get_service_template,
mock_redact_template,
service_one,
fake_uuid,
):
page = client_request.post(
'main.redact_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_follow_redirects=True,
)
assert normalize_spaces(page.select('.banner-default-with-tick')[0].text) == (
'Personalised content will be hidden for messages sent with this template'
)
mock_redact_template.assert_called_once_with(SERVICE_ONE_ID, fake_uuid)

View File

@@ -518,6 +518,11 @@ def mock_delete_service_template(mocker):
'app.service_api_client.delete_service_template', side_effect=_delete)
@pytest.fixture(scope='function')
def mock_redact_template(mocker):
return mocker.patch('app.service_api_client.redact_service_template')
@pytest.fixture(scope='function')
def api_user_pending(fake_uuid):
from app.notify_client.user_api_client import User