+
-
Deployment Information
+ Active envelope generation tasks
{% set table_head = [
- {"text": "Name"},
- {"text": "Value"},
- {"text": "Description"},
+ {"text": "Packaged Workbasket ID"},
+ {"text": "Workbasket ID"},
+ {"text": "Time started"},
+ {"text": "Celery task ID"},
] %}
+ {% set table_rows = [] %}
- {% set table_rows = [
- [
- {"text": "GIT_BRANCH"},
- {"text": GIT_BRANCH},
- {"text": "Environment variable"},
- ],
- [
- {"text": "GIT_COMMIT"},
- {"text": GIT_COMMIT},
- {"text": "Environment variable"},
- ],
- [
- {"text": "APP_UPDATED_TIME"},
- {"text": "{:%d %b %Y, %H:%M}".format(APP_UPDATED_TIME|localtime)},
- {"text": "Estimated application deploy time"},
- ],
- [
- {"text": "LAST_TRANSACTION_TIME"},
- {"text": "{:%d %b %Y, %H:%M}".format(LAST_TRANSACTION_TIME|localtime)},
- {"text": "Last transaction change time"},
- ],
- ] %}
+ {% if celery_healthy %}
+ {% if active_envelope_generation %}
+ {% for generation_info in active_envelope_generation %}
+ {{ table_rows.append([
+ {"text": generation_info.packaged_workbasket_id},
+ {"text": generation_info.workbasket_id},
+ {"text": generation_info.date_time_start},
+ {"text": generation_info.task_id},
+ ]) or "" }}
+ {% endfor %}
+ {% else %}
+ {{ table_rows.append([
+ {
+ "text": "No active envelope generation tasks.",
+ "colspan": 4,
+ }
+ ]) or "" }}
+ {% endif %}
+ {% else %}
+ {{ table_rows.append([
+ {
+ "text": "Envelope generation task details are currently unavailable.",
+ "colspan": 4,
+ }
+ ]) or "" }}
+ {% endif %}
{{ govukTable({
"head": table_head,
@@ -116,6 +164,5 @@
}) }}
-{% endif %}
{% endblock %}
diff --git a/common/tests/test_views.py b/common/tests/test_views.py
index 98cabe92f..2dfc9fa7c 100644
--- a/common/tests/test_views.py
+++ b/common/tests/test_views.py
@@ -118,13 +118,39 @@ def test_healthcheck_response(response, status_code, status):
assert payload[1].tag == "response_time"
-def test_app_info(valid_user_client):
+def test_app_info_non_superuser(valid_user_client):
+ """Users without the superuser permission have a restricted view of
+ application information."""
response = valid_user_client.get(reverse("app-info"))
assert response.status_code == 200
page = BeautifulSoup(str(response.content), "html.parser")
- assert "Active business rule checks" in page.select("h2")[0].text
+ h2_elements = page.select(".info-section h2")
+
+ assert len(h2_elements) == 2
+ assert "Active business rule checks" in h2_elements[0].text
+ assert "Active envelope generation tasks" in h2_elements[1].text
+
+
+def test_app_info_superuser(superuser_client, new_workbasket):
+ """
+ Superusers should have an unrestricted view of application information.
+
+ The new_workbasket fixture provides access to transaction information in the
+ deployment infomation section.
+ """
+ response = superuser_client.get(reverse("app-info"))
+
+ assert response.status_code == 200
+
+ page = BeautifulSoup(str(response.content), "html.parser")
+ h2_elements = page.select(".info-section h2")
+
+ assert len(h2_elements) == 3
+ assert "Deployment information" in h2_elements[0].text
+ assert "Active business rule checks" in h2_elements[1].text
+ assert "Active envelope generation tasks" in h2_elements[2].text
def test_index_displays_footer_links(valid_user_client):
diff --git a/common/views.py b/common/views.py
index 74e829d01..8b95c115d 100644
--- a/common/views.py
+++ b/common/views.py
@@ -2,6 +2,7 @@
import os
import time
from datetime import datetime
+from typing import Dict
from typing import Optional
from typing import Tuple
from typing import Type
@@ -41,6 +42,7 @@
from common.models import Transaction
from common.pagination import build_pagination_list
from common.validators import UpdateType
+from publishing.models import PackagedWorkBasket
from workbaskets.models import WorkBasket
from workbaskets.views.mixins import WithCurrentWorkBasket
@@ -129,16 +131,54 @@ class AppInfoView(
TemplateView,
):
template_name = "common/app_info.jinja"
+ DATETIME_FORMAT = "%d %b %Y, %H:%M"
- def active_checks(self):
- results = []
+ def active_tasks(self) -> Dict:
inspect = app.control.inspect()
if not inspect:
- return results
+ return {}
active_tasks = inspect.active()
if not active_tasks:
- return results
+ return {}
+
+ return active_tasks
+
+ @staticmethod
+ def timestamp_to_datetime_string(timestamp):
+ return make_aware(
+ datetime.fromtimestamp(timestamp),
+ ).strftime(AppInfoView.DATETIME_FORMAT)
+
+ def active_envelope_generation(self, active_tasks):
+ results = []
+
+ for _, task_info_list in active_tasks.items():
+ for task_info in task_info_list:
+ if task_info.get("name") == "publishing.tasks.create_xml_envelope_file":
+ date_time_start = AppInfoView.timestamp_to_datetime_string(
+ task_info.get("time_start"),
+ )
+
+ packaged_workbasket_id = task_info.get("args", [""])[0]
+ packaged_workbasket = PackagedWorkBasket.objects.get(
+ id=packaged_workbasket_id,
+ )
+ workbasket_id = packaged_workbasket.workbasket.id
+
+ results.append(
+ {
+ "task_id": task_info.get("id"),
+ "packaged_workbasket_id": packaged_workbasket_id,
+ "workbasket_id": workbasket_id,
+ "date_time_start": date_time_start,
+ },
+ )
+
+ return results
+
+ def active_checks(self, active_tasks):
+ results = []
for _, task_info_list in active_tasks.items():
for task_info in task_info_list:
@@ -146,11 +186,9 @@ def active_checks(self):
task_info.get("name")
== "workbaskets.tasks.call_check_workbasket_sync"
):
- date_time_start = make_aware(
- datetime.fromtimestamp(
- task_info.get("time_start"),
- ),
- ).strftime("%Y-%m-%d, %H:%M:%S")
+ date_time_start = AppInfoView.timestamp_to_datetime_string(
+ task_info.get("time_start"),
+ )
workbasket_id = task_info.get("args", [""])[0]
workbasket = WorkBasket.objects.get(id=workbasket_id)
@@ -170,19 +208,28 @@ def active_checks(self):
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
try:
- data["active_checks"] = self.active_checks()
+ active_tasks = self.active_tasks()
data["celery_healthy"] = True
+ data["active_checks"] = self.active_checks(active_tasks)
+ data["active_envelope_generation"] = self.active_envelope_generation(
+ active_tasks,
+ )
except kombu.exceptions.OperationalError as oe:
data["celery_healthy"] = False
if self.request.user.is_superuser:
data["GIT_BRANCH"] = os.getenv("GIT_BRANCH", "Unavailable")
data["GIT_COMMIT"] = os.getenv("GIT_COMMIT", "Unavailable")
- data["APP_UPDATED_TIME"] = datetime.fromtimestamp(
+ data["APP_UPDATED_TIME"] = AppInfoView.timestamp_to_datetime_string(
os.path.getmtime(__file__),
)
+ last_transaction = Transaction.objects.order_by("updated_at").last()
data["LAST_TRANSACTION_TIME"] = (
- Transaction.objects.order_by("-updated_at").first().updated_at
+ format(
+ last_transaction.updated_at.strftime(AppInfoView.DATETIME_FORMAT),
+ )
+ if last_transaction
+ else "No transactions"
)
return data