mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-28 18:24:00 -04:00
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:
@@ -252,3 +252,7 @@ details .arrow {
|
|||||||
color: $secondary-text-colour;
|
color: $secondary-text-colour;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.heading-inline {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,6 +76,10 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner-tour {
|
.banner-tour {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-delete-link-without-button {
|
&-delete-link-without-button {
|
||||||
|
@include core-19;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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')
|
@main.route('/services/<service_id>/templates/<template_id>/versions')
|
||||||
@login_required
|
@login_required
|
||||||
@user_has_permissions(
|
@user_has_permissions(
|
||||||
|
|||||||
@@ -168,6 +168,12 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
|||||||
endpoint = "/service/{0}/template/{1}".format(service_id, id_)
|
endpoint = "/service/{0}/template/{1}".format(service_id, id_)
|
||||||
return self.post(endpoint, data)
|
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):
|
def get_service_template(self, service_id, template_id, version=None, *params):
|
||||||
"""
|
"""
|
||||||
Retrieve a service template.
|
Retrieve a service template.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
{% from "components/page-footer.html" import page_footer %}
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
{% from "components/textbox.html" import textbox %}
|
{% from "components/textbox.html" import textbox %}
|
||||||
{% from "components/api-key.html" import api_key %}
|
{% from "components/api-key.html" import api_key %}
|
||||||
@@ -9,6 +10,24 @@
|
|||||||
|
|
||||||
{% block maincolumn_content %}
|
{% 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 won’t be able to see personalised content in Notify for this template
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can’t 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>
|
<h1 class="heading-large">{{ template.name }}</h1>
|
||||||
|
|
||||||
@@ -18,26 +37,29 @@
|
|||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bottom-gutter">
|
<div class="bottom-gutter-1-2">
|
||||||
{{ api_key(template.id, name="Template ID", thing='template ID') }}
|
{{ api_key(template.id, name="Template ID", thing='template ID') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if template._template.updated_at %}
|
<div class="bottom-gutter-1-2">
|
||||||
<div class="bottom-gutter-1-2">
|
{% if template._template.updated_at %}
|
||||||
<h2 class="heading-small">Last edited {{ template._template.updated_at|format_delta }}</h2>
|
<h2 class="heading-small bottom-gutter-2-3 heading-inline">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>
|
<a href="{{ url_for('.view_template_versions', service_id=current_service.id, template_id=template.id) }}">See previous versions</a>
|
||||||
</p>
|
 
|
||||||
</div>
|
<br/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
|
||||||
{% if current_user.has_permissions(permissions=['manage_templates'], admin_override=True) %}
|
<span class="page-footer-delete-link page-footer-delete-link-without-button">
|
||||||
<div class="bottom-gutter">
|
<a href="{{ url_for('.delete_service_template', service_id=current_service.id, template_id=template.id) }}">Delete this template</a>
|
||||||
{{ page_footer(
|
</span>
|
||||||
delete_link=url_for('.delete_service_template', service_id=current_service.id, template_id=template.id),
|
 
|
||||||
delete_link_text='Delete this template'
|
{% if not template.redact_personalisation %}
|
||||||
) }}
|
<span class="page-footer-delete-link page-footer-delete-link-without-button">
|
||||||
</div>
|
<a href="{{ url_for('.redact_template', service_id=current_service.id, template_id=template.id) }}">Hide personalisation after sending</a>
|
||||||
{% endif %}
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -942,3 +942,48 @@ def test_should_create_sms_template_without_downgrading_unicode_characters(
|
|||||||
ANY # process_type
|
ANY # process_type
|
||||||
)
|
)
|
||||||
assert resp.status_code == 302
|
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)
|
||||||
|
|||||||
@@ -518,6 +518,11 @@ def mock_delete_service_template(mocker):
|
|||||||
'app.service_api_client.delete_service_template', side_effect=_delete)
|
'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')
|
@pytest.fixture(scope='function')
|
||||||
def api_user_pending(fake_uuid):
|
def api_user_pending(fake_uuid):
|
||||||
from app.notify_client.user_api_client import User
|
from app.notify_client.user_api_client import User
|
||||||
|
|||||||
Reference in New Issue
Block a user