mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-11 10:28:41 -04:00
Refactored polling for status page
This commit is contained in:
+66
-113
@@ -10,7 +10,6 @@ from flask import (
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
session,
|
||||
stream_with_context,
|
||||
url_for,
|
||||
)
|
||||
@@ -23,8 +22,8 @@ from app import (
|
||||
notification_api_client,
|
||||
service_api_client,
|
||||
)
|
||||
from app.enums import JobStatus, NotificationStatus, ServicePermission
|
||||
from app.formatters import get_time_left, message_count_noun
|
||||
from app.enums import NotificationStatus, ServicePermission
|
||||
from app.formatters import message_count_noun
|
||||
from app.main import main
|
||||
from app.main.forms import SearchNotificationsForm
|
||||
from app.models.job import Job
|
||||
@@ -36,6 +35,7 @@ from app.utils.pagination import (
|
||||
get_page_from_request,
|
||||
)
|
||||
from app.utils.user import user_has_permissions
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from notifications_utils.template import EmailPreviewTemplate, SMSBodyPreviewTemplate
|
||||
|
||||
|
||||
@@ -61,13 +61,35 @@ def view_job(service_id, job_id):
|
||||
filter_args["status"] = set_status_filters(filter_args)
|
||||
api_public_url = os.environ.get("API_PUBLIC_URL")
|
||||
|
||||
notifications = None
|
||||
more_than_one_page = False
|
||||
if job.finished_processing:
|
||||
notifications_data = job.get_notifications(status=filter_args["status"])
|
||||
notifications = list(
|
||||
add_preview_of_content_to_notifications(
|
||||
notifications_data.get("notifications", [])
|
||||
)
|
||||
)
|
||||
more_than_one_page = bool(notifications_data.get("links", {}).get("next"))
|
||||
|
||||
return render_template(
|
||||
"views/jobs/job.html",
|
||||
api_public_url=api_public_url,
|
||||
FEATURE_SOCKET_ENABLED=current_app.config["FEATURE_SOCKET_ENABLED"],
|
||||
job=job,
|
||||
status=request.args.get("status", ""),
|
||||
partials=get_job_partials(job),
|
||||
counts=_get_job_counts(job),
|
||||
notifications=notifications,
|
||||
more_than_one_page=more_than_one_page,
|
||||
download_link=(
|
||||
url_for(
|
||||
".view_job_csv",
|
||||
service_id=service_id,
|
||||
job_id=job_id,
|
||||
status=request.args.get("status"),
|
||||
)
|
||||
if job.finished_processing
|
||||
else None
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -109,58 +131,28 @@ def cancel_job(service_id, job_id):
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>/status.json")
|
||||
@user_has_permissions()
|
||||
def view_job_status_poll(service_id, job_id):
|
||||
"""
|
||||
DISABLED: Lightweight polling endpoint no longer supported.
|
||||
Use manual page refresh instead.
|
||||
"""
|
||||
current_app.logger.info(f"Disabled lightweight polling endpoint accessed for job {job_id[:8]} - returning 410 Gone")
|
||||
abort(410, "Lightweight polling endpoint disabled. Please refresh the page manually.")
|
||||
from app.notify_client.job_api_client import job_api_client
|
||||
|
||||
# Original polling code - commented out for manual refresh mode
|
||||
# start_time = time.time()
|
||||
#
|
||||
# # Use new lightweight status endpoint
|
||||
# try:
|
||||
# status_data = job_api_client.get_job_status(service_id, job_id)
|
||||
#
|
||||
# # Validate the response has expected fields
|
||||
# required_fields = ["sent_count", "failed_count", "pending_count", "total_count", "processing_finished"]
|
||||
# if all(key in status_data for key in required_fields):
|
||||
# response_data = {
|
||||
# "sent_count": status_data["sent_count"],
|
||||
# "failed_count": status_data["failed_count"],
|
||||
# "pending_count": status_data["pending_count"],
|
||||
# "total_count": status_data["total_count"],
|
||||
# "finished": status_data["processing_finished"],
|
||||
# }
|
||||
# processed_count = status_data["sent_count"] + status_data["failed_count"]
|
||||
# else:
|
||||
# current_app.logger.error(f"Status endpoint returned invalid response for job {job_id[:8]}: {status_data}")
|
||||
# abort(500, "Invalid status response from API")
|
||||
#
|
||||
# except Exception as e:
|
||||
# current_app.logger.error(f"Status endpoint failed for job {job_id[:8]}: {e}")
|
||||
# abort(500, "Status endpoint unavailable")
|
||||
#
|
||||
# response_time_ms = round((time.time() - start_time) * 1000, 2)
|
||||
# response_json = json.dumps(response_data)
|
||||
# response_size_bytes = len(response_json.encode("utf-8"))
|
||||
#
|
||||
# current_app.logger.info(
|
||||
# f"Poll status request - job_id={job_id[:8]} "
|
||||
# f"response_size={response_size_bytes}b "
|
||||
# f"response_time={response_time_ms}ms "
|
||||
# f"progress={processed_count}/{response_data['total_count']}"
|
||||
# )
|
||||
#
|
||||
# return jsonify(response_data)
|
||||
try:
|
||||
api_response = job_api_client.get_job_status(service_id, job_id)
|
||||
except HTTPError as e:
|
||||
current_app.logger.error(f"API error fetching job status: {e.status_code} - {e.message}")
|
||||
if e.status_code == 404:
|
||||
abort(404)
|
||||
elif e.status_code >= 500:
|
||||
abort(503, "Service temporarily unavailable")
|
||||
else:
|
||||
abort(500, "Failed to fetch job status")
|
||||
|
||||
response_data = {
|
||||
"total": api_response.get("total", 0),
|
||||
"delivered": api_response.get("delivered", 0),
|
||||
"failed": api_response.get("failed", 0),
|
||||
"pending": api_response.get("pending", 0),
|
||||
"finished": api_response.get("finished", False),
|
||||
}
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>.json")
|
||||
@user_has_permissions()
|
||||
def view_job_updates(service_id, job_id):
|
||||
job = Job.from_id(job_id, service_id=service_id)
|
||||
return jsonify(**get_job_partials(job))
|
||||
return jsonify(response_data)
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/notifications", methods=["GET", "POST"])
|
||||
@@ -183,8 +175,6 @@ def view_notifications(service_id, message_type=None):
|
||||
things_you_can_search_by={
|
||||
"email": ["email address"],
|
||||
"sms": ["phone number"],
|
||||
# We say recipient here because combining all 3 types, plus
|
||||
# reference gets too long for the hint text
|
||||
None: ["recipient"],
|
||||
}.get(message_type)
|
||||
+ {
|
||||
@@ -288,6 +278,11 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
|
||||
limit_days=service_data_retention_days,
|
||||
to=search_term,
|
||||
)
|
||||
|
||||
notifications_list = notifications.get(
|
||||
"notifications", notifications.get("items", [])
|
||||
)
|
||||
|
||||
url_args = {"message_type": message_type, "status": request.args.get("status")}
|
||||
prev_page = None
|
||||
if "links" in notifications and notifications["links"].get("prev", None):
|
||||
@@ -296,7 +291,7 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
|
||||
)
|
||||
next_page = None
|
||||
|
||||
total_items = notifications.get("total", 0)
|
||||
total_items = notifications.get("total", len(notifications_list))
|
||||
page_size = notifications.get("page_size", 50)
|
||||
total_pages = (total_items + page_size - 1) // page_size
|
||||
if (
|
||||
@@ -334,7 +329,7 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
|
||||
"notifications": render_template(
|
||||
"views/activity/notifications.html",
|
||||
notifications=list(
|
||||
add_preview_of_content_to_notifications(notifications["notifications"])
|
||||
add_preview_of_content_to_notifications(notifications_list)
|
||||
),
|
||||
page=page,
|
||||
limit_days=service_data_retention_days,
|
||||
@@ -450,63 +445,18 @@ def _get_job_counts(job):
|
||||
]
|
||||
|
||||
|
||||
def get_job_partials(job):
|
||||
filter_args = parse_filter_args(request.args)
|
||||
filter_args["status"] = set_status_filters(filter_args)
|
||||
notifications = job.get_notifications(status=filter_args["status"])
|
||||
number_of_days = "seven_day"
|
||||
counts = render_template(
|
||||
"partials/count.html",
|
||||
counts=_get_job_counts(job),
|
||||
status=filter_args["status"],
|
||||
notifications_deleted=(
|
||||
job.status == JobStatus.FINISHED and not notifications["notifications"]
|
||||
),
|
||||
)
|
||||
service_data_retention_days = current_service.get_days_of_retention(
|
||||
job.template_type, number_of_days
|
||||
)
|
||||
|
||||
if request.referrer is not None:
|
||||
session["arrived_from_preview_page"] = ("check" in request.referrer) or (
|
||||
"help=0" in request.referrer
|
||||
)
|
||||
else:
|
||||
session["arrived_from_preview_page"] = False
|
||||
|
||||
arrived_from_preview_page_url = session.get("arrived_from_preview_page", False)
|
||||
|
||||
return {
|
||||
"counts": counts,
|
||||
"notifications": render_template(
|
||||
"partials/jobs/notifications.html",
|
||||
notifications=list(
|
||||
add_preview_of_content_to_notifications(notifications["notifications"])
|
||||
),
|
||||
more_than_one_page=bool(notifications.get("links", {}).get("next")),
|
||||
download_link=url_for(
|
||||
".view_job_csv",
|
||||
service_id=current_service.id,
|
||||
job_id=job.id,
|
||||
status=request.args.get("status"),
|
||||
),
|
||||
time_left=get_time_left(
|
||||
job.created_at, service_data_retention_days=service_data_retention_days
|
||||
),
|
||||
job=job,
|
||||
service_data_retention_days=service_data_retention_days,
|
||||
),
|
||||
"status": render_template(
|
||||
"partials/jobs/status.html",
|
||||
job=job,
|
||||
arrived_from_preview_page_url=arrived_from_preview_page_url,
|
||||
),
|
||||
"finished": job.finished_processing,
|
||||
}
|
||||
|
||||
|
||||
def add_preview_of_content_to_notifications(notifications):
|
||||
for notification in notifications:
|
||||
if "template" not in notification and "template_name" in notification:
|
||||
notification["template"] = {
|
||||
"name": notification.get("template_name", ""),
|
||||
"template_type": "sms",
|
||||
"content": notification.get("template_name", ""),
|
||||
}
|
||||
|
||||
if "content" not in notification:
|
||||
notification["content"] = notification.get("template_name", "")
|
||||
|
||||
yield (
|
||||
dict(
|
||||
preview_of_content=get_preview_of_content(notification), **notification
|
||||
@@ -515,6 +465,9 @@ def add_preview_of_content_to_notifications(notifications):
|
||||
|
||||
|
||||
def get_preview_of_content(notification):
|
||||
if "template" not in notification:
|
||||
return notification.get("template_name", "")
|
||||
|
||||
if notification["template"].get("redact_personalisation"):
|
||||
notification["personalisation"] = {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user