From d0346a3ef87fb49555f9434ea099f240cdf51593 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Wed, 15 May 2024 18:57:57 +0200 Subject: [PATCH] feat: create action plan pdf --- .../core/templates/core/action_plan_pdf.html | 60 +++++++++++++++++++ backend/core/templatetags/core_extras.py | 7 +++ backend/core/views.py | 43 +++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 backend/core/templates/core/action_plan_pdf.html diff --git a/backend/core/templates/core/action_plan_pdf.html b/backend/core/templates/core/action_plan_pdf.html new file mode 100644 index 000000000..875c2dfd5 --- /dev/null +++ b/backend/core/templates/core/action_plan_pdf.html @@ -0,0 +1,60 @@ +{% extends 'core/base_pdf.html' %} +{% block content %} +{% load i18n core_extras %} + + + +
+

Action plan

+
+

{% trans "Domain" %}: {{ compliance_assessment.project.folder }}

+

/

+

{% trans "Project" %}: {{ compliance_assessment.project.name }}

+

/

+

{% trans "Audit" %}: {{ compliance_assessment.name }} - {{ compliance_assessment.version }}

+
+

{% trans "Associated applied controls" %}:

+

{% trans "Separated by status and sorted by eta" %}

+ {% for status, applied_controls in context.items%} + {% for status_color, color in color_map.items %} + {% if status_color == status %} +

{% trans status|title %}:

+ {% endif %} + {% endfor %} +
+
+ + + + + + + + + + + + + + {% for applied_control in applied_controls %} + + + + + + + + + + {% endfor %} + +
{% trans "Name" %}{% trans "Description" %}{% trans "Category" %}{% trans "ETA" %}{% trans "Expiry date" %}{% trans "Effort" %}{% trans "Requirements count" %}
{{ applied_control.name }}{{ applied_control.description }}{{ applied_control.category }}{{ applied_control.eta }}{{ applied_control.expiry_date }}{{ applied_control.effort }}{% get_requirements_count applied_control compliance_assessment %}
+
+
+ {% endfor %} +
+{% endblock %} diff --git a/backend/core/templatetags/core_extras.py b/backend/core/templatetags/core_extras.py index 0aebc1e5b..90f069197 100644 --- a/backend/core/templatetags/core_extras.py +++ b/backend/core/templatetags/core_extras.py @@ -2,6 +2,7 @@ from ciso_assistant.settings import VERSION, BUILD, DEBUG from core.utils import COUNTRY_FLAGS, LANGUAGES +from core.models import RequirementAssessment register = template.Library() @@ -15,6 +16,12 @@ def app_version(): def app_build(): return f"{BUILD} (dev)" if DEBUG else BUILD +@register.simple_tag() +def get_requirements_count(applied_control, compliance_assessment): + return RequirementAssessment.objects.filter( + compliance_assessment=compliance_assessment + ).filter(applied_controls=applied_control).count() + @register.filter("class") def _class(obj): diff --git a/backend/core/views.py b/backend/core/views.py index 3b63a2bb0..64a8ceb89 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -1226,6 +1226,49 @@ def action_plan(self, request, pk): applied_control ) return Response(response) + + @action(detail=True, name="Get action plan PDF") + def action_plan_pdf(self, request, pk): + (object_ids_view, _, _) = RoleAssignment.get_accessible_object_ids( + Folder.get_root_folder(), request.user, ComplianceAssessment + ) + if UUID(pk) in object_ids_view: + context = { + "planned": list(), + "active": list(), + "inactive": list(), + "no status": list(), + } + color_map = { + "planned": "#93c5fd", + "active": "#86efac", + "inactive": "#fca5a5", + "no status": "#e5e7eb", + } + compliance_assessment_object = self.get_object() + requirement_assessments_objects = ( + compliance_assessment_object.get_requirement_assessments() + ) + applied_controls = AppliedControl.objects.filter( + requirement_assessments__in=requirement_assessments_objects + ).distinct().order_by("eta") + for applied_control in applied_controls: + context[applied_control.status].append( + applied_control + ) if applied_control.status else context["no status"].append( + applied_control + ) + data = { + "color_map": color_map, + "context": context, + "compliance_assessment": compliance_assessment_object, + } + html = render_to_string("core/action_plan_pdf.html", data) + pdf_file = HTML(string=html).write_pdf() + response = HttpResponse(pdf_file, content_type="application/pdf") + return response + else: + return Response({"error": "Permission denied"}) def perform_create(self, serializer): """