From 2fd2f11bf99adea69822d61624c7706bda127db3 Mon Sep 17 00:00:00 2001 From: Rieven Date: Wed, 3 Jul 2024 16:35:05 +0200 Subject: [PATCH 01/10] changes for post request for the rest of the report flow --- .../templates/forms/report_form_fields.html | 11 +- .../templates/partials/report_setup_scan.html | 2 + .../partials/report_types_selection.html | 3 +- rocky/reports/views/aggregate_report.py | 89 +-------- rocky/reports/views/base.py | 15 +- rocky/reports/views/generate_report.py | 125 +------------ rocky/reports/views/mixins.py | 175 ++++++++++++++++++ rocky/reports/views/multi_report.py | 2 +- 8 files changed, 215 insertions(+), 207 deletions(-) create mode 100644 rocky/reports/views/mixins.py diff --git a/rocky/reports/templates/forms/report_form_fields.html b/rocky/reports/templates/forms/report_form_fields.html index b6fd8ed360f..461594e93b4 100644 --- a/rocky/reports/templates/forms/report_form_fields.html +++ b/rocky/reports/templates/forms/report_form_fields.html @@ -1,7 +1,7 @@ -{% for ooi in selected_oois %}{% endfor %} +{% for ooi in selected_oois %}{% endfor %} {% for ooi_type in ooi_types_selection %}{% endfor %} {% for clearance_level in clearance_levels_selection %} @@ -9,9 +9,14 @@ {% for clearance_type in clearance_types_selection %} {% endfor %} +{% if selected_report_types %} + {% for report_type in selected_report_types %} + + {% endfor %} +{% endif %} {% if plugins.required %} {% for required_plugin in plugins.required %} - + {% endfor %} {% endif %} -{% if request.GET.page %}{% endif %} +{% if request.GET.page %}{% endif %} diff --git a/rocky/reports/templates/partials/report_setup_scan.html b/rocky/reports/templates/partials/report_setup_scan.html index 8984a4809c7..3977c812500 100644 --- a/rocky/reports/templates/partials/report_setup_scan.html +++ b/rocky/reports/templates/partials/report_setup_scan.html @@ -94,6 +94,8 @@

{% translate "Suggested plugins" %}

{% endif %}
{% csrf_token %} + {% include "forms/report_form_fields.html" %} + diff --git a/rocky/reports/templates/partials/report_types_selection.html b/rocky/reports/templates/partials/report_types_selection.html index 96ed76e15d1..0bc6c198735 100644 --- a/rocky/reports/templates/partials/report_types_selection.html +++ b/rocky/reports/templates/partials/report_types_selection.html @@ -56,8 +56,9 @@

