mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
When someone complains about an email from the platform we get a callback from SES.
A new platform admin page Email complaints has been added to surface those complaints. Eventually the complaints will be visible to the services so they can remove the email address from their mailing list. Next thing to implement is "x email complaints" warning on the platform admin summary page.
This commit is contained in:
@@ -58,6 +58,7 @@ from app.notify_client.org_invite_api_client import OrgInviteApiClient
|
||||
from app.notify_client.letter_jobs_client import LetterJobsClient
|
||||
from app.notify_client.inbound_number_client import InboundNumberClient
|
||||
from app.notify_client.billing_api_client import BillingAPIClient
|
||||
from app.notify_client.complaint_api_client import ComplaintApiClient
|
||||
from app.commands import setup_commands
|
||||
from app.utils import get_cdn_domain
|
||||
from app.utils import gmt_timezones
|
||||
@@ -84,6 +85,7 @@ zendesk_client = ZendeskClient()
|
||||
letter_jobs_client = LetterJobsClient()
|
||||
inbound_number_client = InboundNumberClient()
|
||||
billing_api_client = BillingAPIClient()
|
||||
complaint_api_client = ComplaintApiClient()
|
||||
|
||||
# The current service attached to the request stack.
|
||||
current_service = LocalProxy(partial(_lookup_req_object, 'service'))
|
||||
@@ -128,6 +130,7 @@ def create_app(application):
|
||||
letter_jobs_client.init_app(application)
|
||||
inbound_number_client.init_app(application)
|
||||
billing_api_client.init_app(application)
|
||||
complaint_api_client.init_app(application)
|
||||
|
||||
login_manager.init_app(application)
|
||||
login_manager.login_view = 'main.sign_in'
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import datetime
|
||||
from flask import render_template, request
|
||||
from flask_login import login_required
|
||||
|
||||
from app import service_api_client
|
||||
from app import complaint_api_client, service_api_client
|
||||
from app.main import main
|
||||
from app.main.forms import DateFilterForm
|
||||
from app.statistics_utils import get_formatted_percentage
|
||||
@@ -70,6 +70,18 @@ def platform_admin_services():
|
||||
)
|
||||
|
||||
|
||||
@main.route("/platform-admin/complaints")
|
||||
@login_required
|
||||
@user_is_platform_admin
|
||||
def platform_admin_list_complaints():
|
||||
complaints = complaint_api_client.get_all_complaints()
|
||||
return render_template(
|
||||
'views/platform-admin/complaints.html',
|
||||
complaints=complaints,
|
||||
page_title='All Complaints',
|
||||
)
|
||||
|
||||
|
||||
def sum_service_usage(service):
|
||||
total = 0
|
||||
for notification_type in service['statistics'].keys():
|
||||
|
||||
@@ -84,6 +84,7 @@ class HeaderNavigation(Navigation):
|
||||
'update_email_branding',
|
||||
'view_provider',
|
||||
'view_providers',
|
||||
'platform_admin_list_complaints',
|
||||
},
|
||||
'sign-in': {
|
||||
'sign_in',
|
||||
@@ -418,6 +419,7 @@ class MainNavigation(Navigation):
|
||||
'organisation_settings',
|
||||
'organisations',
|
||||
'platform_admin',
|
||||
'platform_admin_list_complaints',
|
||||
'pricing',
|
||||
'privacy',
|
||||
'public_agreement',
|
||||
@@ -586,6 +588,7 @@ class OrgNavigation(Navigation):
|
||||
'old_using_notify',
|
||||
'organisations',
|
||||
'platform_admin',
|
||||
'platform_admin_list_complaints',
|
||||
'pricing',
|
||||
'privacy',
|
||||
'public_agreement',
|
||||
|
||||
11
app/notify_client/complaint_api_client.py
Normal file
11
app/notify_client/complaint_api_client.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from app.notify_client import NotifyAdminAPIClient
|
||||
|
||||
|
||||
class ComplaintApiClient(NotifyAdminAPIClient):
|
||||
# Fudge assert in the super __init__ so
|
||||
# we can set those variables later.
|
||||
def __init__(self):
|
||||
super().__init__("a" * 73, "b")
|
||||
|
||||
def get_all_complaints(self):
|
||||
return self.get('/complaint')
|
||||
@@ -19,7 +19,8 @@
|
||||
('Providers', url_for('main.view_providers')),
|
||||
('Email branding', url_for('main.email_branding')),
|
||||
('Letter jobs', url_for('main.letter_jobs')),
|
||||
('Inbound SMS numbers', url_for('main.inbound_sms_admin'))
|
||||
('Inbound SMS numbers', url_for('main.inbound_sms_admin')),
|
||||
('Email Complaints', url_for('main.platform_admin_list_complaints'))
|
||||
] %}
|
||||
<li>
|
||||
<a href="{{ url }}">
|
||||
|
||||
36
app/templates/views/platform-admin/complaints.html
Normal file
36
app/templates/views/platform-admin/complaints.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends "views/platform-admin/_base_template.html" %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/table.html" import list_table, field, text_field, link_field, right_aligned_field_heading, hidden_field_heading %}
|
||||
|
||||
{% block per_page_title %}
|
||||
{{ page_title|capitalize }}
|
||||
{% endblock %}
|
||||
|
||||
{% block platform_admin_content %}
|
||||
|
||||
<h1 class="heading-large">
|
||||
Email complaints
|
||||
</h1>
|
||||
|
||||
|
||||
{% call(item, row_number) list_table(
|
||||
complaints,
|
||||
caption="Complaints",
|
||||
caption_visible=False,
|
||||
empty_message='No complaints',
|
||||
field_headings=['Notification Id', 'Service', 'Complaint type', 'Complaint Date'],
|
||||
field_headings_visible=True
|
||||
) %}
|
||||
|
||||
{{ link_field(item.notification_id, url_for('main.view_notification', service_id=item.service_id, notification_id=item.notification_id)) }}
|
||||
|
||||
{{ link_field(item.service_name, url_for('main.service_dashboard', service_id=item.service_id)) }}
|
||||
|
||||
{{ text_field(item.complaint_type) }}
|
||||
|
||||
{{ text_field(item.complaint_date|format_datetime_short) }}
|
||||
|
||||
{% endcall %}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from unittest.mock import ANY
|
||||
|
||||
import pytest
|
||||
@@ -637,3 +638,32 @@ def test_sum_service_usage_with_zeros(fake_uuid):
|
||||
sms_failed=0
|
||||
)
|
||||
assert sum_service_usage(service) == 0
|
||||
|
||||
|
||||
def test_platform_admin_list_complaints(
|
||||
client,
|
||||
platform_admin_user,
|
||||
mocker
|
||||
):
|
||||
mock_get_user(mocker, user=platform_admin_user)
|
||||
client.login(platform_admin_user)
|
||||
complaint = {
|
||||
'id': str(uuid.uuid4()),
|
||||
'notification_id': str(uuid.uuid4()),
|
||||
'service_id': str(uuid.uuid4()),
|
||||
'service_name': 'Sample service',
|
||||
'ses_feedback_id': 'Some ses id',
|
||||
'complaint_type': 'abuse',
|
||||
'complaint_date': '2018-06-05T13:50:30.012354',
|
||||
'created_at': '2018-06-05T13:50:30.012354',
|
||||
}
|
||||
mock = mocker.patch('app.complaint_api_client.get_all_complaints',
|
||||
return_value=[complaint])
|
||||
|
||||
client.login(platform_admin_user)
|
||||
response = client.get(url_for('main.platform_admin_list_complaints'))
|
||||
|
||||
assert response.status_code == 200
|
||||
resp_data = response.get_data(as_text=True)
|
||||
assert 'Email complaints' in resp_data
|
||||
mock.assert_called_once()
|
||||
|
||||
10
tests/app/notify_client/test_compliant_client.py
Normal file
10
tests/app/notify_client/test_compliant_client.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from app import ComplaintApiClient
|
||||
|
||||
|
||||
def test_get_all_complaints(mocker):
|
||||
client = ComplaintApiClient()
|
||||
|
||||
mock = mocker.patch('app.notify_client.complaint_api_client.ComplaintApiClient.get')
|
||||
|
||||
client.get_all_complaints()
|
||||
mock.assert_called_once_with('/complaint')
|
||||
Reference in New Issue
Block a user