Skip to content

Commit

Permalink
Add platform admin page for uuid queries (#1965)
Browse files Browse the repository at this point in the history
  • Loading branch information
sastels authored Nov 14, 2024
1 parent 9f9a137 commit 7a08447
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
from app.notify_client.provider_client import provider_client
from app.notify_client.service_api_client import service_api_client
from app.notify_client.status_api_client import status_api_client
from app.notify_client.support_api_client import support_api_client
from app.notify_client.template_api_prefill_client import template_api_prefill_client
from app.notify_client.template_category_api_client import template_category_api_client
from app.notify_client.template_folder_api_client import template_folder_api_client
Expand Down Expand Up @@ -165,6 +166,7 @@ def get_locale():
provider_client,
service_api_client,
status_api_client,
support_api_client,
template_category_api_client,
template_folder_api_client,
template_statistics_client,
Expand Down
1 change: 1 addition & 0 deletions app/main/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
email_branding,
find_services,
find_users,
find_ids,
forgot_password,
inbound_number,
index,
Expand Down
7 changes: 7 additions & 0 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,13 @@ class SearchUsersByEmailForm(StripWhitespaceForm):
)


class SearchIds(StripWhitespaceForm):
search = SearchField(
_l("List of UUIDs"),
validators=[DataRequired(_l("You need to enter one or more UUIDs to search by."))],
)


class SearchUsersForm(StripWhitespaceForm):
search = SearchField(_l("Search by name or email address"))

Expand Down
16 changes: 16 additions & 0 deletions app/main/views/find_ids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask import render_template

from app import support_api_client
from app.main import main
from app.main.forms import SearchIds
from app.utils import user_is_platform_admin


@main.route("/find-ids", methods=["GET", "POST"])
@user_is_platform_admin
def find_ids():
form = SearchIds()
records = None
if form.validate_on_submit():
records = support_api_client.find_ids(form.search.data)
return render_template("views/find-ids/find-ids.html", form=form, records=records)
5 changes: 5 additions & 0 deletions app/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class AdminNavigation(Navigation):
"find_users_by_email": {
"find_users_by_email",
},
"find_ids": {
"find_ids",
},
"platform_admin_list_complaints": {
"platform_admin_list_complaints",
},
Expand Down Expand Up @@ -510,6 +513,7 @@ class MainNavigation(Navigation):
"template_categories",
"find_services_by_name",
"find_users_by_email",
"find_ids",
"letter_branding",
"live_api_keys",
"live_services",
Expand Down Expand Up @@ -634,6 +638,7 @@ class OrgNavigation(Navigation):
"contact",
"find_services_by_name",
"find_users_by_email",
"find_ids",
"forgot_password",
"forced-password-reset",
"get_example_csv",
Expand Down
17 changes: 17 additions & 0 deletions app/notify_client/support_api_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from app.notify_client import NotifyAdminAPIClient


class SupportApiClient(NotifyAdminAPIClient):
def init_app(self, app):
super().init_app(app)
self.admin_url = app.config["ADMIN_BASE_URL"]
self.contact_email = app.config["CONTACT_EMAIL"]
self.notify_user_id = app.config["NOTIFY_USER_ID"]
self.notify_service_id = app.config["NOTIFY_SERVICE_ID"]

def find_ids(self, ids):
data = self.get("/support/find-ids", params={"ids": ids})
return data


support_api_client = SupportApiClient()
3 changes: 3 additions & 0 deletions app/notify_client/user_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def verify_password(self, user_id, password, login_data={}):
if e.status_code == 400 or e.status_code == 404:
return False

def find_ids(self, ids):
return self.get("/support/find-ids", params={"ids": ids})