{% translate "Available report types" %} ({{ available_report_types|length }

{% translate "All report types that are available for your selection." %}

{% translate "Toggle all report types" %} + {% csrf_token %} {% include "forms/report_form_fields.html" %}
diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 49de8995055..2fd21cf8707 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -1,16 +1,12 @@ -from collections.abc import Sequence from typing import Any -from django.contrib import messages from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ -from octopoes.models import ScanProfileType -from octopoes.models.ooi.reports import Report as ReportOOI -from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport, aggregate_reports +from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport from reports.report_types.definitions import Report from reports.report_types.helpers import get_ooi_types_from_aggregate_report, get_report_types_from_aggregate_report from reports.views.base import ( @@ -21,6 +17,7 @@ ReportTypeSelectionView, get_selection, ) +from reports.views.mixins import SaveAggregateReportMixin from reports.views.view_helpers import AggregateReportStepsMixin from rocky.views.ooi_view import BaseOOIListView @@ -134,72 +131,6 @@ def get_context_data(self, **kwargs): return context -class SaveAggregateReportMixin(ReportPluginView): - def save_report(self) -> ReportOOI: - input_oois = self.get_oois() - - aggregate_report, post_processed_data, report_data, report_errors = aggregate_reports( - self.octopoes_api_connector, - input_oois, - self.selected_report_types, - self.observed_at, - ) - - # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error - if report_errors: - report_types = ", ".join(set(report_errors)) - date = self.observed_at.date() - error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { - "report_types": report_types, - "date": date, - } - messages.add_message(self.request, messages.ERROR, error_message) - - observed_at = self.get_observed_at() - - post_processed_data["plugins"] = self.get_plugin_data_for_saving() - post_processed_data["oois"] = [] - for input_ooi in input_oois: - post_processed_data["oois"].append( - { - "name": input_ooi.human_readable, - "type": input_ooi.object_type, - "scan_profile_level": input_ooi.scan_profile.level.value if input_ooi.scan_profile else 0, - "scan_profile_type": ( - input_ooi.scan_profile.scan_profile_type if input_ooi.scan_profile else ScanProfileType.EMPTY - ), - } - ) - - post_processed_data["report_types"] = [] - for report_type in self.report_types: - post_processed_data["report_types"].append( - { - "name": str(report_type.name), - "description": str(report_type.description), - "label_style": report_type.label_style, - } - ) - - # Create the report - report_data_raw_id = self.save_report_raw(data=post_processed_data) - report_ooi = self.save_report_ooi( - report_data_raw_id=report_data_raw_id, - report_type=type(aggregate_report), - input_oois=[ooi.primary_key for ooi in input_oois], - parent=None, - has_parent=False, - observed_at=observed_at, - ) - - # Save the child reports to bytes - for ooi, types in report_data.items(): - for report_type, data in types.items(): - self.save_report_raw(data=data) - - return report_ooi - - class SetupScanAggregateReportView( SaveAggregateReportMixin, AggregateReportStepsMixin, BreadcrumbsAggregateReportView, ReportPluginView ): @@ -212,11 +143,6 @@ class SetupScanAggregateReportView( current_step = 3 def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - if not self.selected_report_types: - messages.error(self.request, _("Select at least one report type to proceed.")) - return redirect( - reverse("aggregate_report_select_report_types", kwargs=self.get_kwargs()) + get_selection(self.request) - ) if not self.report_has_required_plugins() or self.plugins_enabled(): report_ooi = self.save_report() @@ -230,15 +156,20 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: return super().get(request, *args, **kwargs) + def post(self, request, *args, **kwargs): + if not self.report_type_selection_is_valid(): + return redirect(self.get_previous()) + return self.get(request, *args, **kwargs) + class SaveAggregateReportView(SaveAggregateReportMixin, BreadcrumbsAggregateReportView, ReportPluginView): """ Save the report and redirect to the saved report """ - current_step = 6 - ooi_types = get_ooi_types_from_aggregate_report(AggregateOrganisationReport) - report_types: Sequence[type[Report]] + template_name = "aggregate_report.html" + breadcrumbs_step = 6 + current_step = 4 def post(self, request, *args, **kwargs): report_ooi = self.save_report() diff --git a/rocky/reports/views/base.py b/rocky/reports/views/base.py index 69528fa211e..5764da7a069 100644 --- a/rocky/reports/views/base.py +++ b/rocky/reports/views/base.py @@ -171,8 +171,7 @@ def get_context_data(self, **kwargs): class ReportTypeSelectionView(TemplateView): """ - Shows report types based on the OOIs selections. - Handles all request for report types selections. + Shows report types and handles selections and requests. """ def setup(self, request, *args, **kwargs): @@ -209,15 +208,20 @@ def get_report_types(reports: set[type[BaseReportType]]) -> list[dict[str, str]] for report_type in reports ] - def report_type_selection_is_valid(self): + def report_type_selection_is_valid(self) -> bool: is_valid = True if not self.selected_report_types: is_valid = False messages.error(self.request, _("Select at least one report type to proceed.")) return is_valid + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["selected_report_types"] = self.selected_report_types + return context -class ReportPluginView(OrganizationView, ReportTypeSelectionView): + +class ReportPluginView(OOISelectionView, ReportTypeSelectionView): """ This view shows the required and optional plugins. Needs ReportTypeView to know which report type is selected to get their plugins. @@ -386,12 +390,9 @@ def get_observed_at(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["created_at"] = datetime.now() - context["selected_oois"] = self.selected_oois - context["selected_report_types"] = self.selected_report_types context["plugins"] = self.plugins context["all_plugins_enabled"] = self.all_plugins_enabled context["plugin_data"] = self.get_plugin_data() - context["oois"] = self.get_oois() return context diff --git a/rocky/reports/views/generate_report.py b/rocky/reports/views/generate_report.py index ac36abbf9ad..181f7ee27f3 100644 --- a/rocky/reports/views/generate_report.py +++ b/rocky/reports/views/generate_report.py @@ -1,20 +1,12 @@ -from collections.abc import Sequence from typing import Any -from django.contrib import messages from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect from django.urls import reverse from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ -from django.views.generic import TemplateView -from octopoes.models import Reference -from octopoes.models.exception import ObjectNotFoundException, TypeNotFound -from octopoes.models.ooi.reports import Report as ReportOOI -from reports.report_types.concatenated_report.report import ConcatenatedReport -from reports.report_types.definitions import Report -from reports.report_types.helpers import REPORTS, get_ooi_types_with_report, get_report_by_id, get_report_types_for_oois +from reports.report_types.helpers import get_ooi_types_with_report, get_report_types_for_oois from reports.views.base import ( REPORTS_PRE_SELECTION, OOISelectionView, @@ -23,6 +15,7 @@ ReportTypeSelectionView, get_selection, ) +from reports.views.mixins import SaveGenerateReportMixin from reports.views.view_helpers import GenerateReportStepsMixin from rocky.views.ooi_view import BaseOOIListView @@ -115,109 +108,11 @@ def get_context_data(self, **kwargs): return context -class SaveGenerateReportMixin(ReportPluginView): - def save_report(self) -> ReportOOI: - error_reports = [] - report_data: dict[str, dict[str, dict[str, Any]]] = {} - by_type: dict[str, list[str]] = {} - - number_of_reports = 0 - - for ooi in self.get_oois_pk(): - ooi_type = Reference.from_str(ooi).class_ - - if ooi_type not in by_type: - by_type[ooi_type] = [] - - by_type[ooi_type].append(ooi) - - sorted_report_types = list(filter(lambda x: x in self.report_types, REPORTS)) - - for report_class in sorted_report_types: - oois = { - ooi for ooi_type in report_class.input_ooi_types for ooi in by_type.get(ooi_type.get_object_type(), []) - } - - try: - results = report_class(self.octopoes_api_connector).collect_data(oois, self.observed_at) - - except ObjectNotFoundException: - error_reports.append(report_class.id) - continue - except TypeNotFound: - error_reports.append(report_class.id) - continue - - for ooi, data in results.items(): - if report_class.id not in report_data: - report_data[report_class.id] = {} - - report_data[report_class.id][ooi] = { - "data": data, - "template": report_class.template_path, - "report_name": report_class.name, - } - number_of_reports += 1 - - observed_at = self.get_observed_at() - - # if its not a single report, we need a parent - if number_of_reports > 1: - raw_id = self.save_report_raw(data={"plugins": self.get_plugin_data_for_saving()}) - report_ooi = self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=ConcatenatedReport, - input_oois=[], - parent=None, - has_parent=False, - observed_at=observed_at, - ) - for report_type, ooi_data in report_data.items(): - for ooi, data in ooi_data.items(): - raw_id = self.save_report_raw(data={"report_data": data["data"]}) - self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=get_report_by_id(report_type), - input_oois=[ooi], - parent=report_ooi.reference, - has_parent=True, - observed_at=observed_at, - ) - # if its a single report we can just save it as complete - else: - report_type = next(iter(report_data)) - ooi = next(iter(report_data[report_type])) - data = report_data[report_type][ooi] - raw_id = self.save_report_raw( - data={"report_data": data["data"], "plugins": self.get_plugin_data_for_saving()} - ) - report_ooi = self.save_report_ooi( - report_data_raw_id=raw_id, - report_type=get_report_by_id(report_type), - input_oois=[ooi], - parent=None, - has_parent=False, - observed_at=observed_at, - ) - # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error - if error_reports: - report_types = ", ".join(set(error_reports)) - date = self.observed_at.date() - error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { - "report_types": report_types, - "date": date, - } - messages.error(self.request, error_message) - - return report_ooi - - class SetupScanGenerateReportView( SaveGenerateReportMixin, GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportPluginView, - TemplateView, ): """ Show required and optional plugins to start scans to generate OOIs to include in report. @@ -228,11 +123,6 @@ class SetupScanGenerateReportView( current_step = 3 def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - if not self.selected_report_types: - messages.error(self.request, _("Select at least one report type to proceed.")) - return redirect( - reverse("generate_report_select_report_types", kwargs=self.get_kwargs()) + get_selection(self.request) - ) if not self.report_has_required_plugins() or self.plugins_enabled(): report_ooi = self.save_report() return redirect( @@ -244,17 +134,20 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: return redirect(self.get_previous()) return super().get(request, *args, **kwargs) + def post(self, request, *args, **kwargs): + if not self.report_type_selection_is_valid(): + return redirect(self.get_previous()) + return self.get(request, *args, **kwargs) + -class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportView, ReportPluginView, TemplateView): +class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportView, ReportPluginView): """ Save the report generated. """ template_name = "generate_report.html" breadcrumbs_step = 6 - current_step = 6 - report_types: Sequence[type[Report]] - ooi_types = get_ooi_types_with_report() + current_step = 4 def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: report_ooi = self.save_report() diff --git a/rocky/reports/views/mixins.py b/rocky/reports/views/mixins.py new file mode 100644 index 00000000000..508cc1542b4 --- /dev/null +++ b/rocky/reports/views/mixins.py @@ -0,0 +1,175 @@ +from typing import Any + +from django.contrib import messages +from django.utils.translation import gettext_lazy as _ + +from octopoes.models import Reference, ScanProfileType +from octopoes.models.exception import ObjectNotFoundException, TypeNotFound +from octopoes.models.ooi.reports import Report as ReportOOI +from reports.report_types.aggregate_organisation_report.report import aggregate_reports +from reports.report_types.concatenated_report.report import ConcatenatedReport +from reports.report_types.helpers import REPORTS, get_report_by_id +from reports.views.base import ReportPluginView + + +class SaveGenerateReportMixin(ReportPluginView): + def save_report(self) -> ReportOOI: + error_reports = [] + report_data: dict[str, dict[str, dict[str, Any]]] = {} + by_type: dict[str, list[str]] = {} + + number_of_reports = 0 + + for ooi in self.get_oois_pk(): + ooi_type = Reference.from_str(ooi).class_ + + if ooi_type not in by_type: + by_type[ooi_type] = [] + + by_type[ooi_type].append(ooi) + + sorted_report_types = list(filter(lambda x: x in self.report_types, REPORTS)) + + for report_class in sorted_report_types: + oois = { + ooi for ooi_type in report_class.input_ooi_types for ooi in by_type.get(ooi_type.get_object_type(), []) + } + + try: + results = report_class(self.octopoes_api_connector).collect_data(oois, self.observed_at) + + except ObjectNotFoundException: + error_reports.append(report_class.id) + continue + except TypeNotFound: + error_reports.append(report_class.id) + continue + + for ooi, data in results.items(): + if report_class.id not in report_data: + report_data[report_class.id] = {} + + report_data[report_class.id][ooi] = { + "data": data, + "template": report_class.template_path, + "report_name": report_class.name, + } + number_of_reports += 1 + + observed_at = self.get_observed_at() + + # if its not a single report, we need a parent + if number_of_reports > 1: + raw_id = self.save_report_raw(data={"plugins": self.get_plugin_data_for_saving()}) + report_ooi = self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=ConcatenatedReport, + input_oois=[], + parent=None, + has_parent=False, + observed_at=observed_at, + ) + for report_type, ooi_data in report_data.items(): + for ooi, data in ooi_data.items(): + raw_id = self.save_report_raw(data={"report_data": data["data"]}) + self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=get_report_by_id(report_type), + input_oois=[ooi], + parent=report_ooi.reference, + has_parent=True, + observed_at=observed_at, + ) + # if its a single report we can just save it as complete + else: + report_type = next(iter(report_data)) + ooi = next(iter(report_data[report_type])) + data = report_data[report_type][ooi] + raw_id = self.save_report_raw( + data={"report_data": data["data"], "plugins": self.get_plugin_data_for_saving()} + ) + report_ooi = self.save_report_ooi( + report_data_raw_id=raw_id, + report_type=get_report_by_id(report_type), + input_oois=[ooi], + parent=None, + has_parent=False, + observed_at=observed_at, + ) + # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error + if error_reports: + report_types = ", ".join(set(error_reports)) + date = self.observed_at.date() + error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { + "report_types": report_types, + "date": date, + } + messages.error(self.request, error_message) + + return report_ooi + + +class SaveAggregateReportMixin(ReportPluginView): + def save_report(self) -> ReportOOI: + input_oois = self.get_oois() + + aggregate_report, post_processed_data, report_data, report_errors = aggregate_reports( + self.octopoes_api_connector, + input_oois, + self.selected_report_types, + self.observed_at, + ) + + # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error + if report_errors: + report_types = ", ".join(set(report_errors)) + date = self.observed_at.date() + error_message = _("No data could be found for %(report_types). Object(s) did not exist on %(date)s.") % { + "report_types": report_types, + "date": date, + } + messages.add_message(self.request, messages.ERROR, error_message) + + observed_at = self.get_observed_at() + + post_processed_data["plugins"] = self.get_plugin_data_for_saving() + post_processed_data["oois"] = [] + for input_ooi in input_oois: + post_processed_data["oois"].append( + { + "name": input_ooi.human_readable, + "type": input_ooi.object_type, + "scan_profile_level": input_ooi.scan_profile.level.value if input_ooi.scan_profile else 0, + "scan_profile_type": ( + input_ooi.scan_profile.scan_profile_type if input_ooi.scan_profile else ScanProfileType.EMPTY + ), + } + ) + + post_processed_data["report_types"] = [] + for report_type in self.report_types: + post_processed_data["report_types"].append( + { + "name": str(report_type.name), + "description": str(report_type.description), + "label_style": report_type.label_style, + } + ) + + # Create the report + report_data_raw_id = self.save_report_raw(data=post_processed_data) + report_ooi = self.save_report_ooi( + report_data_raw_id=report_data_raw_id, + report_type=type(aggregate_report), + input_oois=[ooi.primary_key for ooi in input_oois], + parent=None, + has_parent=False, + observed_at=observed_at, + ) + + # Save the child reports to bytes + for ooi, types in report_data.items(): + for report_type, data in types.items(): + self.save_report_raw(data=data) + + return report_ooi diff --git a/rocky/reports/views/multi_report.py b/rocky/reports/views/multi_report.py index eee40a00ee1..12d4d5e165f 100644 --- a/rocky/reports/views/multi_report.py +++ b/rocky/reports/views/multi_report.py @@ -120,7 +120,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: return super().get(request, *args, **kwargs) -class MultiReportView(BreadcrumbsMultiReportView, OOISelectionView, ReportPluginView): +class MultiReportView(BreadcrumbsMultiReportView, ReportPluginView): """ Shows the multi report from OOIS and report types. """ From 3604a1b0937df5748dd9f53fcd336dc3a89b620d Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 8 Jul 2024 15:52:56 +0200 Subject: [PATCH 02/10] Fix get to post --- rocky/reports/views/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/reports/views/base.py b/rocky/reports/views/base.py index 286acadbf6f..d9cb5cc41db 100644 --- a/rocky/reports/views/base.py +++ b/rocky/reports/views/base.py @@ -180,7 +180,7 @@ def setup(self, request, *args, **kwargs): self.report_type_ids = [report_type for report_type in self.selected_report_types] def get_report_type_selection(self) -> list[str]: - return sorted(set(self.request.GET.getlist("report_type", []))) + return sorted(set(self.request.POST.getlist("report_type", []))) def get_report_types_from_choice( self, From 39d779ff883ab5a4cfd3be66e6a5588d56b8d70d Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 8 Jul 2024 16:31:34 +0200 Subject: [PATCH 03/10] fiux test --- rocky/tests/reports/test_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocky/tests/reports/test_plugins.py b/rocky/tests/reports/test_plugins.py index 03deac4c5ee..d699d616260 100644 --- a/rocky/tests/reports/test_plugins.py +++ b/rocky/tests/reports/test_plugins.py @@ -27,7 +27,7 @@ def test_generate_report_setup_scan_wrong_plugin_id( kwargs = {"organization_code": client_member.organization.code} url = reverse("generate_report_setup_scan", kwargs=kwargs) - request = rf.get( + request = rf.post( url, { "observed_at": valid_time.strftime("%Y-%m-%d"), From b264cfb0e5d8b57df90b92bbecae54437e160d17 Mon Sep 17 00:00:00 2001 From: Rieven Date: Thu, 18 Jul 2024 14:24:53 +0200 Subject: [PATCH 04/10] Add organization code --- rocky/reports/views/mixins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rocky/reports/views/mixins.py b/rocky/reports/views/mixins.py index 508cc1542b4..166810849c7 100644 --- a/rocky/reports/views/mixins.py +++ b/rocky/reports/views/mixins.py @@ -118,6 +118,7 @@ def save_report(self) -> ReportOOI: input_oois, self.selected_report_types, self.observed_at, + self.organization.code, ) # If OOI could not be found or the date is incorrect, it will be shown to the user as a message error From 654a311eb2b6bad07891b18b9b382020adc9902a Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 22 Jul 2024 15:57:07 +0200 Subject: [PATCH 05/10] fix lang --- rocky/rocky/locale/django.pot | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 25ff212effe..ee3f35016f7 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-03 15:27+0000\n" +"POT-Creation-Date: 2024-07-22 13:56+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3842,19 +3842,12 @@ msgstr "" msgid "Save report" msgstr "" -#: reports/views/aggregate_report.py reports/views/generate_report.py -msgid "" -"No data could be found for %(report_types). Object(s) did not exist on " -"%(date)s." -msgstr "" - -#: reports/views/aggregate_report.py reports/views/base.py -#: reports/views/generate_report.py -msgid "Select at least one report type to proceed." +#: reports/views/base.py +msgid "Select at least one OOI to proceed." msgstr "" #: reports/views/base.py -msgid "Select at least one OOI to proceed." +msgid "Select at least one report type to proceed." msgstr "" #: reports/views/base.py @@ -3862,6 +3855,12 @@ msgstr "" msgid "Report type '%s' does not exist." msgstr "" +#: reports/views/mixins.py +msgid "" +"No data could be found for %(report_types). Object(s) did not exist on " +"%(date)s." +msgstr "" + #: reports/views/multi_report.py msgid "Multi report" msgstr "" From d59c4da3b516c5cb2a18206702854bd023841e0f Mon Sep 17 00:00:00 2001 From: Rieven Date: Tue, 23 Jul 2024 12:21:50 +0200 Subject: [PATCH 06/10] Add test --- .../aggregate_organisation_report/report.py | 2 +- rocky/tests/conftest.py | 40 ++++++++ .../reports/test_aggregate_report_flow.py | 96 ++++++++++++++++++- .../reports/test_generate_report_flow.py | 93 +++++++++++++++++- 4 files changed, 228 insertions(+), 3 deletions(-) diff --git a/rocky/reports/report_types/aggregate_organisation_report/report.py b/rocky/reports/report_types/aggregate_organisation_report/report.py index d929718491d..6020ea98dbb 100644 --- a/rocky/reports/report_types/aggregate_organisation_report/report.py +++ b/rocky/reports/report_types/aggregate_organisation_report/report.py @@ -408,7 +408,7 @@ def is_mail_compliant(result): "total_systems": total_ips, "total_hostnames": total_hostnames, "total_systems_basic_security": total_systems_basic_security, - "health": [health.dict() for health in flattened_health], + "health": [health.model_dump() for health in flattened_health], "config_oois": config_oois, } diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index 746114fec7e..a5b52688d6a 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -39,6 +39,7 @@ from octopoes.models.transaction import TransactionRecord from octopoes.models.tree import ReferenceTree from octopoes.models.types import OOIType +from rocky.health import ServiceHealth from rocky.scheduler import PaginatedTasksResponse, Task LANG_LIST = [code for code, _ in settings.LANGUAGES] @@ -1664,3 +1665,42 @@ def onboarding_collect_data(): "finding_types": [], } } + + +@pytest.fixture +def rocky_health(): + ServiceHealth( + service="rocky", + healthy=True, + version="0.0.1.dev1", + additional=None, + results=[ + ServiceHealth( + service="octopoes", + healthy=True, + version="0.0.1.dev1", + additional=None, + results=[ + ServiceHealth( + service="xtdb", + healthy=True, + version="1.24.1", + additional={ + "version": "1.24.1", + "revision": "1164f9a3c7e36edbc026867945765fd4366c1731", + "indexVersion": 22, + "consumerState": None, + "kvStore": "xtdb.rocksdb.RocksKv", + "estimateNumKeys": 24552, + "size": 24053091, + }, + results=[], + ) + ], + ), + ServiceHealth(service="katalogus", healthy=True, version="0.0.1-development", additional=None, results=[]), + ServiceHealth(service="scheduler", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ServiceHealth(service="bytes", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ServiceHealth(service="keiko", healthy=True, version="0.0.1.dev1", additional=None, results=[]), + ], + ) diff --git a/rocky/tests/reports/test_aggregate_report_flow.py b/rocky/tests/reports/test_aggregate_report_flow.py index 0d836103391..f06fcd3baf3 100644 --- a/rocky/tests/reports/test_aggregate_report_flow.py +++ b/rocky/tests/reports/test_aggregate_report_flow.py @@ -1,5 +1,10 @@ from pytest_django.asserts import assertContains -from reports.views.aggregate_report import OOISelectionAggregateReportView, ReportTypesSelectionAggregateReportView +from reports.views.aggregate_report import ( + OOISelectionAggregateReportView, + ReportTypesSelectionAggregateReportView, + SaveAggregateReportView, + SetupScanAggregateReportView, +) from octopoes.models.pagination import Paginated from octopoes.models.types import OOIType @@ -145,3 +150,92 @@ def test_change_ooi_selection_with_ooi_selection( oois_fetched_from_post = response.context_data["selected_oois"] assert len(oois_fetched_from_post) == 2 + + +def test_report_types_selection_nothing_selected( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d")}, + ), + client_member.user, + ) + + response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 + assert list(request._messages)[0].message == "Select at least one report type to proceed." + + +def test_report_types_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "aggregate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": "dns-report"}, + ), + client_member.user, + ) + + response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + +def test_save_generate_report_view( + rf, client_member, valid_time, mock_organization_view_octopoes, listed_hostnames, rocky_health, mocker +): + """ + Will send data through post to generate report. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() + rocky_health_mocker.return_value = rocky_health + + request = setup_request( + rf.post( + "aggregate_report_save", + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + "report_type": ["systems-report", "open-ports-report"], + }, + ), + client_member.user, + ) + + response = SaveAggregateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 # after post follows redirect, this to first create report ID + assert "report_id=Report" in response.url diff --git a/rocky/tests/reports/test_generate_report_flow.py b/rocky/tests/reports/test_generate_report_flow.py index 2f5e99a1126..ed75d338dde 100644 --- a/rocky/tests/reports/test_generate_report_flow.py +++ b/rocky/tests/reports/test_generate_report_flow.py @@ -1,5 +1,10 @@ from pytest_django.asserts import assertContains -from reports.views.generate_report import OOISelectionGenerateReportView, ReportTypesSelectionGenerateReportView +from reports.views.generate_report import ( + OOISelectionGenerateReportView, + ReportTypesSelectionGenerateReportView, + SaveGenerateReportView, + SetupScanGenerateReportView, +) from octopoes.models.pagination import Paginated from octopoes.models.types import OOIType @@ -145,3 +150,89 @@ def test_change_ooi_selection_with_ooi_selection( oois_fetched_from_post = response.context_data["selected_oois"] assert len(oois_fetched_from_post) == 2 + + +def test_report_types_selection_nothing_selected( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d")}, + ), + client_member.user, + ) + + response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 + assert list(request._messages)[0].message == "Select at least one report type to proceed." + + +def test_report_types_selection( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send the selected report types to the configuration page (set plugins). + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_setup_scan", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": "dns-report"}, + ), + client_member.user, + ) + + response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 200 + + +def test_save_generate_report_view( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, +): + """ + Will send data through post to generate report. + """ + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + + request = setup_request( + rf.post( + "generate_report_view", + {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", "report_type": "dns-report"}, + ), + client_member.user, + ) + + response = SaveGenerateReportView.as_view()(request, organization_code=client_member.organization.code) + + assert response.status_code == 302 # after post follows redirect, this to first create report ID + assert "report_id=Report" in response.url From 4bcb8af8698647cb082e543c744d33ab8a5daecc Mon Sep 17 00:00:00 2001 From: Rieven Date: Wed, 24 Jul 2024 15:18:57 +0200 Subject: [PATCH 07/10] fix tests --- rocky/tests/conftest.py | 24 ++++++++++- .../reports/test_aggregate_report_flow.py | 42 +++++++++++++++---- .../reports/test_generate_report_flow.py | 21 +++++++++- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py index a5b52688d6a..31dba7b8d8e 100644 --- a/rocky/tests/conftest.py +++ b/rocky/tests/conftest.py @@ -17,7 +17,8 @@ from django_otp import DEVICE_ID_SESSION_KEY from django_otp.middleware import OTPMiddleware from httpx import Response -from katalogus.client import parse_plugin +from katalogus.client import Boefje, parse_plugin +from tools.enums import SCAN_LEVEL from tools.models import GROUP_ADMIN, GROUP_CLIENT, GROUP_REDTEAM, Indemnification, Organization, OrganizationMember from octopoes.config.settings import ( @@ -1704,3 +1705,24 @@ def rocky_health(): ServiceHealth(service="keiko", healthy=True, version="0.0.1.dev1", additional=None, results=[]), ], ) + + +@pytest.fixture +def boefje_dns_records(): + return Boefje( + id="dns-records", + name="DnsRecords", + version=None, + authors=None, + created=None, + description="Fetch the DNS record(s) of a hostname", + environment_keys=None, + related=[], + enabled=True, + type="boefje", + scan_level=SCAN_LEVEL.L1, + consumes={Hostname}, + options=None, + runnable_hash=None, + produces={"boefje/dns-records"}, + ) diff --git a/rocky/tests/reports/test_aggregate_report_flow.py b/rocky/tests/reports/test_aggregate_report_flow.py index f06fcd3baf3..a24458a9f2b 100644 --- a/rocky/tests/reports/test_aggregate_report_flow.py +++ b/rocky/tests/reports/test_aggregate_report_flow.py @@ -187,11 +187,23 @@ def test_report_types_selection( valid_time, mock_organization_view_octopoes, listed_hostnames, + mocker, + boefje_dns_records, + rocky_health, + mock_bytes_client, ): """ Will send the selected report types to the configuration page (set plugins). """ + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() + rocky_health_mocker.return_value = rocky_health + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( count=len(listed_hostnames), items=listed_hostnames ) @@ -206,30 +218,44 @@ def test_report_types_selection( response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 200 + assert response.status_code == 302 # if all plugins are enabled the view will auto redirect to generate report + assert "report_id=Report" in response.url -def test_save_generate_report_view( - rf, client_member, valid_time, mock_organization_view_octopoes, listed_hostnames, rocky_health, mocker +def test_save_aggregate_report_view( + rf, + client_member, + valid_time, + mock_organization_view_octopoes, + listed_hostnames, + rocky_health, + mocker, + boefje_dns_records, + mock_bytes_client, ): """ - Will send data through post to generate report. + Will send data through post to aggregate report. """ - mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( - count=len(listed_hostnames), items=listed_hostnames - ) + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] rocky_health_mocker = mocker.patch("reports.report_types.aggregate_organisation_report.report.get_rocky_health")() rocky_health_mocker.return_value = rocky_health + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( + count=len(listed_hostnames), items=listed_hostnames + ) + request = setup_request( rf.post( "aggregate_report_save", { "observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", - "report_type": ["systems-report", "open-ports-report"], + "report_type": ["systems-report", "dns-report"], }, ), client_member.user, diff --git a/rocky/tests/reports/test_generate_report_flow.py b/rocky/tests/reports/test_generate_report_flow.py index ed75d338dde..ec9a6213c5d 100644 --- a/rocky/tests/reports/test_generate_report_flow.py +++ b/rocky/tests/reports/test_generate_report_flow.py @@ -187,11 +187,19 @@ def test_report_types_selection( valid_time, mock_organization_view_octopoes, listed_hostnames, + mocker, + boefje_dns_records, + mock_bytes_client, ): """ Will send the selected report types to the configuration page (set plugins). """ + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( count=len(listed_hostnames), items=listed_hostnames ) @@ -199,14 +207,15 @@ def test_report_types_selection( request = setup_request( rf.post( "generate_report_setup_scan", - {"observed_at": valid_time.strftime("%Y-%m-%d"), "report_type": "dns-report"}, + {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", "report_type": "dns-report"}, ), client_member.user, ) response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 200 + assert response.status_code == 302 # plugin is enabled so redirect to generate report view + assert "report_id=Report" in response.url def test_save_generate_report_view( @@ -215,11 +224,19 @@ def test_save_generate_report_view( valid_time, mock_organization_view_octopoes, listed_hostnames, + mocker, + boefje_dns_records, + mock_bytes_client, ): """ Will send data through post to generate report. """ + katalogus_mocker = mocker.patch("reports.views.base.get_katalogus")() + katalogus_mocker.get_plugins.return_value = [boefje_dns_records] + + mock_bytes_client().upload_raw.return_value = "Report|e821aaeb-a6bd-427f-b064-e46837911a5d" + mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( count=len(listed_hostnames), items=listed_hostnames ) From 888db7c51b0aa1e2d85b536397b7d227806494bd Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 5 Aug 2024 13:37:30 +0200 Subject: [PATCH 08/10] Fix post request for export page --- .../partials/export_report_settings.html | 2 ++ .../templates/partials/report_setup_scan.html | 1 + rocky/reports/views/aggregate_report.py | 6 +----- rocky/reports/views/generate_report.py | 20 +++++-------------- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/rocky/reports/templates/partials/export_report_settings.html b/rocky/reports/templates/partials/export_report_settings.html index 11dc8814e7f..4b4e7f90fc5 100644 --- a/rocky/reports/templates/partials/export_report_settings.html +++ b/rocky/reports/templates/partials/export_report_settings.html @@ -106,6 +106,8 @@

{% translate "Edit " %}{{ report_name }}

{% csrf_token %} diff --git a/rocky/reports/templates/partials/report_setup_scan.html b/rocky/reports/templates/partials/report_setup_scan.html index 9a7e1abfcc1..a4bec23215e 100644 --- a/rocky/reports/templates/partials/report_setup_scan.html +++ b/rocky/reports/templates/partials/report_setup_scan.html @@ -96,6 +96,7 @@

{% translate "Suggested plugins" %}

class="inline" method="post" action="{{ next }}"> + {% csrf_token %} {% include "forms/report_form_fields.html" %} {% else %} - - {% translate "Go back" %} - +{% include "partials/return_button.html" with btn_text="Go back" %} + {% endif %}
diff --git a/rocky/reports/templates/partials/report_ooi_list.html b/rocky/reports/templates/partials/report_ooi_list.html index f916c9765b7..66b1fef5572 100644 --- a/rocky/reports/templates/partials/report_ooi_list.html +++ b/rocky/reports/templates/partials/report_ooi_list.html @@ -58,7 +58,7 @@

+ class="inline layout-wide checkboxes_required"> {% csrf_token %} {% if "all" in selected_oois %} {% include "forms/report_form_fields.html" %} diff --git a/rocky/reports/templates/partials/report_setup_scan.html b/rocky/reports/templates/partials/report_setup_scan.html index a4bec23215e..fb664a92071 100644 --- a/rocky/reports/templates/partials/report_setup_scan.html +++ b/rocky/reports/templates/partials/report_setup_scan.html @@ -6,9 +6,7 @@

{% translate "Configuration" %}

{% translate "Set up the required plugins for this report." %}

{% if selected_oois and selected_report_types %} - - {% translate "Change selection" %} - + {% include "partials/return_button.html" with btn_text="Change selection" %} {% include "partials/plugin_overview_table.html" %}

{% translate "Plugins" %}

@@ -104,9 +102,8 @@

{% translate "Suggested plugins" %}

{% else %} - - {% translate "Go back" %} - + {% include "partials/return_button.html" with btn_text="Go back" %} + {% endif %} diff --git a/rocky/reports/templates/partials/report_types_selection.html b/rocky/reports/templates/partials/report_types_selection.html index 77113e3b2b1..3c401605847 100644 --- a/rocky/reports/templates/partials/report_types_selection.html +++ b/rocky/reports/templates/partials/report_types_selection.html @@ -14,9 +14,8 @@

{% translate "Choose report types" %}

{% endblocktranslate %}

{% if not selected_oois %} - - {% translate "Go back" %} - + {% include "partials/return_button.html" with btn_text="Go back" %} + {% else %}

{% blocktranslate trimmed count counter=oois|length %} diff --git a/rocky/reports/templates/partials/report_types_tiles.html b/rocky/reports/templates/partials/report_types_tiles.html index c74c1566dd1..c757622d991 100644 --- a/rocky/reports/templates/partials/report_types_tiles.html +++ b/rocky/reports/templates/partials/report_types_tiles.html @@ -5,7 +5,7 @@ + {% if report_type.id in selected_report_types %}checked{% endif %} />

{{ report_type.description }}

diff --git a/rocky/reports/templates/partials/report_types_tiles_required_optional.html b/rocky/reports/templates/partials/report_types_tiles_required_optional.html index 833b8358a39..0a7581b6e3f 100644 --- a/rocky/reports/templates/partials/report_types_tiles_required_optional.html +++ b/rocky/reports/templates/partials/report_types_tiles_required_optional.html @@ -7,7 +7,7 @@ + {% if report_type.id in selected_report_types %}checked{% endif %} /> {% else %} {% endif %} diff --git a/rocky/reports/templates/partials/return_button.html b/rocky/reports/templates/partials/return_button.html new file mode 100644 index 00000000000..ed038f61bd1 --- /dev/null +++ b/rocky/reports/templates/partials/return_button.html @@ -0,0 +1,14 @@ +{% load i18n %} + +
+ {% csrf_token %} + {% include "forms/report_form_fields.html" %} + + +
From 37195886cfdd4fe2d43ad83c555ed69aa0355ca0 Mon Sep 17 00:00:00 2001 From: Rieven Date: Mon, 5 Aug 2024 16:54:39 +0200 Subject: [PATCH 10/10] fix lang and tests --- rocky/reports/views/aggregate_report.py | 8 ------ rocky/reports/views/mixins.py | 4 +++ rocky/rocky/locale/django.pot | 28 +++++++++---------- .../reports/test_aggregate_report_flow.py | 7 +++-- .../reports/test_generate_report_flow.py | 14 ++++++++-- rocky/tests/reports/test_plugins.py | 2 +- 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py index 41e34ca43a2..2b7c82a37e3 100644 --- a/rocky/reports/views/aggregate_report.py +++ b/rocky/reports/views/aggregate_report.py @@ -150,14 +150,6 @@ class SetupScanAggregateReportView( breadcrumbs_step = 5 current_step = 3 - def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: - if not self.report_has_required_plugins() or self.plugins_enabled(): - return redirect(self.get_next()) - if not self.plugins: - return redirect(self.get_previous()) - - return super().get(request, *args, **kwargs) - def post(self, request, *args, **kwargs): if not self.selected_report_types: messages.error(request, self.NONE_REPORT_TYPE_SELECTION_MESSAGE) diff --git a/rocky/reports/views/mixins.py b/rocky/reports/views/mixins.py index cb044f242c7..99a8e5f37bf 100644 --- a/rocky/reports/views/mixins.py +++ b/rocky/reports/views/mixins.py @@ -78,8 +78,12 @@ def save_report(self, report_names: list) -> ReportOOI: if ooi_name in default_name and report_type_name in default_name: name = updated_name break + else: + name = default_name + break raw_id = self.save_report_raw(data={"report_data": data["data"]}) + self.save_report_ooi( report_data_raw_id=raw_id, report_type=get_report_by_id(report_type), diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index fc689523bb1..ba70cbfca1d 100644 --- a/rocky/rocky/locale/django.pot +++ b/rocky/rocky/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-05 09:27+0000\n" +"POT-Creation-Date: 2024-08-05 13:42+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -811,9 +811,6 @@ msgid "" msgstr "" #: katalogus/templates/katalogus_settings.html -#: reports/templates/partials/export_report_settings.html -#: reports/templates/partials/report_setup_scan.html -#: reports/templates/partials/report_types_selection.html #: rocky/templates/two_factor/core/otp_required.html msgid "Go back" msgstr "" @@ -3580,11 +3577,6 @@ msgstr "" msgid "Set up the required plugins for this report." msgstr "" -#: reports/templates/partials/report_setup_scan.html -#: reports/templates/partials/report_types_selection.html -msgid "Change selection" -msgstr "" - #: reports/templates/partials/report_setup_scan.html msgid "Plugins" msgstr "" @@ -3703,6 +3695,10 @@ msgid_plural "You have selected %(total_oois)s objects in previous step." msgstr[0] "" msgstr[1] "" +#: reports/templates/partials/report_types_selection.html +msgid "Change selection" +msgstr "" + #: reports/templates/partials/report_types_selection.html msgid "Available report types" msgstr "" @@ -3715,6 +3711,11 @@ msgstr "" msgid "Toggle all report types" msgstr "" +#: reports/templates/partials/return_button.html +#, python-format +msgid "%(btn_text)s" +msgstr "" + #: reports/templates/report_overview/report_history.html #: reports/views/report_overview.py msgid "Reports history" @@ -3909,15 +3910,14 @@ msgstr "" msgid "Save report" msgstr "" -#: reports/views/aggregate_report.py reports/views/base.py -#: reports/views/generate_report.py reports/views/multi_report.py -msgid "Select at least one report type to proceed." -msgstr "" - #: reports/views/base.py msgid "Select at least one OOI to proceed." msgstr "" +#: reports/views/base.py reports/views/multi_report.py +msgid "Select at least one report type to proceed." +msgstr "" + #: reports/views/base.py #, python-format msgid "Report type '%s' does not exist." diff --git a/rocky/tests/reports/test_aggregate_report_flow.py b/rocky/tests/reports/test_aggregate_report_flow.py index a24458a9f2b..f3c6610cbf8 100644 --- a/rocky/tests/reports/test_aggregate_report_flow.py +++ b/rocky/tests/reports/test_aggregate_report_flow.py @@ -218,8 +218,9 @@ def test_report_types_selection( response = SetupScanAggregateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 # if all plugins are enabled the view will auto redirect to generate report - assert "report_id=Report" in response.url + assert response.status_code == 200 # if all plugins are enabled the view will auto redirect to generate report + + assertContains(response, '', html=True) def test_save_aggregate_report_view( @@ -256,6 +257,8 @@ def test_save_aggregate_report_view( "observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", "report_type": ["systems-report", "dns-report"], + "old_report_name": ["Aggregate Report"], + "report_name": ["Testing a new name for Aggregate Report"], }, ), client_member.user, diff --git a/rocky/tests/reports/test_generate_report_flow.py b/rocky/tests/reports/test_generate_report_flow.py index ec9a6213c5d..1271a69bff7 100644 --- a/rocky/tests/reports/test_generate_report_flow.py +++ b/rocky/tests/reports/test_generate_report_flow.py @@ -214,8 +214,8 @@ def test_report_types_selection( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 # plugin is enabled so redirect to generate report view - assert "report_id=Report" in response.url + assert response.status_code == 200 + assertContains(response, '', html=True) def test_save_generate_report_view( @@ -241,10 +241,18 @@ def test_save_generate_report_view( count=len(listed_hostnames), items=listed_hostnames ) + old_report_names = [f"DNS report for {ooi.name}" for ooi in listed_hostnames] + request = setup_request( rf.post( "generate_report_view", - {"observed_at": valid_time.strftime("%Y-%m-%d"), "ooi": "all", "report_type": "dns-report"}, + { + "observed_at": valid_time.strftime("%Y-%m-%d"), + "ooi": "all", + "report_type": "dns-report", + "old_report_name": old_report_names, + "report_name": [f"DNS report for {len(listed_hostnames)} objects"], + }, ), client_member.user, ) diff --git a/rocky/tests/reports/test_plugins.py b/rocky/tests/reports/test_plugins.py index d699d616260..9343f181931 100644 --- a/rocky/tests/reports/test_plugins.py +++ b/rocky/tests/reports/test_plugins.py @@ -41,5 +41,5 @@ def test_generate_report_setup_scan_wrong_plugin_id( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) - assert response.status_code == 302 + assert response.status_code == 200 assert list(request._messages)[0].message == "A HTTP error occurred. Check logs for more info."