Skip to content

Commit

Permalink
Add the ability to copy a link/url from the pdf that leads to the pag…
Browse files Browse the repository at this point in the history
…e where you can download the same report with the right filters set.

Signed-off-by: Donny Peeters <[email protected]>
  • Loading branch information
Donnype committed Sep 5, 2023
1 parent 9a0e9a9 commit b63cc5a
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 19 deletions.
8 changes: 8 additions & 0 deletions keiko/templates/bevindingenrapport/template.tex
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ \section{Samenvatting}
{% endfor %}
\end{longtable}

{% if report_url.startswith('http') %}
\noindent Kopieer \href{@@{ report_url }@@}{deze link} om dit rapport te reproduceren.
{% else %}
\noindent Gebruik de volgende URL om dit rapport te reproduceren:

\{uw OpenKAT domein\} \url{@@{ report_url }@@}
{% endif %}

\bgroup{}
\def\arraystretch{1.2}
\section{Totalen}
Expand Down
83 changes: 78 additions & 5 deletions rocky/rocky/keiko.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import re
import time
from datetime import datetime, timezone
from datetime import date, datetime, timezone
from http import HTTPStatus
from io import BytesIO
from typing import Any, BinaryIO, Dict, List, Optional
from typing import Any, BinaryIO, Dict, Iterable, List, Optional

import requests
from django.conf import settings
from django.urls import reverse
from django.utils import translation
from requests import HTTPError
from tools.ooi_helpers import get_ooi_dict
from tools.view_helpers import get_ooi_url, url_with_querystring

from octopoes.models import OOI
from octopoes.models.ooi.findings import Finding, FindingType, RiskLevelSeverity
Expand Down Expand Up @@ -77,6 +80,75 @@ def health(self) -> ServiceHealth:
keiko_client = KeikoClient(settings.KEIKO_API, settings.KEIKO_REPORT_TIMEOUT)


class ReportQuery:
def to_dict(self) -> Dict:
raise NotImplementedError

def to_url(self) -> str:
raise NotImplementedError


class FindingReportQuery(ReportQuery):
def __init__(
self,
organization: str,
observed_at: date,
severities: Iterable[RiskLevelSeverity],
language: str = "nl",
origin: str = "",
):
self.organization = organization
self.observed_at = observed_at
self.severities = severities
self.language = language
self.origin = origin

def to_dict(self) -> Dict:
return {
"observed_at": str(self.observed_at),
"severities": [severity.value for severity in self.severities],
}

def to_url(self) -> str:
translation.activate(self.language)
url = reverse("finding_list", kwargs={"organization_code": self.organization})
translation.deactivate()

with_querystring = url_with_querystring(
url, True, observed_at=self.observed_at, severity=[severity.value for severity in self.severities]
)

return f"{self.origin}{with_querystring}"


class OOIReportQuery(ReportQuery):
def __init__(
self, organization: str, observed_at: date, ooi: OOI, depth: int, language: str = "nl", origin: str = ""
):
self.organization = organization
self.observed_at = observed_at
self.ooi = ooi
self.depth = depth
self.language = language
self.origin = origin

def to_dict(self) -> Dict:
return {
"observed_at": str(self.observed_at),
"ooi": self.ooi.reference,
"depth": self.depth,
}

def to_url(self) -> str:
translation.activate(self.language)
url = get_ooi_url(
"ooi_report", self.ooi.primary_key, self.organization, observed_at=str(self.observed_at), depth=self.depth
)
translation.deactivate()

return f"{self.origin}{url}"


class ReportsService:
FILE_NAME_FRIENDLY_DATE_FORMAT = "%Y_%d_%mT%H_%M_%S_%f_%z"

Expand All @@ -89,14 +161,15 @@ def get_report(
source_type: str,
source_value: str,
store: Dict,
filters: Dict,
filters: ReportQuery,
) -> BinaryIO:
report_data = build_findings_list_from_store(store) # reuse existing dict structure
report_data["findings_grouped"] = _ooi_field_as_string(report_data["findings_grouped"], store)
report_data["valid_time"] = str(valid_time)
report_data["report_source_type"] = source_type
report_data["report_source_value"] = source_value
report_data["filters"] = filters
report_data["filters"] = filters.to_dict()
report_data["report_url"] = filters.to_url()

report_id = self.keiko_client.generate_report("bevindingenrapport", report_data, "dutch.hiero.csv")

