Merge branch 'main' of https://github.com/GSA/notifications-admin into 1674-match-recent-batches-to-wireframe

This commit is contained in:
Jonathan Bobel
2024-08-13 16:51:18 -04:00
7 changed files with 82 additions and 2 deletions

View File

@@ -1,9 +1,11 @@
import csv
import itertools import itertools
import json import json
from collections import OrderedDict from collections import OrderedDict
from datetime import datetime from datetime import datetime
from io import StringIO
from flask import abort, flash, render_template, request, url_for from flask import Response, abort, flash, render_template, request, url_for
from notifications_python_client.errors import HTTPError from notifications_python_client.errors import HTTPError
from app import ( from app import (
@@ -70,6 +72,40 @@ def platform_admin():
) )
@main.route("/platform-admin/download-all-users")
@user_is_platform_admin
def download_all_users():
# Create a CSV string from the user data
users = user_api_client.get_all_users_detailed()
if len(users) == 0:
return "No data to download."
output = StringIO()
header = ["Name", "Email Address", "Phone Number", "Service"]
fieldnames = ["name", "email_address", "mobile_number", "service"]
writer = csv.DictWriter(
output,
fieldnames=fieldnames,
delimiter=",",
)
# Write custom header
writer.writerow(dict(zip(fieldnames, header)))
for user in users:
user_no_commas = {key: value.replace(",", "") for key, value in user.items()}
if user_no_commas["name"].startswith("e2e"):
continue
writer.writerow(user_no_commas)
csv_data = output.getvalue()
# Create a direct download response with the CSV data and appropriate headers
response = Response(csv_data, content_type="text/csv; charset=utf-8")
response.headers["Content-Disposition"] = "attachment; filename=users.csv"
return response
def is_over_threshold(number, total, threshold): def is_over_threshold(number, total, threshold):
percentage = number / total * 100 if total else 0 percentage = number / total * 100 if total else 0
return percentage > threshold return percentage > threshold

View File

@@ -123,6 +123,7 @@ class HeaderNavigation(Navigation):
"get_billing_report", "get_billing_report",
"get_users_report", "get_users_report",
"get_daily_volumes", "get_daily_volumes",
"download_all_users",
"get_daily_sms_provider_volumes", "get_daily_sms_provider_volumes",
"get_volumes_by_service", "get_volumes_by_service",
"organizations", "organizations",

View File

@@ -157,6 +157,10 @@ class UserApiClient(NotifyAdminAPIClient):
endpoint = "/user" endpoint = "/user"
return self.get(endpoint)["data"] return self.get(endpoint)["data"]
def get_all_users_detailed(self):
endpoint = "/user/report-all-users"
return self.get(endpoint)["data"]
@cache.delete("service-{service_id}") @cache.delete("service-{service_id}")
@cache.delete("service-{service_id}-template-folders") @cache.delete("service-{service_id}-template-folders")
@cache.delete("user-{user_id}") @cache.delete("user-{user_id}")

View File

@@ -31,4 +31,8 @@
<p> <p>
<a class="usa-link" href="{{ url_for('main.get_users_report') }}">Users Report</a> <a class="usa-link" href="{{ url_for('main.get_users_report') }}">Users Report</a>
</p> </p>
<p>
<a class="usa-link" href="{{ url_for('main.download_all_users') }}">Download All Users</a>
</p>
{% endblock %} {% endblock %}

View File

@@ -99,10 +99,11 @@ const copyGtmHead = () => {
// Task to copy images // Task to copy images
const copyImages = () => { const copyImages = () => {
return src(paths.src + 'images/**/*') return src(paths.src + 'images/**/*', { encoding: false })
.pipe(dest(paths.dist + 'images/')); .pipe(dest(paths.dist + 'images/'));
}; };
// Configure USWDS paths // Configure USWDS paths
uswds.settings.version = 3; uswds.settings.version = 3;
uswds.paths.dist.css = paths.dist + 'css'; uswds.paths.dist.css = paths.dist + 'css';

View File

@@ -1254,3 +1254,36 @@ def test_get_daily_sms_provider_volumes_report_calls_api_and_download_data(
+ "80" + "80"
+ "\r\n" + "\r\n"
) )
def test_download_all_users(client_request, platform_admin_user, mocker):
mocker.patch(
"app.main.views.platform_admin.user_api_client.get_all_users_detailed",
return_value=[
{
"name": "Johnny Sokko",
"email_address": "j_sokko@unicorn.gov",
"mobile_number": "15555555555",
"service": "Emperor, Guillotine, Service",
}
],
)
client_request.login(platform_admin_user)
response = client_request.get_response(
"main.download_all_users",
_data={},
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert "attachment" in response.headers["Content-Disposition"]
assert "filename" in response.headers["Content-Disposition"]
assert "users" in response.headers["Content-Disposition"]
my_response = response.get_data(as_text=True)
assert "Johnny Sokko" in my_response
assert "Emperor Guillotine Service" in my_response
assert "j_sokko@unicorn.gov" in my_response
assert "15555555555" in my_response

View File

@@ -68,6 +68,7 @@ EXCLUDED_ENDPOINTS = tuple(
"delivery_status_callback", "delivery_status_callback",
"design_content", "design_content",
"documentation", "documentation",
"download_all_users",
"download_notifications_csv", "download_notifications_csv",
"download_organization_usage_report", "download_organization_usage_report",
"edit_and_format_messages", "edit_and_format_messages",