mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-23 09:29:14 -04:00
Merge pull request #2171 from alphagov/flexible-data-retention
Flexible data retention
This commit is contained in:
@@ -344,6 +344,14 @@ def valid_phone_number(phone_number):
|
||||
return False
|
||||
|
||||
|
||||
def format_notification_type(notification_type):
|
||||
return {
|
||||
'email': 'Email',
|
||||
'sms': 'SMS',
|
||||
'letter': 'Letter'
|
||||
}[notification_type]
|
||||
|
||||
|
||||
def format_notification_status(status, template_type):
|
||||
return {
|
||||
'email': {
|
||||
@@ -646,6 +654,7 @@ def add_template_filters(application):
|
||||
format_datetime_relative,
|
||||
format_delta,
|
||||
format_notification_status,
|
||||
format_notification_type,
|
||||
format_notification_status_as_time,
|
||||
format_notification_status_as_field_status,
|
||||
format_notification_status_as_url,
|
||||
|
||||
@@ -1035,3 +1035,27 @@ class BrandingOptionsEmail(StripWhitespaceForm):
|
||||
DataRequired()
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class ServiceDataRetentionForm(StripWhitespaceForm):
|
||||
|
||||
notification_type = RadioField(
|
||||
'What notification type?',
|
||||
choices=[
|
||||
('email', 'Email'),
|
||||
('sms', 'SMS'),
|
||||
('letter', 'Letter'),
|
||||
],
|
||||
validators=[DataRequired()],
|
||||
)
|
||||
days_of_retention = IntegerField(label="Days of retention",
|
||||
validators=[validators.NumberRange(min=3, max=90,
|
||||
message="Must be between 3 and 90")],
|
||||
)
|
||||
|
||||
|
||||
class ServiceDataRetentionEditForm(StripWhitespaceForm):
|
||||
days_of_retention = IntegerField(label="Days of retention",
|
||||
validators=[validators.NumberRange(min=3, max=90,
|
||||
message="Must be between 3 and 90")],
|
||||
)
|
||||
|
||||
@@ -36,6 +36,8 @@ from app.main.forms import (
|
||||
RequestToGoLiveForm,
|
||||
ServiceBasicViewForm,
|
||||
ServiceContactLinkForm,
|
||||
ServiceDataRetentionEditForm,
|
||||
ServiceDataRetentionForm,
|
||||
ServiceEditInboundNumberForm,
|
||||
ServiceInboundNumberForm,
|
||||
ServiceLetterContactBlockForm,
|
||||
@@ -86,6 +88,7 @@ def service_settings(service_id):
|
||||
)
|
||||
|
||||
free_sms_fragment_limit = billing_api_client.get_free_sms_fragment_limit_for_year(service_id)
|
||||
data_retention = service_api_client.get_service_data_retention(service_id)
|
||||
|
||||
return render_template(
|
||||
'views/service-settings.html',
|
||||
@@ -104,6 +107,7 @@ def service_settings(service_id):
|
||||
free_sms_fragment_limit=free_sms_fragment_limit,
|
||||
prefix_sms=current_service.prefix_sms,
|
||||
organisation=organisation,
|
||||
data_retention=data_retention,
|
||||
)
|
||||
|
||||
|
||||
@@ -1006,6 +1010,48 @@ def branding_request(service_id):
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/data-retention", methods=['GET'])
|
||||
@login_required
|
||||
@user_is_platform_admin
|
||||
def data_retention(service_id):
|
||||
results = service_api_client.get_service_data_retention(service_id)
|
||||
return render_template('views/service-settings/data-retention.html',
|
||||
data_retention_settings=results)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/data-retention/add", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_is_platform_admin
|
||||
def add_data_retention(service_id):
|
||||
form = ServiceDataRetentionForm()
|
||||
if form.validate_on_submit():
|
||||
service_api_client.create_service_data_retention(service_id,
|
||||
form.notification_type.data,
|
||||
form.days_of_retention.data)
|
||||
return redirect(url_for('.data_retention', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/data-retention/add.html',
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/data-retention/<data_retention_id>/edit", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_is_platform_admin
|
||||
def edit_data_retention(service_id, data_retention_id):
|
||||
data_retention_item = service_api_client.get_service_data_retention_by_id(service_id, data_retention_id)
|
||||
form = ServiceDataRetentionEditForm(days_of_retention=data_retention_item['days_of_retention'])
|
||||
if form.validate_on_submit():
|
||||
service_api_client.update_service_data_retention(service_id, data_retention_id, form.days_of_retention.data)
|
||||
return redirect(url_for('.data_retention', service_id=service_id))
|
||||
return render_template(
|
||||
'views/service-settings/data-retention/edit.html',
|
||||
form=form,
|
||||
data_retention_id=data_retention_id,
|
||||
notification_type=data_retention_item['notification_type']
|
||||
)
|
||||
|
||||
|
||||
def get_branding_as_value_and_label(email_branding):
|
||||
return [
|
||||
(branding['id'], branding['name'])
|
||||
|
||||
@@ -103,6 +103,7 @@ class HeaderNavigation(Navigation):
|
||||
'accept_invite',
|
||||
'accept_org_invite',
|
||||
'action_blocked',
|
||||
'add_data_retention',
|
||||
'add_service',
|
||||
'add_service_template',
|
||||
'add_template_by_type',
|
||||
@@ -135,12 +136,14 @@ class HeaderNavigation(Navigation):
|
||||
'cookies',
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'data_retention',
|
||||
'delete_service_template',
|
||||
'delivery_and_failure',
|
||||
'delivery_status_callback',
|
||||
'design_content',
|
||||
'download_agreement',
|
||||
'download_notifications_csv',
|
||||
'edit_data_retention',
|
||||
'edit_organisation_name',
|
||||
'edit_provider',
|
||||
'edit_service_template',
|
||||
@@ -372,6 +375,7 @@ class MainNavigation(Navigation):
|
||||
exclude = {
|
||||
'accept_invite',
|
||||
'accept_org_invite',
|
||||
'add_data_retention',
|
||||
'add_organisation',
|
||||
'add_service',
|
||||
'agreement',
|
||||
@@ -391,11 +395,13 @@ class MainNavigation(Navigation):
|
||||
'conversation_updates',
|
||||
'cookies',
|
||||
'create_email_branding',
|
||||
'data_retention',
|
||||
'delivery_and_failure',
|
||||
'design_content',
|
||||
'documentation',
|
||||
'download_agreement',
|
||||
'download_notifications_csv',
|
||||
'edit_data_retention',
|
||||
'edit_organisation_name',
|
||||
'edit_provider',
|
||||
'edit_user_org_permissions',
|
||||
@@ -529,6 +535,7 @@ class CaseworkNavigation(Navigation):
|
||||
'accept_invite',
|
||||
'accept_org_invite',
|
||||
'action_blocked',
|
||||
'add_data_retention',
|
||||
'add_organisation',
|
||||
'add_service',
|
||||
'add_service_template',
|
||||
@@ -563,6 +570,7 @@ class CaseworkNavigation(Navigation):
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'create_email_branding',
|
||||
'data_retention',
|
||||
'delete_service_template',
|
||||
'delivery_and_failure',
|
||||
'delivery_status_callback',
|
||||
@@ -570,6 +578,7 @@ class CaseworkNavigation(Navigation):
|
||||
'documentation',
|
||||
'download_agreement',
|
||||
'download_notifications_csv',
|
||||
'edit_data_retention',
|
||||
'edit_organisation_name',
|
||||
'edit_provider',
|
||||
'edit_service_template',
|
||||
@@ -755,6 +764,7 @@ class OrgNavigation(Navigation):
|
||||
'accept_invite',
|
||||
'accept_org_invite',
|
||||
'action_blocked',
|
||||
'add_data_retention',
|
||||
'add_organisation',
|
||||
'add_service',
|
||||
'add_service_template',
|
||||
@@ -789,6 +799,7 @@ class OrgNavigation(Navigation):
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'create_email_branding',
|
||||
'data_retention',
|
||||
'delete_service_template',
|
||||
'delivery_and_failure',
|
||||
'delivery_status_callback',
|
||||
@@ -796,6 +807,7 @@ class OrgNavigation(Navigation):
|
||||
'documentation',
|
||||
'download_agreement',
|
||||
'download_notifications_csv',
|
||||
'edit_data_retention',
|
||||
'edit_provider',
|
||||
'edit_service_template',
|
||||
'edit_user_permissions',
|
||||
|
||||
@@ -480,3 +480,23 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
"updated_by_id": user_id
|
||||
}
|
||||
return self.post("/service/{}/delivery-receipt-api".format(service_id), data)
|
||||
|
||||
def create_service_data_retention(self, service_id, notification_type, days_of_retention):
|
||||
data = {
|
||||
"notification_type": notification_type,
|
||||
"days_of_retention": days_of_retention
|
||||
}
|
||||
|
||||
return self.post("/service/{}/data-retention".format(service_id), data)
|
||||
|
||||
def update_service_data_retention(self, service_id, data_retention_id, days_of_retention):
|
||||
data = {
|
||||
"days_of_retention": days_of_retention
|
||||
}
|
||||
return self.post("/service/{}/data-retention/{}".format(service_id, data_retention_id), data)
|
||||
|
||||
def get_service_data_retention(self, service_id):
|
||||
return self.get("/service/{}/data-retention".format(service_id))
|
||||
|
||||
def get_service_data_retention_by_id(self, service_id, data_retention_id):
|
||||
return self.get("service/{}/data-retention/{}".format(service_id, data_retention_id))
|
||||
|
||||
@@ -320,6 +320,13 @@
|
||||
{{ text_field(letter_branding) }}
|
||||
{{ edit_field('Change', url_for('.set_letter_branding', service_id=current_service.id)) }}
|
||||
{% endcall %}
|
||||
{% call row() %}
|
||||
{{ text_field('Data retention')}}
|
||||
{% call field() %}
|
||||
{{ data_retention | join(', ', attribute='notification_type') }}
|
||||
{% endcall %}
|
||||
{{ edit_field('Change', url_for('.data_retention', service_id=current_service.id)) }}
|
||||
{% endcall %}
|
||||
{% endcall %}
|
||||
|
||||
<ul>
|
||||
|
||||
50
app/templates/views/service-settings/data-retention.html
Normal file
50
app/templates/views/service-settings/data-retention.html
Normal file
@@ -0,0 +1,50 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/api-key.html" import api_key %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/table.html" import mapping_table, row_group, row, text_field, edit_field, field, boolean_field, list_table with context %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Email reply to addresses
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-large">
|
||||
Data retention
|
||||
</h1>
|
||||
</div>
|
||||
<div class="column-one-third">
|
||||
<a href="{{ url_for('.add_data_retention', service_id=current_service.id) }}" class="button align-with-heading">Add data retention</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-full">
|
||||
By default data is kept for 7 days
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-list">
|
||||
{% if not data_retention_settings %}
|
||||
<div class="user-list-item">
|
||||
<span class="hint">You haven’t added any data retention</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% call mapping_table(
|
||||
caption='Data retention',
|
||||
field_headings=['Label', 'Value', 'Action'],
|
||||
field_headings_visible=False,
|
||||
caption_visible=False
|
||||
) %}
|
||||
{% for item in data_retention_settings %}
|
||||
{% call row() %}
|
||||
{{ text_field(item.notification_type | format_notification_type)}}
|
||||
{{ text_field(item.days_of_retention) }}
|
||||
{{ edit_field('Change', url_for('.edit_data_retention', service_id=current_service.id, data_retention_id=item.id)) }}
|
||||
{% endcall %}
|
||||
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
25
app/templates/views/service-settings/data-retention/add.html
Normal file
25
app/templates/views/service-settings/data-retention/add.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% from "components/radios.html" import radios %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Data retention
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
|
||||
<h1 class="heading-large">Set data retention</h1>
|
||||
<form method="post">
|
||||
{{ radios(form.notification_type) }}
|
||||
{{ textbox(form.days_of_retention) }}
|
||||
{{ page_footer(
|
||||
'Add',
|
||||
back_link=url_for('.add_data_retention', service_id=current_service.id),
|
||||
back_link_text='Back'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,25 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
|
||||
{% from "components/radios.html" import radios %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Data retention
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
|
||||
<h1 class="heading-large">Set data retention</h1>
|
||||
<form method="post">
|
||||
{{ notification_type | capitalize}}
|
||||
{{ textbox(form.days_of_retention) }}
|
||||
{{ page_footer(
|
||||
'Save',
|
||||
back_link=url_for('.edit_data_retention', service_id=current_service.id, data_retention_id=data_retention_id),
|
||||
back_link_text='Back'
|
||||
) }}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user