Expand All @@ -107,7 +180,7 @@ def get_organization_finding_report(
valid_time: datetime,
organization_name: str,
findings_metadata: List[Dict[str, Any]],
filters: Dict,
filters: FindingReportQuery,
) -> BinaryIO:
store = {}
for item in findings_metadata:
Expand Down
23 changes: 15 additions & 8 deletions rocky/rocky/views/ooi_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
)
from octopoes.models.ooi.dns.zone import Hostname
from rocky.keiko import (
FindingReportQuery,
GeneratingReportFailed,
OOIReportQuery,
ReportNotFoundException,
ReportsService,
build_findings_list_from_store,
Expand Down Expand Up @@ -88,10 +90,13 @@ def get(self, request, *args, **kwargs):
self.ooi.object_type,
self.ooi.human_readable,
self.tree.store,
{
"ooi": self.ooi.reference,
"valid_time": str(valid_time),
},
OOIReportQuery(
self.organization.code,
valid_time.date(),
self.ooi,
self.depth,
origin=f"{request.scheme}://{request.get_host()}",
),
)
except GeneratingReportFailed:
messages.error(self.request, _("Generating report failed. See Keiko logs for more information."))
Expand Down Expand Up @@ -129,10 +134,12 @@ def get(self, request, *args, **kwargs):
self.get_observed_at(),
self.organization.name,
generate_findings_metadata(findings, severities),
{
"severities": [severity.value for severity in severities],
"valid_time": str(self.get_observed_at()),
},
FindingReportQuery(
self.organization.code,
self.get_observed_at().date(),
severities,
origin=f"{request.scheme}://{request.get_host()}",
),
)
except GeneratingReportFailed:
messages.error(request, _("Generating report failed. See Keiko logs for more information."))
Expand Down
1 change: 1 addition & 0 deletions rocky/tests/objects/test_objects_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def test_ooi_pdf_report(rf, client_member, mock_organization_view_octopoes, mock
mock_datetime = mocker.patch("rocky.keiko.datetime")
mock_mixin_datetime = mocker.patch("rocky.views.mixins.datetime")
mock_datetime.now().strftime.return_value = dt_in_filename
mock_mixin_datetime.now().date.return_value = "2010-10-10"
mock_mixin_datetime.now().strftime.return_value = dt_in_filename

# Setup Keiko mock
Expand Down
9 changes: 5 additions & 4 deletions rocky/tools/management/commands/generate_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from octopoes.connector.octopoes import OctopoesAPIConnector
from octopoes.models.ooi.findings import RiskLevelSeverity
from rocky.keiko import ReportsService, keiko_client
from rocky.keiko import FindingReportQuery, ReportsService, keiko_client
from rocky.views.finding_list import generate_findings_metadata
from rocky.views.mixins import FindingList
from tools.models import Organization
Expand Down Expand Up @@ -53,6 +53,7 @@ def handle(self, *args, **options):
sys.exit(1)

organization = self.get_organization(**options)
severities = [severity for severity in RiskLevelSeverity if severity >= options["min_severity"]]

if not organization:
self.stderr.write("Provider either a valid primary key of an organization or a valid code (not both)")
Expand All @@ -62,7 +63,8 @@ def handle(self, *args, **options):
report = ReportsService(keiko_client).get_organization_finding_report(
valid_time,
organization.name,
self.get_findings_metadata(organization, valid_time, options),
self.get_findings_metadata(organization, valid_time, severities),
FindingReportQuery(organization.code, valid_time.date(), severities),
)

if options["output"]:
Expand All @@ -73,8 +75,7 @@ def handle(self, *args, **options):
self.stdout.buffer.write(report.read())

@staticmethod
def get_findings_metadata(organization, valid_time, options) -> List[Dict[str, Any]]:
severities = [severity for severity in RiskLevelSeverity if severity >= options["min_severity"]]
def get_findings_metadata(organization, valid_time, severities) -> List[Dict[str, Any]]:
findings = FindingList(
OctopoesAPIConnector(settings.OCTOPOES_API, organization.code),
valid_time,
Expand Down
4 changes: 2 additions & 2 deletions rocky/tools/view_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def generate_job_id():
return str(uuid.uuid4())


def url_with_querystring(path, **kwargs) -> str:
def url_with_querystring(path, doseq=False, **kwargs) -> str:
parsed_route = urlparse(path)

return str(
Expand All @@ -45,7 +45,7 @@ def url_with_querystring(path, **kwargs) -> str:
parsed_route.netloc,
parsed_route.path,
parsed_route.params,
urlencode(kwargs),
urlencode(kwargs, doseq),
parsed_route.fragment,
)
)
Expand Down

0 comments on commit b63cc5a

Please sign in to comment.