def send_verify_code(self, user_id, code_type, to, next_string=None):
data = {"to": to}
if next_string:
Expand Down
1 change: 1 addition & 0 deletions app/templates/partials/nav/gc_header_nav_mobile.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
('Template categories', 'template_categories'),
('Search for service', 'find_services_by_name'),
('Search for user', 'find_users_by_email'),
('Search for ids', 'find_ids'),
('Email complaints', 'platform_admin_list_complaints'),
('Reports', 'platform_admin_reports'),
('Inbound SMS numbers', 'inbound_sms_admin'),
Expand Down
64 changes: 64 additions & 0 deletions app/templates/views/find-ids/find-ids.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{% extends "views/platform-admin/_base_template.html" %}
{% from "components/form.html" import form_wrapper %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/textbox.html" import textbox_search %}

{% block per_page_title %}
{{ _('Search for ids') }}
{% endblock %}

{% block platform_admin_content %}

<h1 class="heading-large">
{{ _('Search for ids') }}
</h1>


{% call form_wrapper(
action=url_for('.find_ids'),
class='grid-row contain-floats',
id='search-form'
) %}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
{% set label_txt = _('Find records by UUID') %}
<div class="md:w-full float-left py-0 px-0 px-gutterHalf box-border">
{{ textbox_search(
form.search,
width='w-full',
label=label_txt
) }}
</div>
{% endcall %}

{% if records %}
{% for record in records %}
<nav class="browse-list">
<ul>
<li class="browse-list-item">
{% if record.type == "notification" %}
<a href="{{url_for('.service_dashboard', service_id=record.service_id)}}" class="browse-list-link">{{ record.service_name }}</a> /
<a href="{{url_for('.view_template', service_id=record.service_id, template_id=record.template_id)}}" class="browse-list-link">{{ record.template_name }}</a> /
<a href="{{url_for('.view_notification', service_id=record.service_id, notification_id=record.id)}}" class="browse-list-link">notification</a>
{% elif record.type == "template" %}
<a href="{{url_for('.service_dashboard', service_id=record.service_id)}}" class="browse-list-link">{{ record.service_name }}</a> /
<a href="{{url_for('.view_template', service_id=record.service_id, template_id=record.id)}}" class="browse-list-link">{{ record.template_name }}</a>
{% elif record.type == "service" %}
<a href="{{url_for('.service_dashboard', service_id=record.id)}}" class="browse-list-link">{{ record.service_name }}</a>
{% elif record.type == "user" %}
<a href="{{url_for('.user_information', user_id=record.id)}}" class="browse-list-link">{{ record.user_name }}</a>
{% elif record.type == "job" %}
<a href="{{url_for('.service_dashboard', service_id=record.service_id)}}" class="browse-list-link">{{ record.service_name }}</a> /
<a href="{{url_for('.view_template', service_id=record.service_id, template_id=record.template_id)}}" class="browse-list-link">{{ record.template_name }}</a> /
<a href="{{url_for('.view_job', service_id=record.service_id, job_id=record.id)}}" class="browse-list-link">job</a>
{% else %}
{{ record.type}}
{% endif %}
</li>
</ul>
</nav>
{% endfor %}

{% elif records == [] %}
<p class="browse-list-hint">{{ _('No records found.') }}</p>
{% endif %}
{% endblock %}
1 change: 1 addition & 0 deletions app/templates/views/platform-admin/_base_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
('Template categories', 'template_categories'),
('Search for service', 'find_services_by_name'),
('Search for user', 'find_users_by_email'),
('Search for ids', 'find_ids'),
('Email complaints', 'platform_admin_list_complaints'),
('Reports', 'platform_admin_reports'),
('Inbound SMS numbers', 'inbound_sms_admin'),
Expand Down
4 changes: 4 additions & 0 deletions app/translations/csv/fr.csv
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@
"Search by email address","Cherchez par adresse courriel"
"Search by phone number","Cherchez par numéro de téléphone"
"Search by email address or phone number","Chercher par adresse courriel ou par numéro de téléphone"
"Search for ids","Recherche par id"
"List of UUIDs","Liste des UUIDs"
"Find records by UUID","Recherche d'enregistrements par UUID"
"You need to enter one or more UUIDs to search by.","Vous devez saisir un ou plusieurs UUIDs pour effectuer la recherche."
"Must be a valid https URL","L’URL https doit être valide"
"Bearer token","Jeton 'Bearer'"
"Must be at least 10 characters","Doit contenir au moins 10 caractères"
Expand Down
154 changes: 154 additions & 0 deletions tests/app/main/views/test_find_ids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
def test_find_ids_page_loads_correctly(client_request, platform_admin_user):
client_request.login(platform_admin_user)
document = client_request.get("main.find_ids")

assert document.h1.text.strip() == "Search for ids"
assert len(document.find_all("input", {"type": "search"})) > 0


def test_find_ids_displays_services_found(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[{"id": "1234", "type": "service", "service_name": "Test Service"}],
)
document = client_request.post(
"main.find_ids",
_data={"search": "1234"},
_expected_status=200,
)
get_records.assert_called_once_with("1234")
result = document.find("a", {"class": "browse-list-link"})
assert result.text.strip() == "Test Service"
assert result.attrs["href"] == "/services/1234"


def test_find_ids_displays_notifications_found(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[
{
"id": "1234",
"type": "notification",
"service_id": "service_1234",
"service_name": "Test Service",
"template_id": "template_1234",
"template_name": "Test Template",
}
],
)
document = client_request.post(
"main.find_ids",
_data={"search": "1234"},
_expected_status=200,
)
get_records.assert_called_once_with("1234")
results = document.find_all("a", {"class": "browse-list-link"})
assert len(results) == 3
assert results[0].text.strip() == "Test Service"
assert results[0].attrs["href"] == "/services/service_1234"
assert results[1].text.strip() == "Test Template"
assert results[1].attrs["href"] == "/services/service_1234/templates/template_1234"
assert results[2].text.strip() == "notification"
assert results[2].attrs["href"] == "/services/service_1234/notification/1234"


def test_find_ids_displays_templates_found(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[
{
"id": "1234",
"type": "template",
"template_name": "Test Template",
"service_id": "service_1234",
"service_name": "Test Service",
}
],
)
document = client_request.post(
"main.find_ids",
_data={"search": "1234"},
_expected_status=200,
)
get_records.assert_called_once_with("1234")
results = document.find_all("a", {"class": "browse-list-link"})
assert len(results) == 2
assert results[0].text.strip() == "Test Service"
assert results[0].attrs["href"] == "/services/service_1234"
assert results[1].text.strip() == "Test Template"
assert results[1].attrs["href"] == "/services/service_1234/templates/1234"


def test_find_ids_displays_users_found(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[{"id": "1234", "type": "user", "user_name": "Test User"}],
)
document = client_request.post(
"main.find_ids",
_data={"search": "1234"},
_expected_status=200,
)
get_records.assert_called_once_with("1234")
result = document.find("a", {"class": "browse-list-link"})

assert result.text.strip() == "Test User"
assert result.attrs["href"] == "/users/1234"


def test_find_ids_displays_jobs_found(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[
{
"id": "1234",
"type": "job",
"service_id": "service_1234",
"service_name": "Test Service",
"template_id": "template_1234",
"template_name": "Test Template",
}
],
)
document = client_request.post(
"main.find_ids",
_data={"search": "1234"},
_expected_status=200,
)
get_records.assert_called_once_with("1234")
results = document.find_all("a", {"class": "browse-list-link"})
assert len(results) == 3
assert results[0].text.strip() == "Test Service"
assert results[0].attrs["href"] == "/services/service_1234"
assert results[1].text.strip() == "Test Template"
assert results[1].attrs["href"] == "/services/service_1234/templates/template_1234"
assert results[2].text.strip() == "job"
assert results[2].attrs["href"] == "/services/service_1234/jobs/1234"


def test_find_ids_display_two_records(client_request, platform_admin_user, mocker):
client_request.login(platform_admin_user)
get_records = mocker.patch(
"app.support_api_client.find_ids",
return_value=[
{"id": "1234", "type": "service", "service_name": "Test Service"},
{"id": "5678", "type": "user", "user_name": "Test User"},
],
)
document = client_request.post("main.find_ids", _data={"search": "1234,5678"}, _expected_status=200)
get_records.assert_called_once_with("1234,5678")
results = document.find_all("a", {"class": "browse-list-link"})
assert len(results) == 2
assert [result.text.strip() for result in results] == [
"Test Service",
"Test User",
]
assert [result.attrs["href"] for result in results] == [
"/services/1234",
"/users/5678",
]

0 comments on commit 7a08447

Please sign in to comment.