From 1589b0af502f5f5a58c51e74b21ba385f598274e Mon Sep 17 00:00:00 2001
From: Madelon Dohmen <99282220+madelondohmen@users.noreply.github.com>
Date: Tue, 26 Nov 2024 10:10:51 +0100
Subject: [PATCH 01/44] Enable/disable scheduled reports (#3871)
Co-authored-by: TwistMeister
Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com>
---
rocky/assets/css/components/system-tag.scss | 43 ++++++++++++
rocky/assets/css/main.scss | 1 +
.../soft/fundamentals/border-radii.scss | 4 ++
rocky/components/modal/README.md | 4 +-
.../enable_disable_schedule_modal.html | 24 +++++++
.../scheduled_reports_table.html | 65 +++++++++++++------
rocky/reports/urls.py | 12 +++-
rocky/reports/views/report_overview.py | 52 +++++++++++++++
rocky/rocky/locale/django.pot | 57 ++++++++++++++--
rocky/rocky/views/scheduler.py | 6 ++
10 files changed, 237 insertions(+), 31 deletions(-)
create mode 100644 rocky/assets/css/components/system-tag.scss
create mode 100644 rocky/reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
diff --git a/rocky/assets/css/components/system-tag.scss b/rocky/assets/css/components/system-tag.scss
new file mode 100644
index 00000000000..3f7caab05eb
--- /dev/null
+++ b/rocky/assets/css/components/system-tag.scss
@@ -0,0 +1,43 @@
+.system-tag,
+span.system-tag {
+ background-color: var(--colors-white);
+ border: 2px solid;
+ border-radius: var(--border-radius-xl);
+ padding: var(--spacing-grid-025) var(--spacing-grid-100);
+ box-sizing: border-box;
+ width: auto;
+
+ &::before {
+ content: none;
+ }
+
+ &.color-1 {
+ color: var(--colors-blue-600);
+ border-color: var(--colors-blue-600);
+ }
+
+ &.color-2 {
+ color: var(--colors-green-600);
+ border-color: var(--colors-green-600);
+ }
+
+ &.color-3 {
+ color: var(--colors-ochre-500);
+ border-color: var(--colors-ochre-500);
+ }
+
+ &.color-4 {
+ color: var(--colors-orange-600);
+ border-color: var(--colors-orange-600);
+ }
+
+ &.color-5 {
+ color: var(--colors-red-600);
+ border-color: var(--colors-red-600);
+ }
+
+ &.color-6 {
+ color: var(--colors-purrple-600);
+ border-color: var(--colors-purrple-600);
+ }
+}
diff --git a/rocky/assets/css/main.scss b/rocky/assets/css/main.scss
index 4fb860423c0..1dd5615f43f 100644
--- a/rocky/assets/css/main.scss
+++ b/rocky/assets/css/main.scss
@@ -67,6 +67,7 @@
@import "components/sticky";
@import "components/sticky-column";
@import "components/state-tags";
+@import "components/system-tag";
@import "components/table";
@import "components/toggle";
@import "components/toolbar";
diff --git a/rocky/assets/css/themes/soft/fundamentals/border-radii.scss b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss
index 0ac5c9d7060..547a6f6d8bb 100644
--- a/rocky/assets/css/themes/soft/fundamentals/border-radii.scss
+++ b/rocky/assets/css/themes/soft/fundamentals/border-radii.scss
@@ -20,6 +20,10 @@
border-radius: var(--border-radius-l);
}
+.border-radius-xl {
+ border-radius: var(--border-radius-xl);
+}
+
.border-radius-round {
border-radius: var(--border-radius-round);
}
diff --git a/rocky/components/modal/README.md b/rocky/components/modal/README.md
index b6f996e6dc4..ec49e5030a8 100644
--- a/rocky/components/modal/README.md
+++ b/rocky/components/modal/README.md
@@ -10,7 +10,7 @@ This outlines the basic usages and provides a code block example below, of how t
### Instantiate
-First you need to add `{% load component_tags %}` at the top of your template. Next you need to add the following code block at the bottom, to include the corresponding JS (if you haven't already you also need to add `{% load compress %}`).
+First you need to add `{% load component_tags %}` at the top of your template. Next you need to add the following code block at the bottom, to include the corresponding JS (if you haven't already you also need to add `{% load compress %}` and `{% load static %}`).
```
{% block html_at_end_body %}
@@ -58,7 +58,7 @@ Including `{% component_css_dependencies %}` is needed to inject the reference t
{% fill "content" %}
diff --git a/rocky/reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html b/rocky/reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
new file mode 100644
index 00000000000..6351601a78a
--- /dev/null
+++ b/rocky/reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
@@ -0,0 +1,24 @@
+{% load i18n %}
+
+{% component "modal" size="dialog-small" modal_id=modal_id %}
+{% fill "header" %}
+{% translate "Disable schedule" %}
+{% endfill %}
+{% fill "content" %}
+
+{% endfill %}
+{% fill "footer_buttons" %}
+{% translate "Disable schedule" %}
+
+{% endfill %}
+{% endcomponent %}
+{% component_css_dependencies %}
diff --git a/rocky/reports/templates/report_overview/scheduled_reports_table.html b/rocky/reports/templates/report_overview/scheduled_reports_table.html
index 41ed31ae923..7a824d2c39d 100644
--- a/rocky/reports/templates/report_overview/scheduled_reports_table.html
+++ b/rocky/reports/templates/report_overview/scheduled_reports_table.html
@@ -1,6 +1,9 @@
{% load i18n %}
+{% load static %}
{% load ooi_extra %}
{% load report_extra %}
+{% load compress %}
+{% load component_tags %}
{% if scheduled_reports %}
@@ -11,10 +14,11 @@
{% translate "Scheduled reports:" %}
- {% translate "Report Name" %} |
- {% translate "Report types" %} |
+ {% translate "Name" %} |
+ {% translate "Report type" %} |
{% translate "Scheduled for" %} |
{% translate "Recurrence" %} |
+ {% translate "Schedule status" %} |
|
@@ -26,27 +30,36 @@
|
- {{ schedule.deadline_at }} |
+
+ {% if not schedule.enabled %}
+ -
+ {% else %}
+ {{ schedule.deadline_at }}
+ {% endif %}
+ |
{{ schedule.cron }} |
+
+ {% if schedule.enabled %}
+ {% translate "Enabled" %}
+ {% else %}
+ {% translate "Disabled" %}
+ {% endif %}
+ |
|
@@ -110,3 +128,8 @@
{% else %}
{% translate "No scheduled reports have been generated yet." %}
{% endif %}
+{% block html_at_end_body %}
+ {% compress js %}
+
+ {% endcompress %}
+{% endblock html_at_end_body %}
diff --git a/rocky/reports/urls.py b/rocky/reports/urls.py
index dcee21ad3d0..d7c809a31a9 100644
--- a/rocky/reports/urls.py
+++ b/rocky/reports/urls.py
@@ -25,12 +25,22 @@
ReportTypesSelectionMultiReportView,
SetupScanMultiReportView,
)
-from reports.views.report_overview import ReportHistoryView, ScheduledReportsView, SubreportView
+from reports.views.report_overview import (
+ ReportHistoryView,
+ ScheduledReportsEnableDisableView,
+ ScheduledReportsView,
+ SubreportView,
+)
# Report overview urls
urlpatterns = [
path("", ReportsLandingView.as_view(), name="reports"),
path("scheduled-reports/", ScheduledReportsView.as_view(), name="scheduled_reports"),
+ path(
+ "scheduled-reports/enable-disable",
+ ScheduledReportsEnableDisableView.as_view(),
+ name="enable_disable_scheduled_reports",
+ ),
path("report-history/", ReportHistoryView.as_view(), name="report_history"),
path("report-history/subreports", SubreportView.as_view(), name="subreports"),
]
diff --git a/rocky/reports/views/report_overview.py b/rocky/reports/views/report_overview.py
index e6ff232ed2c..269ac7dd036 100644
--- a/rocky/reports/views/report_overview.py
+++ b/rocky/reports/views/report_overview.py
@@ -4,6 +4,8 @@
import structlog
from django.contrib import messages
+from django.http import HttpResponse
+from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView
@@ -70,9 +72,11 @@ def get_queryset(self) -> list[dict[str, Any]]:
recipe_tree = recipe_ooi_tree.store.values()
recipe_ooi = next(ooi for ooi in recipe_tree if isinstance(ooi, ReportRecipe))
report_oois = [ooi for ooi in recipe_tree if isinstance(ooi, Report)]
+ report_oois.sort(key=lambda ooi: ooi.date_generated, reverse=True)
recipes.append(
{
"schedule_id": schedule["id"],
+ "enabled": schedule["enabled"],
"recipe": recipe_ooi,
"cron": schedule["schedule"],
"deadline_at": datetime.fromisoformat(schedule["deadline_at"]),
@@ -88,6 +92,54 @@ def get_context_data(self, **kwargs):
return context
+class ScheduledReportsEnableDisableView(BreadcrumbsReportOverviewView, SchedulerView, ListView):
+ """
+ Cancel the selected report(s)
+ """
+
+ task_type = "report"
+ template_name = "report_overview/scheduled_reports.html"
+
+ def get_queryset(self) -> ReportList:
+ return ReportList(self.octopoes_api_connector, valid_time=self.observed_at)
+
+ def get(self, request, *args, **kwargs) -> HttpResponse:
+ schedule_id = request.GET.get("schedule_id")
+ schedule = self.get_schedule_details(schedule_id)
+ is_schedule_enabled = schedule.enabled
+
+ self.edit_report_schedule(schedule_id, {"enabled": not is_schedule_enabled})
+
+ logger.info(
+ _("Schedule {}").format("disabled" if is_schedule_enabled else "enabled"),
+ event_code="0800081" if is_schedule_enabled else "0800082",
+ schedule_id=schedule_id,
+ )
+
+ report_recipe_id = schedule.data["report_recipe_id"]
+ report_recipe = self.octopoes_api_connector.get(
+ Reference.from_str(f"ReportRecipe|{report_recipe_id}"), valid_time=datetime.now(timezone.utc)
+ )
+
+ if is_schedule_enabled:
+ messages.success(
+ self.request,
+ _(
+ "Schedule disabled successfully. '{}' will not be generated "
+ "automatically until the schedule is enabled again."
+ ).format(report_recipe.report_name_format),
+ )
+ else:
+ messages.success(
+ self.request,
+ _("Schedule enabled successfully. '{}' will be generated according to schedule.").format(
+ report_recipe.report_name_format
+ ),
+ )
+
+ return redirect(reverse("scheduled_reports", kwargs={"organization_code": self.organization.code}))
+
+
class ReportHistoryView(BreadcrumbsReportOverviewView, OctopoesView, ListView):
"""
Shows all the reports that have ever been generated for the organization.
diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot
index 331596e4fe3..c896645a930 100644
--- a/rocky/rocky/locale/django.pot
+++ b/rocky/rocky/locale/django.pot
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-11-18 15:24+0000\n"
+"POT-Creation-Date: 2024-11-25 09:27+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -586,6 +586,7 @@ msgstr ""
#: katalogus/templates/change_clearance_level.html
#: katalogus/templates/confirmation_clone_settings.html
#: katalogus/templates/plugin_settings_delete.html
+#: reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
#: rocky/templates/oois/ooi_delete.html
#: rocky/templates/oois/ooi_mute_finding.html
#: rocky/templates/organizations/organization_edit.html
@@ -626,12 +627,14 @@ msgstr ""
#: katalogus/templates/partials/plugin_tile_modal.html
#: katalogus/templates/plugin_container_image.html
#: reports/report_types/dns_report/report.html
+#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Enabled"
msgstr ""
#: katalogus/forms/katalogus_filter.py
#: katalogus/templates/partials/plugin_tile_modal.html
#: katalogus/templates/plugin_container_image.html
+#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/summary/selected_plugins.html
msgid "Disabled"
msgstr ""
@@ -1101,7 +1104,6 @@ msgstr ""
#: katalogus/templates/partials/plugin_tile_modal.html reports/forms.py
#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Report types"
msgstr ""
@@ -1278,7 +1280,6 @@ msgstr ""
#: reports/templates/report_overview/modal_partials/delete_modal.html
#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
msgid "Creation date"
msgstr ""
@@ -4171,6 +4172,22 @@ msgstr ""
msgid "Reference date"
msgstr ""
+#: reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+msgid "Disable schedule"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/enable_disable_schedule_modal.html
+#, python-format
+msgid ""
+"\n"
+" Are you sure you want to disable the schedule for "
+"%(report_name)s?\n"
+" The recipe will still exist and the schedule can be enabled "
+"later on.\n"
+" "
+msgstr ""
+
#: reports/templates/report_overview/modal_partials/rename_modal.html
msgid "Rename the following report(s):"
msgstr ""
@@ -4298,11 +4315,11 @@ msgid "Scheduled reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-msgid "Report Name"
+msgid "Scheduled for"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-msgid "Scheduled for"
+msgid "Schedule status"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4310,18 +4327,25 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
+msgid "Input"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Show report details"
msgstr ""
+#: reports/templates/report_overview/scheduled_reports_table.html
+msgid "objects"
+msgstr ""
+
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Edit report recipe"
msgstr ""
+#: reports/templates/report_overview/scheduled_reports_table.html
+msgid "Enable schedule"
+msgstr ""
+
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "No scheduled reports have been generated yet."
msgstr ""
@@ -4493,6 +4517,21 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "Schedule {}"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Schedule disabled successfully. '{}' will not be generated automatically "
+"until the schedule is enabled again."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Schedule enabled successfully. '{}' will be generated according to schedule."
+msgstr ""
+
#: reports/views/report_overview.py
msgid "An unexpected error occurred, please check logs for more info."
msgstr ""
@@ -6671,6 +6710,10 @@ msgstr ""
msgid "Download meta data"
msgstr ""
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
+msgstr ""
+
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
diff --git a/rocky/rocky/views/scheduler.py b/rocky/rocky/views/scheduler.py
index 1b0343adf84..b3c4c2e8736 100644
--- a/rocky/rocky/views/scheduler.py
+++ b/rocky/rocky/views/scheduler.py
@@ -178,6 +178,12 @@ def get_json_task_details(self) -> JsonResponse | None:
except SchedulerError as error:
return messages.error(self.request, error.message)
+ def get_schedule_details(self, schedule_id: str) -> ScheduleResponse:
+ try:
+ return self.scheduler_client.get_schedule_details(schedule_id)
+ except SchedulerError as error:
+ return messages.error(self.request, error.message)
+
def get_schedule_with_filters(self, filters: dict[str, list[dict[str, str]]]) -> ScheduleResponse:
try:
return self.scheduler_client.post_schedule_search(filters).results[0]
From efee7191202f6164d2ad300b1101b4a1bb70e161 Mon Sep 17 00:00:00 2001
From: Jeroen Dekkers
Date: Tue, 26 Nov 2024 10:18:13 +0100
Subject: [PATCH 02/44] Fix rocky katalogus tests and delete unused fixtures
(#3884)
Co-authored-by: Jan Klopper
---
rocky/tests/conftest.py | 143 ------------------------
rocky/tests/katalogus/test_katalogus.py | 68 ++++++-----
2 files changed, 43 insertions(+), 168 deletions(-)
diff --git a/rocky/tests/conftest.py b/rocky/tests/conftest.py
index cde70e1abbf..c11aea4b237 100644
--- a/rocky/tests/conftest.py
+++ b/rocky/tests/conftest.py
@@ -222,13 +222,6 @@ def redteamuser(django_user_model):
)
-@pytest.fixture
-def redteamuser_b(django_user_model):
- return create_user(
- django_user_model, "redteamerB@openkat.nl", "RedteamBRedteamB123!!", "Redteam B name", "default_redteam_b"
- )
-
-
@pytest.fixture
def redteam_member(redteamuser, organization):
member = create_member(redteamuser, organization)
@@ -236,13 +229,6 @@ def redteam_member(redteamuser, organization):
return member
-@pytest.fixture
-def redteam_member_b(redteamuser_b, organization_b):
- member = create_member(redteamuser_b, organization_b)
- add_redteam_group_permissions(member)
- return member
-
-
@pytest.fixture
def clientuser(django_user_model):
return create_user(django_user_model, "client@openkat.nl", "ClientClient123!!", "Client name", "default_client")
@@ -331,14 +317,6 @@ def mock_crisis_room_octopoes(mocker):
return mocker.patch("crisis_room.views.OctopoesAPIConnector")
-@pytest.fixture
-def lazy_task_list_empty() -> MagicMock:
- mock = MagicMock()
- mock.__getitem__.return_value = []
- mock.count.return_value = 0
- return mock
-
-
@pytest.fixture
def task() -> Task:
return Task.model_validate(
@@ -795,17 +773,6 @@ def tree_data_dns_findings():
}
-@pytest.fixture
-def finding_type_kat_no_caa() -> KATFindingType:
- return KATFindingType(
- id="KAT-NO-CAA",
- description="Fake description...",
- recommendation="Fake recommendation...",
- risk_score=9.5,
- risk_severity=RiskLevelSeverity.CRITICAL,
- )
-
-
@pytest.fixture
def finding_type_kat_invalid_spf() -> KATFindingType:
return KATFindingType(
@@ -1322,93 +1289,6 @@ def report_recipe():
)
-@pytest.fixture
-def get_report_schedules():
- report_schedule = [
- {
- "id": "06a783b3-af62-429d-8b48-5934c8702366",
- "scheduler_id": "report-madelon123",
- "hash": "f429f60fda539f9017544758163a955e",
- "data": {
- "type": "report",
- "organisation_id": "madelon123",
- "report_recipe_id": "6a121a53-f795-4bfe-9aea-f410a96fca59",
- },
- "enabled": "true",
- "schedule": "0 * * * *",
- "tasks": [
- {
- "id": "21ce00b8-57c4-4d65-a53e-275b4e44da6f",
- "scheduler_id": "report-madelon123",
- "schedule_id": "06a783b3-af62-429d-8b48-5934c8702366",
- "priority": 1729520184,
- "status": "completed",
- "type": "report",
- "hash": "f429f60fda539f9017544758163a955e",
- "data": {
- "organisation_id": "madelon123",
- "report_recipe_id": "6a121a53-f795-4bfe-9aea-f410a96fca59",
- },
- "created_at": "2024-10-21T14:16:24.702759Z",
- "modified_at": "2024-10-21T14:16:24.702761Z",
- },
- {
- "id": "f63c2224-a4b2-4161-9790-9b4d665a4683",
- "scheduler_id": "report-madelon123",
- "schedule_id": "06a783b3-af62-429d-8b48-5934c8702366",
- "priority": 1729580020,
- "status": "completed",
- "type": "report",
- "hash": "f429f60fda539f9017544758163a955e",
- "data": {
- "organisation_id": "madelon123",
- "report_recipe_id": "6a121a53-f795-4bfe-9aea-f410a96fca59",
- },
- "created_at": "2024-10-22T06:53:40.405185Z",
- "modified_at": "2024-10-22T06:53:40.405192Z",
- },
- ],
- "deadline_at": "2024-10-22T12:00:00Z",
- "created_at": "2024-10-21T14:14:00.359039Z",
- "modified_at": "2024-10-21T14:14:00.359043Z",
- },
- {
- "id": "e9a00bc1-850a-401a-89d9-252d98823bb3",
- "scheduler_id": "report-madelon123",
- "hash": "02e67c8676cb8135681d52ca62a9fe5b",
- "data": {
- "type": "report",
- "organisation_id": "madelon123",
- "report_recipe_id": "31c79490-fb51-440d-9108-0c388276f655",
- },
- "enabled": "true",
- "schedule": "0 0 * * *",
- "tasks": [
- {
- "id": "f4f938e0-5f2d-4bcd-9b28-11831b7835e4",
- "scheduler_id": "report-madelon123",
- "schedule_id": "e9a00bc1-850a-401a-89d9-252d98823bb3",
- "priority": 1729521145,
- "status": "completed",
- "type": "report",
- "hash": "02e67c8676cb8135681d52ca62a9fe5b",
- "data": {
- "organisation_id": "madelon123",
- "report_recipe_id": "31c79490-fb51-440d-9108-0c388276f655",
- },
- "created_at": "2024-10-21T14:32:25.247525Z",
- "modified_at": "2024-10-21T14:32:25.247527Z",
- }
- ],
- "deadline_at": "2024-10-23T00:00:00Z",
- "created_at": "2024-10-21T13:34:42.791561Z",
- "modified_at": "2024-10-21T13:34:42.791563Z",
- },
- ]
-
- return report_schedule
-
-
def setup_request(request, user):
request = SessionMiddleware(lambda r: r)(request)
request.session[DEVICE_ID_SESSION_KEY] = user.staticdevice_set.get().persistent_id
@@ -1710,29 +1590,6 @@ def reports_more_input_oois():
]
-def onboarding_collect_data():
- return {
- "Hostname|internet|mispo.es": {
- "input_ooi": "Hostname|internet|mispo.es",
- "records": [
- {"type": "A", "ttl": 480, "name": "mispo.es", "content": "134.209.85.72"},
- {"type": "MX", "ttl": 480, "name": "mispo.es", "content": "10 mx.wijmailenveilig.nl."},
- {"type": "NS", "ttl": 480, "name": "mispo.es", "content": "ns1.domaindiscount24.net."},
- {"type": "NS", "ttl": 480, "name": "mispo.es", "content": "ns2.domaindiscount24.net."},
- {"type": "NS", "ttl": 480, "name": "mispo.es", "content": "ns3.domaindiscount24.net."},
- {
- "type": "SOA",
- "ttl": 480,
- "name": "mispo.es",
- "content": "ns1.domaindiscount24.net. tech.key-systems.net. 2023012324 10800 3600 604800 3600",
- },
- ],
- "security": {"spf": False, "dkim": False, "dmarc": False, "dnssec": False, "caa": False},
- "finding_types": [],
- }
- }
-
-
@pytest.fixture
def rocky_health():
ServiceHealth(
diff --git a/rocky/tests/katalogus/test_katalogus.py b/rocky/tests/katalogus/test_katalogus.py
index 8207c640d2d..2b11999af53 100644
--- a/rocky/tests/katalogus/test_katalogus.py
+++ b/rocky/tests/katalogus/test_katalogus.py
@@ -13,10 +13,12 @@
def test_valid_plugin_id():
with pytest.raises(ValueError):
- valid_plugin_id("123")
valid_plugin_id("test test")
+
+ with pytest.raises(ValueError):
valid_plugin_id("test$test")
+ assert valid_plugin_id("123") == "123"
assert valid_plugin_id("test-test") == "test-test"
@@ -28,38 +30,46 @@ def test_valid_organization_code():
@pytest.mark.parametrize("member", ["superuser_member", "admin_member", "redteam_member", "client_member"])
-def katalogus_plugin_listing(request, rf, member, mocker):
+def test_katalogus_plugin_listing(request, rf, member, mocker):
plugins = get_plugins_data()
mock_requests = mocker.patch("katalogus.client.httpx")
mock_response = mocker.MagicMock()
- mock_requests.Session().get.return_value = mock_response
+ mock_requests.Client().get.return_value = mock_response
mock_response.json.return_value = plugins
member = request.getfixturevalue(member)
- response = KATalogusView.as_view()(
- setup_request(rf.get("katalogus"), member.user), organization_code=member.organization.code
- )
+ request = setup_request(rf.get("all_plugins_list"), member.user)
+ request.resolver_match = mocker.Mock(url_name="all_plugins_list")
+ response = KATalogusView.as_view()(request, organization_code=member.organization.code)
assert response.status_code == 200
assertContains(response, "KAT-alogus")
assertContains(response, "An overview of all available plugins.")
# active toolbar, only one link is active, "All"
assertContains(
- response, 'All'
+ response,
+ 'All',
+ html=True,
)
assertNotContains(
- response, 'Boefjes'
+ response,
+ 'Boefjes',
+ html=True,
)
assertNotContains(
response,
'Normalizers',
+ html=True,
)
assertNotContains(
response,
'About plugins',
+ html=True,
)
- assertContains(response, str(len(plugins)) + " Plugins available")
+ assertContains(response, f"{len(plugins)}Plugins available", html=True)
# All plugins shows Boefjes and Normalizers, checking if one of each is available
assertContains(response, "kat_adr_finding_types_normalize")
@@ -70,56 +80,64 @@ def katalogus_plugin_listing(request, rf, member, mocker):
@pytest.mark.parametrize("member", ["superuser_member", "admin_member", "redteam_member", "client_member"])
-def katalogus_plugin_listing_boefjes(request, rf, member, mocker):
+def test_katalogus_plugin_listing_boefjes(request, rf, member, mocker):
boefjes = get_boefjes_data()
mock_requests = mocker.patch("katalogus.client.httpx")
mock_response = mocker.MagicMock()
- mock_requests.Session().get.return_value = mock_response
+ mock_requests.Client().get.return_value = mock_response
mock_response.json.return_value = boefjes
member = request.getfixturevalue(member)
- response = BoefjeListView.as_view()(
- setup_request(rf.get("boefjes_list"), member.user), organization_code=member.organization.code
- )
+ request = setup_request(rf.get("boefjes_list"), member.user)
+ request.resolver_match = mocker.Mock(url_name="boefjes_list")
+ response = BoefjeListView.as_view()(request, organization_code=member.organization.code)
+
assert response.status_code == 200
assertContains(response, "Boefjes")
assertContains(
- response, 'Boefjes'
+ response,
+ 'Boefjes',
+ html=True,
)
- assertContains(response, str(len(boefjes)) + " Boefjes available")
+ assertContains(response, f"{len(boefjes)}Boefjes available", html=True)
assertNotContains(response, 'Normalizer')
assertContains(response, 'Boefje')
assertContains(response, "ssl-certificates")
@pytest.mark.parametrize("member", ["superuser_member", "admin_member", "redteam_member", "client_member"])
-def katalogus_plugin_listing_normalizers(request, rf, member, mocker):
+def test_katalogus_plugin_listing_normalizers(request, rf, member, mocker):
normalizers = get_normalizers_data()
mock_requests = mocker.patch("katalogus.client.httpx")
mock_response = mocker.MagicMock()
- mock_requests.Session().get.return_value = mock_response
+ mock_requests.Client().get.return_value = mock_response
mock_response.json.return_value = normalizers
member = request.getfixturevalue(member)
- response = NormalizerListView.as_view()(
- setup_request(rf.get("normalizers_list"), member.user), organization_code=member.organization.code
- )
+ request = setup_request(rf.get("normalizers_list"), member.user)
+ request.resolver_match = mocker.Mock(url_name="normalizers_list")
+ response = NormalizerListView.as_view()(request, organization_code=member.organization.code)
assert response.status_code == 200
assertContains(response, "Normalizers")
assertContains(
response,
- 'Normalizers',
+ 'Normalizers',
+ html=True,
)
- assertContains(response, str(len(normalizers)) + " Normalizers available")
+ assertContains(response, f"{len(normalizers)}Normalizers available", html=True)
assertContains(response, 'Normalizer')
assertNotContains(response, 'Boefje')
assertNotContains(response, "ssl-certificates")
- assertNotContains(response, "binaryedge")
+ assertContains(response, "binaryedge")
@pytest.mark.parametrize("member", ["superuser_member", "admin_member", "redteam_member", "client_member"])
-def katalogus_about_plugins(request, rf, member):
+def test_katalogus_about_plugins(request, rf, member):
member = request.getfixturevalue(member)
response = AboutPluginsView.as_view()(
From 45afffb6a614f89c412d094f8c509c6347464957 Mon Sep 17 00:00:00 2001
From: noamblitz <43830693+noamblitz@users.noreply.github.com>
Date: Tue, 26 Nov 2024 14:53:49 +0100
Subject: [PATCH 03/44] Change plugins enabling in report flow to checkboxes
(#3747)
Co-authored-by: ammar92
Co-authored-by: stephanie0x00 <9821756+stephanie0x00@users.noreply.github.com>
Co-authored-by: Jan Klopper
---
.../templates/forms/report_form_fields.html | 2 +-
.../templates/partials/report_setup_scan.html | 11 +++++---
rocky/reports/views/aggregate_report.py | 26 +++++++++++++++++++
rocky/reports/views/generate_report.py | 26 +++++++++++++++++++
rocky/rocky/locale/django.pot | 12 +++++++--
5 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/rocky/reports/templates/forms/report_form_fields.html b/rocky/reports/templates/forms/report_form_fields.html
index 3e7df3310eb..f8f6d645d3c 100644
--- a/rocky/reports/templates/forms/report_form_fields.html
+++ b/rocky/reports/templates/forms/report_form_fields.html
@@ -18,7 +18,7 @@
{% endfor %}
{% endif %}
{% for required_optional_plugin, plugins_ in plugins.items %}
- {% for plugin in plugins_ %}{% endfor %}
+ {% for plugin in plugins_ %}{% endfor %}
{% endfor %}
{% if request.POST.choose_recurrence %}
{% translate "Required plugins" %}
{% for required_plugin in plugins.required|dictsort:"enabled" %}
- {% include "partials/plugin_tile.html" with plugin=required_plugin plugin_report_types=plugin_data.plugin_report_types show_report_types="yes" plugin_report_types=plugin_data.plugin_report_types %}
+ {% if required_plugin.enabled %}
+ {% include "partials/plugin_tile.html" with form_id="continue-to-configuration" plugin_report_types=plugin_data.plugin_report_types show_report_types="yes" plugin=required_plugin remove_action_buttons="yes" add_checkbox="yes" %}
+ {% else %}
+ {% include "partials/plugin_tile.html" with form_id="continue-to-configuration" plugin_report_types=plugin_data.plugin_report_types show_report_types="yes" plugin=required_plugin remove_action_buttons="yes" add_checkbox="yes" checked="yes" %}
+
+ {% endif %}
{% endfor %}
@@ -76,7 +81,7 @@ {% translate "Suggested plugins" %}
{% for optional_plugin in plugins.optional|dictsort:"enabled" %}
- {% include "partials/plugin_tile.html" with plugin=optional_plugin form_id="continue-to-configurationt" show_report_types="yes" plugin_report_types=plugin_data.plugin_report_types %}
+ {% include "partials/plugin_tile.html" with form_id="continue-to-configuration" plugin_report_types=plugin_data.plugin_report_types show_report_types="yes" plugin=optional_plugin remove_action_buttons="yes" add_checkbox="yes" %}
{% endfor %}
@@ -98,7 +103,7 @@ {% translate "Suggested plugins" %}
{% include "forms/report_form_fields.html" %}
{% else %}
diff --git a/rocky/reports/views/aggregate_report.py b/rocky/reports/views/aggregate_report.py
index af57fa39ab6..94e1db5ede5 100644
--- a/rocky/reports/views/aggregate_report.py
+++ b/rocky/reports/views/aggregate_report.py
@@ -1,10 +1,14 @@
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.translation import gettext_lazy as _
from django.views.generic import TemplateView
+from httpx import HTTPError
+from katalogus.client import get_katalogus
+from tools.view_helpers import PostRedirect
from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport
from reports.views.base import (
@@ -107,6 +111,28 @@ class ExportSetupAggregateReportView(
current_step = 4
report_type = AggregateOrganisationReport
+ def post(self, request, *args, **kwargs):
+ selected_plugins = request.POST.getlist("plugin", [])
+
+ if not selected_plugins:
+ return super().post(request, *args, **kwargs)
+
+ if not self.organization_member.has_perm("tools.can_enable_disable_boefje"):
+ messages.error(request, _("You do not have the required permissions to enable plugins."))
+ return PostRedirect(self.get_previous())
+
+ client = get_katalogus(self.organization.code)
+ for selected_plugin in selected_plugins:
+ try:
+ client.enable_boefje_by_id(selected_plugin)
+ except HTTPError:
+ messages.error(
+ request,
+ _("An error occurred while enabling {}. The plugin is not available.").format(selected_plugin),
+ )
+ return self.post(request, *args, **kwargs)
+ return super().post(request, *args, **kwargs)
+
class SaveAggregateReportView(SaveAggregateReportMixin, BreadcrumbsAggregateReportView, SaveReportView):
"""
diff --git a/rocky/reports/views/generate_report.py b/rocky/reports/views/generate_report.py
index 55a7457a8c7..4fa5169cb75 100644
--- a/rocky/reports/views/generate_report.py
+++ b/rocky/reports/views/generate_report.py
@@ -1,10 +1,14 @@
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.translation import gettext_lazy as _
from django.views.generic import TemplateView
+from httpx import HTTPError
+from katalogus.client import get_katalogus
+from tools.view_helpers import PostRedirect
from reports.views.base import (
REPORTS_PRE_SELECTION,
@@ -100,6 +104,28 @@ class ExportSetupGenerateReportView(GenerateReportStepsMixin, BreadcrumbsGenerat
breadcrumbs_step = 6
current_step = 4
+ def post(self, request, *args, **kwargs):
+ selected_plugins = request.POST.getlist("plugin", [])
+
+ if not selected_plugins:
+ return super().post(request, *args, **kwargs)
+
+ if not self.organization_member.has_perm("tools.can_enable_disable_boefje"):
+ messages.error(request, _("You do not have the required permissions to enable plugins."))
+ return PostRedirect(self.get_previous())
+
+ client = get_katalogus(self.organization.code)
+ for selected_plugin in selected_plugins:
+ try:
+ client.enable_boefje_by_id(selected_plugin)
+ except HTTPError:
+ messages.error(
+ request,
+ _("An error occurred while enabling {}. The plugin is not available.").format(selected_plugin),
+ )
+ return self.post(request, *args, **kwargs)
+ return super().post(request, *args, **kwargs)
+
class SaveGenerateReportView(SaveGenerateReportMixin, BreadcrumbsGenerateReportView, SaveReportView):
"""
diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot
index c896645a930..962ed1d10cf 100644
--- a/rocky/rocky/locale/django.pot
+++ b/rocky/rocky/locale/django.pot
@@ -1617,7 +1617,6 @@ msgstr ""
#: onboarding/templates/account/step_2a_organization_update.html
#: onboarding/templates/account/step_2b_indemnification_setup.html
#: onboarding/templates/step_3d_clearance_level_introduction.html
-#: reports/templates/partials/report_setup_scan.html
msgid "Continue"
msgstr ""
@@ -2385,7 +2384,8 @@ msgstr ""
msgid "Please select all required plugins to proceed."
msgstr ""
-#: onboarding/views.py
+#: onboarding/views.py reports/views/aggregate_report.py
+#: reports/views/generate_report.py
msgid "An error occurred while enabling {}. The plugin is not available."
msgstr ""
@@ -4063,6 +4063,10 @@ msgstr ""
msgid "There are no optional plugins."
msgstr ""
+#: reports/templates/partials/report_setup_scan.html
+msgid "Enable plugins and continue"
+msgstr ""
+
#: reports/templates/partials/report_severity_totals.html
#: reports/templates/partials/report_severity_totals_table.html
msgid "Findings overview"
@@ -4463,6 +4467,10 @@ msgstr ""
msgid "Save report"
msgstr ""
+#: reports/views/aggregate_report.py reports/views/generate_report.py
+msgid "You do not have the required permissions to enable plugins."
+msgstr ""
+
#: reports/views/base.py
msgid "Select at least one OOI to proceed."
msgstr ""
From 50273bd039a5e5d7510ccd8dbc65a74b8d5063d7 Mon Sep 17 00:00:00 2001
From: noamblitz <43830693+noamblitz@users.noreply.github.com>
Date: Tue, 26 Nov 2024 15:11:22 +0100
Subject: [PATCH 04/44] Let mailserver inherit l1 (#3704)
Co-authored-by: Jan Klopper
Co-authored-by: Jeroen Dekkers
---
octopoes/octopoes/models/ooi/dns/records.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/octopoes/octopoes/models/ooi/dns/records.py b/octopoes/octopoes/models/ooi/dns/records.py
index 8d63cf70ed4..972b20e4a07 100644
--- a/octopoes/octopoes/models/ooi/dns/records.py
+++ b/octopoes/octopoes/models/ooi/dns/records.py
@@ -50,7 +50,7 @@ class DNSMXRecord(DNSRecord):
object_type: Literal["DNSMXRecord"] = "DNSMXRecord"
dns_record_type: Literal["MX"] = "MX"
- mail_hostname: Reference | None = ReferenceField(Hostname, default=None)
+ mail_hostname: Reference | None = ReferenceField(Hostname, default=None, max_inherit_scan_level=1)
preference: int | None = None
_reverse_relation_names = {"hostname": "dns_mx_records", "mail_hostname": "mail_server_of"}
From f3c04823518b85c630d12a1a347bb9729ba5da87 Mon Sep 17 00:00:00 2001
From: noamblitz <43830693+noamblitz@users.noreply.github.com>
Date: Wed, 27 Nov 2024 11:18:24 +0100
Subject: [PATCH 05/44] Ignore specific url parameters when following location
headers (#3856)
Co-authored-by: Jan Klopper
Co-authored-by: ammar92
---
.../plugins/kat_answer_parser/normalize.py | 2 +-
boefjes/tests/plugins/test_answer_parser.py | 4 +--
.../bits/ask_url_params_to_ignore/__init__.py | 0
.../ask_url_params_to_ignore.py | 17 +++++++++++++
octopoes/bits/ask_url_params_to_ignore/bit.py | 10 ++++++++
.../question_schema.json | 17 +++++++++++++
octopoes/bits/oois_in_headers/bit.py | 6 ++++-
.../bits/oois_in_headers/oois_in_headers.py | 25 +++++++++++++++++--
.../tests/integration/test_ooi_deletion.py | 8 +++---
rocky/rocky/views/ooi_detail.py | 5 +++-
10 files changed, 83 insertions(+), 11 deletions(-)
create mode 100644 octopoes/bits/ask_url_params_to_ignore/__init__.py
create mode 100644 octopoes/bits/ask_url_params_to_ignore/ask_url_params_to_ignore.py
create mode 100644 octopoes/bits/ask_url_params_to_ignore/bit.py
create mode 100644 octopoes/bits/ask_url_params_to_ignore/question_schema.json
diff --git a/boefjes/boefjes/plugins/kat_answer_parser/normalize.py b/boefjes/boefjes/plugins/kat_answer_parser/normalize.py
index acef37ad53f..8e4d817c471 100644
--- a/boefjes/boefjes/plugins/kat_answer_parser/normalize.py
+++ b/boefjes/boefjes/plugins/kat_answer_parser/normalize.py
@@ -10,4 +10,4 @@ def run(input_ooi: dict, raw: bytes) -> Iterable[NormalizerOutput]:
bit_id = data["schema"].removeprefix("/bit/")
- yield Config(ooi=input_ooi["primary_key"], bit_id=bit_id, config=data["answer"])
+ yield Config(ooi=data["answer_ooi"], bit_id=bit_id, config=data["answer"])
diff --git a/boefjes/tests/plugins/test_answer_parser.py b/boefjes/tests/plugins/test_answer_parser.py
index 9762a2683ad..74e98fdb459 100644
--- a/boefjes/tests/plugins/test_answer_parser.py
+++ b/boefjes/tests/plugins/test_answer_parser.py
@@ -13,10 +13,10 @@ def test_config_yielded(normalizer_runner):
normalizer_runner.run(meta, bytes(raw, "UTF-8"))
with pytest.raises(ValidationError):
- raw = '{"schema": "/bit/port-classification-ip", "answer": [{"key": "test"}]}'
+ raw = '{"schema": "/bit/port-classification-ip", "answer": [{"key": "test"}], "answer_ooi": "Network|internet"}'
normalizer_runner.run(meta, bytes(raw, "UTF-8"))
- raw = '{"schema": "/bit/port-classification-ip", "answer": {"key": "test"}}'
+ raw = '{"schema": "/bit/port-classification-ip", "answer": {"key": "test"}, "answer_ooi": "Network|internet"}'
output = normalizer_runner.run(meta, bytes(raw, "UTF-8"))
assert len(output.observations) == 1
diff --git a/octopoes/bits/ask_url_params_to_ignore/__init__.py b/octopoes/bits/ask_url_params_to_ignore/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/octopoes/bits/ask_url_params_to_ignore/ask_url_params_to_ignore.py b/octopoes/bits/ask_url_params_to_ignore/ask_url_params_to_ignore.py
new file mode 100644
index 00000000000..971f1d68993
--- /dev/null
+++ b/octopoes/bits/ask_url_params_to_ignore/ask_url_params_to_ignore.py
@@ -0,0 +1,17 @@
+import json
+from collections.abc import Iterator
+from pathlib import Path
+from typing import Any
+
+from octopoes.models import OOI
+from octopoes.models.ooi.network import Network
+from octopoes.models.ooi.question import Question
+
+
+def run(input_ooi: Network, additional_oois: list, config: dict[str, Any]) -> Iterator[OOI]:
+ network = input_ooi
+
+ with (Path(__file__).parent / "question_schema.json").open() as f:
+ schema = json.load(f)
+
+ yield Question(ooi=network.reference, schema_id=schema["$id"], json_schema=json.dumps(schema))
diff --git a/octopoes/bits/ask_url_params_to_ignore/bit.py b/octopoes/bits/ask_url_params_to_ignore/bit.py
new file mode 100644
index 00000000000..f78db5af1ea
--- /dev/null
+++ b/octopoes/bits/ask_url_params_to_ignore/bit.py
@@ -0,0 +1,10 @@
+from bits.definitions import BitDefinition
+from octopoes.models.ooi.network import Network
+
+BIT = BitDefinition(
+ id="ask_url_params_to_ignore",
+ consumes=Network,
+ parameters=[],
+ min_scan_level=0,
+ module="bits.ask_url_params_to_ignore.ask_url_params_to_ignore",
+)
diff --git a/octopoes/bits/ask_url_params_to_ignore/question_schema.json b/octopoes/bits/ask_url_params_to_ignore/question_schema.json
new file mode 100644
index 00000000000..a8b368d7474
--- /dev/null
+++ b/octopoes/bits/ask_url_params_to_ignore/question_schema.json
@@ -0,0 +1,17 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "/bit/oois-in-headers",
+ "type": "object",
+ "default": {},
+ "required": [
+ "ignored_url_parameters"
+ ],
+ "properties": {
+ "ignored_url_parameters": {
+ "description": "Comma separated list of url parameters that are ignored when following location headers.",
+ "type": "string",
+ "pattern": "^(\\s*(,*)[^,]+,?\\s*)*$",
+ "default": "session_id, phpsessid, jsessionid, cifd, cftoken, asp.net_sessionid"
+ }
+ }
+}
diff --git a/octopoes/bits/oois_in_headers/bit.py b/octopoes/bits/oois_in_headers/bit.py
index eac7470aa10..70beea24333 100644
--- a/octopoes/bits/oois_in_headers/bit.py
+++ b/octopoes/bits/oois_in_headers/bit.py
@@ -2,5 +2,9 @@
from octopoes.models.types import HTTPHeader
BIT = BitDefinition(
- id="oois-in-headers", consumes=HTTPHeader, parameters=[], module="bits.oois_in_headers.oois_in_headers"
+ id="oois-in-headers",
+ consumes=HTTPHeader,
+ parameters=[],
+ module="bits.oois_in_headers.oois_in_headers",
+ config_ooi_relation_path="HTTPHeader.resource.website.hostname.network",
)
diff --git a/octopoes/bits/oois_in_headers/oois_in_headers.py b/octopoes/bits/oois_in_headers/oois_in_headers.py
index a6e67d15b08..cd49dd8dffb 100644
--- a/octopoes/bits/oois_in_headers/oois_in_headers.py
+++ b/octopoes/bits/oois_in_headers/oois_in_headers.py
@@ -1,7 +1,7 @@
import re
from collections.abc import Iterator
from typing import Any
-from urllib.parse import urljoin, urlparse
+from urllib.parse import parse_qs, urlencode, urljoin, urlparse, urlunparse
from pydantic import ValidationError
@@ -16,12 +16,33 @@ def is_url(input_str):
return bool(result.scheme)
+def get_ignored_url_params(config: dict, config_key: str, default: list) -> list[str]:
+ ignored_url_params = config.get(config_key)
+ if ignored_url_params is None:
+ return default
+ return [param.strip() for param in ignored_url_params.split(",")] if ignored_url_params else []
+
+
+def remove_ignored_params(url: str, ignored_params: list[str]) -> str:
+ parsed_url = urlparse(url)
+ query_params = parse_qs(parsed_url.query)
+ if not query_params:
+ return url
+ filtered_params = {k: v for k, v in query_params.items() if k.lower() not in ignored_params}
+ new_query = urlencode(filtered_params, doseq=True)
+ new_url = urlunparse(
+ (parsed_url.scheme, parsed_url.netloc, parsed_url.path, parsed_url.params, new_query, parsed_url.fragment)
+ )
+ return new_url
+
+
def run(input_ooi: HTTPHeader, additional_oois: list, config: dict[str, Any]) -> Iterator[OOI]:
network = Network(name="internet")
if input_ooi.key.lower() == "location":
+ ignored_url_params = get_ignored_url_params(config, "ignored_url_parameters", [])
if is_url(input_ooi.value):
- u = URL(raw=input_ooi.value, network=network.reference)
+ u = URL(raw=remove_ignored_params(input_ooi.value, ignored_url_params), network=network.reference)
else:
# url is not a url but a relative path
http_url = input_ooi.reference.tokenized.resource.web_url
diff --git a/octopoes/tests/integration/test_ooi_deletion.py b/octopoes/tests/integration/test_ooi_deletion.py
index 0ca8d56586a..ba288ed942a 100644
--- a/octopoes/tests/integration/test_ooi_deletion.py
+++ b/octopoes/tests/integration/test_ooi_deletion.py
@@ -131,9 +131,9 @@ def test_events_created_in_worker_during_handling(
xtdb_octopoes_service.process_event(event)
xtdb_octopoes_service.commit()
- assert len(event_manager.queue) == 7 # Handling OOI delete event triggers Origin delete event
+ assert len(event_manager.queue) == 8 # Handling OOI delete event triggers Origin delete event
- event = event_manager.queue[6] # OOID]elete event
+ event = event_manager.queue[7] # OOIDelete event
assert isinstance(event, OriginDBEvent)
assert event.operation_type.value == "delete"
@@ -229,7 +229,7 @@ def test_deletion_events_after_nxdomain(
event_manager.complete_process_events(xtdb_octopoes_service)
assert len(list(filter(lambda x: x.operation_type.value == "delete", event_manager.queue))) == 0
- assert xtdb_octopoes_service.ooi_repository.list_oois({OOI}, valid_time).count == 7
+ assert xtdb_octopoes_service.ooi_repository.list_oois({OOI}, valid_time).count == 8
nxd = NXDOMAIN(hostname=hostname.reference)
xtdb_octopoes_service.ooi_repository.save(nxd, valid_time)
@@ -250,7 +250,7 @@ def test_deletion_events_after_nxdomain(
event_manager.complete_process_events(xtdb_octopoes_service)
assert len(list(filter(lambda x: x.operation_type.value == "delete", event_manager.queue))) >= 3
- assert xtdb_octopoes_service.ooi_repository.list_oois({OOI}, valid_time).count == 5
+ assert xtdb_octopoes_service.ooi_repository.list_oois({OOI}, valid_time).count == 6
@pytest.mark.xfail(reason="Wappalyzer works on wrong input objects (to be addressed)")
diff --git a/rocky/rocky/views/ooi_detail.py b/rocky/rocky/views/ooi_detail.py
index 0e1eee8d2f3..e5edbeaa425 100644
--- a/rocky/rocky/views/ooi_detail.py
+++ b/rocky/rocky/views/ooi_detail.py
@@ -51,7 +51,10 @@ def answer_ooi_questions(self) -> None:
messages.error(self.request, error.message)
return
- self.bytes_client.upload_raw(schema_answer.encode(), {"answer", f"{self.ooi.schema_id}"}, self.ooi.ooi)
+ raw = json.dumps(
+ {"schema": self.ooi.schema_id, "answer": parsed_schema_answer, "answer_ooi": self.ooi.ooi}
+ ).encode()
+ self.bytes_client.upload_raw(raw, {"answer"}, self.ooi.primary_key)
messages.success(self.request, _("Question has been answered."))
def start_boefje_scan(self) -> None:
From 413ffe53898046bab7eafde5b2b7293b27edde83 Mon Sep 17 00:00:00 2001
From: JP Bruins Slot
Date: Wed, 27 Nov 2024 11:29:53 +0100
Subject: [PATCH 06/44] Add `auto_calculate_deadline` attribute to Scheduler
(#3869)
Co-authored-by: Rieven
Co-authored-by: Jan Klopper
---
mula/scheduler/schedulers/boefje.py | 9 ++++++++-
mula/scheduler/schedulers/normalizer.py | 10 ++++++++--
mula/scheduler/schedulers/report.py | 9 ++++++++-
mula/scheduler/schedulers/scheduler.py | 4 +++-
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/mula/scheduler/schedulers/boefje.py b/mula/scheduler/schedulers/boefje.py
index a6768b884b5..c229a0f99d7 100644
--- a/mula/scheduler/schedulers/boefje.py
+++ b/mula/scheduler/schedulers/boefje.py
@@ -68,7 +68,14 @@ def __init__(
pq_store=ctx.datastores.pq_store,
)
- super().__init__(ctx=ctx, queue=self.queue, scheduler_id=scheduler_id, callback=callback, create_schedule=True)
+ super().__init__(
+ ctx=ctx,
+ queue=self.queue,
+ scheduler_id=scheduler_id,
+ callback=callback,
+ create_schedule=True,
+ auto_calculate_deadline=True,
+ )
# Priority ranker
self.priority_ranker = rankers.BoefjeRanker(self.ctx)
diff --git a/mula/scheduler/schedulers/normalizer.py b/mula/scheduler/schedulers/normalizer.py
index e193a3b8398..d633b061274 100644
--- a/mula/scheduler/schedulers/normalizer.py
+++ b/mula/scheduler/schedulers/normalizer.py
@@ -38,7 +38,6 @@ def __init__(
):
self.logger: structlog.BoundLogger = structlog.getLogger(__name__)
self.organisation: Organisation = organisation
- self.create_schedule = False
self.queue = queue or queues.PriorityQueue(
pq_id=scheduler_id,
@@ -48,7 +47,14 @@ def __init__(
pq_store=ctx.datastores.pq_store,
)
- super().__init__(ctx=ctx, queue=self.queue, scheduler_id=scheduler_id, callback=callback)
+ super().__init__(
+ ctx=ctx,
+ queue=self.queue,
+ scheduler_id=scheduler_id,
+ callback=callback,
+ create_schedule=False,
+ auto_calculate_deadline=False,
+ )
self.ranker = rankers.NormalizerRanker(ctx=self.ctx)
diff --git a/mula/scheduler/schedulers/report.py b/mula/scheduler/schedulers/report.py
index 321dad01034..833bbed3008 100644
--- a/mula/scheduler/schedulers/report.py
+++ b/mula/scheduler/schedulers/report.py
@@ -36,7 +36,14 @@ def __init__(
pq_store=ctx.datastores.pq_store,
)
- super().__init__(ctx=ctx, queue=self.queue, scheduler_id=scheduler_id, callback=callback, create_schedule=True)
+ super().__init__(
+ ctx=ctx,
+ queue=self.queue,
+ scheduler_id=scheduler_id,
+ callback=callback,
+ create_schedule=True,
+ auto_calculate_deadline=False,
+ )
def run(self) -> None:
# Rescheduling
diff --git a/mula/scheduler/schedulers/scheduler.py b/mula/scheduler/schedulers/scheduler.py
index b8cf74e1434..22eaf56af4c 100644
--- a/mula/scheduler/schedulers/scheduler.py
+++ b/mula/scheduler/schedulers/scheduler.py
@@ -61,6 +61,7 @@ def __init__(
callback: Callable[..., None] | None = None,
max_tries: int = -1,
create_schedule: bool = False,
+ auto_calculate_deadline: bool = True,
):
"""Initialize the Scheduler.
@@ -88,6 +89,7 @@ def __init__(
self.max_tries: int = max_tries
self.enabled: bool = True
self.create_schedule: bool = create_schedule
+ self.auto_calculate_deadline: bool = auto_calculate_deadline
self._last_activity: datetime | None = None
# Queue
@@ -327,7 +329,7 @@ def post_push(self, item: models.Task) -> models.Task:
# based on the item.
if schedule_db.schedule is not None:
schedule_db.deadline_at = cron.next_run(schedule_db.schedule)
- else:
+ elif self.auto_calculate_deadline:
schedule_db.deadline_at = self.calculate_deadline(item)
self.ctx.datastores.schedule_store.update_schedule(schedule_db)
From 2586547ed23488e13042759d2ef14013f865a7e8 Mon Sep 17 00:00:00 2001
From: Rieven
Date: Wed, 27 Nov 2024 11:40:38 +0100
Subject: [PATCH 07/44] Fix for task id as valid UUID (#3744)
Co-authored-by: Jan Klopper
---
rocky/rocky/scheduler.py | 8 +++-
rocky/rocky/views/scheduler.py | 47 +++++++++++--------
rocky/rocky/views/task_detail.py | 1 +
rocky/rocky/views/tasks.py | 13 ++---
.../tests/scheduler/test_scheduler_errors.py | 30 +++++++++++-
5 files changed, 67 insertions(+), 32 deletions(-)
diff --git a/rocky/rocky/scheduler.py b/rocky/rocky/scheduler.py
index 10fe3daded0..db01e932fed 100644
--- a/rocky/rocky/scheduler.py
+++ b/rocky/rocky/scheduler.py
@@ -322,7 +322,7 @@ def list_tasks(self, **kwargs) -> PaginatedTasksResponse:
filter_key = "filters"
params = {k: v for k, v in kwargs.items() if v is not None if k != filter_key} # filter Nones from kwargs
endpoint = "/tasks"
- res = self._client.post(endpoint, params=params, json=kwargs.get(filter_key, None))
+ res = self._client.post(endpoint, params=params, json=kwargs.get(filter_key))
return PaginatedTasksResponse.model_validate_json(res.content)
except ValidationError:
raise SchedulerValidationError(extra_message=_("Task list: "))
@@ -330,7 +330,11 @@ def list_tasks(self, **kwargs) -> PaginatedTasksResponse:
raise SchedulerConnectError(extra_message=_("Task list: "))
def get_task_details(self, task_id: str) -> Task:
- return Task.model_validate_json(self._get(f"/tasks/{task_id}", "content"))
+ try:
+ task_id = str(uuid.UUID(task_id))
+ return Task.model_validate_json(self._get(f"/tasks/{task_id}", "content"))
+ except ValueError:
+ raise SchedulerTaskNotFound()
def push_task(self, item: Task) -> None:
try:
diff --git a/rocky/rocky/views/scheduler.py b/rocky/rocky/views/scheduler.py
index b3c4c2e8736..731a114ecab 100644
--- a/rocky/rocky/views/scheduler.py
+++ b/rocky/rocky/views/scheduler.py
@@ -3,7 +3,7 @@
from typing import Any
from django.contrib import messages
-from django.http import JsonResponse
+from django.http import Http404, JsonResponse
from django.utils.translation import gettext_lazy as _
from katalogus.client import Boefje, Normalizer
from reports.forms import (
@@ -107,13 +107,14 @@ def get_report_child_name_form(self):
return self.report_child_name_form()
def get_task_details(self, task_id: str) -> Task | None:
- task = self.scheduler_client.get_task_details(task_id)
-
- if task.organization_id() != self.organization.code:
- messages.error(self.request, SchedulerTaskNotFound.message)
- return None
+ try:
+ task = self.scheduler_client.get_task_details(task_id)
+ if task.organization_id() != self.organization.code:
+ raise SchedulerTaskNotFound()
- return task
+ return task
+ except SchedulerTaskNotFound:
+ raise Http404()
def create_report_schedule(self, report_recipe: ReportRecipe, deadline_at: datetime) -> ScheduleResponse | None:
try:
@@ -163,7 +164,7 @@ def get_output_oois(self, task):
messages.error(self.request, error.message)
return []
- def get_json_task_details(self) -> JsonResponse | None:
+ def get_json_task_details(self) -> JsonResponse:
try:
task = self.get_task_details(self.kwargs["task_id"])
if task:
@@ -174,9 +175,11 @@ def get_json_task_details(self) -> JsonResponse | None:
},
safe=False,
)
- return task
- except SchedulerError as error:
- return messages.error(self.request, error.message)
+ else:
+ raise SchedulerTaskNotFound()
+
+ except SchedulerTaskNotFound:
+ raise Http404()
def get_schedule_details(self, schedule_id: str) -> ScheduleResponse:
try:
@@ -211,18 +214,22 @@ def schedule_task(self, task: Task) -> None:
# task info from the scheduler. Task data should be available from the context
# from which the task is created.
def reschedule_task(self, task_id: str) -> None:
- task = self.scheduler_client.get_task_details(task_id)
-
- if task.organization_id() != self.organization.code:
- messages.error(self.request, SchedulerTaskNotFound.message)
- return
+ try:
+ task = self.get_task_details(task_id)
+ if task:
+ if task.organization_id() != self.organization.code:
+ raise SchedulerTaskNotFound()
- new_id = uuid.uuid4()
- task.data.id = new_id
+ new_id = uuid.uuid4()
+ task.data.id = new_id
- new_task = Task(id=new_id, scheduler_id=task.scheduler_id, priority=1, data=task.data)
+ new_task = Task(id=new_id, scheduler_id=task.scheduler_id, priority=1, data=task.data)
- self.schedule_task(new_task)
+ self.schedule_task(new_task)
+ else:
+ raise SchedulerTaskNotFound()
+ except SchedulerTaskNotFound:
+ raise Http404()
def run_normalizer(self, katalogus_normalizer: Normalizer, raw_data: RawData) -> None:
try:
diff --git a/rocky/rocky/views/task_detail.py b/rocky/rocky/views/task_detail.py
index 3fba9eb1a05..8446fc205e7 100644
--- a/rocky/rocky/views/task_detail.py
+++ b/rocky/rocky/views/task_detail.py
@@ -57,6 +57,7 @@ def get_context_data(self, **kwargs):
class NormalizerTaskJSONView(TaskDetailView):
task_type = "normalizer"
plugin_type = "normalizer"
+ template_name = "tasks/normalizer_task_detail.html"
def get(self, request, *args, **kwargs) -> JsonResponse | HttpResponse:
task = self.get_json_task_details()
diff --git a/rocky/rocky/views/tasks.py b/rocky/rocky/views/tasks.py
index 44762de4b88..f6808296e16 100644
--- a/rocky/rocky/views/tasks.py
+++ b/rocky/rocky/views/tasks.py
@@ -31,15 +31,10 @@ def get_queryset(self):
return self.get_task_list()
def post(self, request, *args, **kwargs):
- try:
- if self.action == self.RESCHEDULE_TASK:
- task_id = self.request.POST.get("task_id", "")
- self.reschedule_task(task_id)
- except HTTPError as exc:
- message = f"HTTP error for {exc.request.url} - {exc}"
- messages.error(request, message)
- except SchedulerError as error:
- messages.error(request, error.message)
+ if self.action == self.RESCHEDULE_TASK:
+ task_id = self.request.POST.get("task_id", "")
+ self.reschedule_task(task_id)
+
return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
diff --git a/rocky/tests/scheduler/test_scheduler_errors.py b/rocky/tests/scheduler/test_scheduler_errors.py
index b9229216aab..94d8cb5493b 100644
--- a/rocky/tests/scheduler/test_scheduler_errors.py
+++ b/rocky/tests/scheduler/test_scheduler_errors.py
@@ -1,4 +1,13 @@
-from rocky.scheduler import SchedulerConnectError, SchedulerTooManyRequestError, SchedulerValidationError
+import pytest
+from django.http import Http404
+
+from rocky.scheduler import (
+ SchedulerConnectError,
+ SchedulerTaskNotFound,
+ SchedulerTooManyRequestError,
+ SchedulerValidationError,
+)
+from rocky.views.task_detail import NormalizerTaskJSONView
from rocky.views.tasks import BoefjesTaskListView
from tests.conftest import setup_request
@@ -37,3 +46,22 @@ def test_tasks_view_too_many_requests_error(rf, client_member, mock_scheduler):
list(request._messages)[0].message
== "Scheduler is receiving too many requests. Increase SCHEDULER_PQ_MAXSIZE or wait for task to finish."
)
+
+
+def test_get_task_details_json_bad_task_id(rf, client_member, mock_scheduler):
+ mock_scheduler.get_task_details.side_effect = SchedulerTaskNotFound
+ request = setup_request(rf.get("normalizer_task_view"), client_member.user)
+
+ with pytest.raises(Http404):
+ NormalizerTaskJSONView.as_view()(request, organization_code=client_member.organization.code, task_id="/delete")
+
+
+def test_reschedule_task_bad_task_id(rf, client_member, mock_bytes_client, mock_scheduler):
+ mock_scheduler.get_task_details.side_effect = SchedulerTaskNotFound
+
+ request = setup_request(
+ rf.post("task_list", {"action": "reschedule_task", "task_id": "/delete"}), client_member.user
+ )
+
+ with pytest.raises(Http404):
+ BoefjesTaskListView.as_view()(request, organization_code=client_member.organization.code)
From 041f18c60219051f5e58c272e236ca7666620380 Mon Sep 17 00:00:00 2001
From: Jeroen Dekkers
Date: Wed, 27 Nov 2024 11:43:37 +0100
Subject: [PATCH 08/44] Increase max number of PostgreSQL connections (#3889)
Co-authored-by: Jan Klopper
---
docker-compose.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/docker-compose.yml b/docker-compose.yml
index 7ad1333c859..d56efc4baa0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -23,6 +23,9 @@ services:
test: ["CMD", "gosu", "postgres", "pg_isready"]
interval: 10s
retries: 10
+ # Django runserver does not limit the number of threads. We need to increase
+ # the maximum number of connection to make sure that we don't hit the limit.
+ command: -c max_connections=500
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.sh
From ff6d154b9d9ba3e805c5b33e21a36125d04960db Mon Sep 17 00:00:00 2001
From: "Weblate (bot)"
Date: Wed, 27 Nov 2024 12:33:33 +0100
Subject: [PATCH 09/44] Translations update from Hosted Weblate (#3870)
Co-authored-by: Wim Benes
Co-authored-by: Jan Klopper
---
rocky/rocky/locale/de/LC_MESSAGES/django.po | 280 +++++++++---
.../locale/en@pirate/LC_MESSAGES/django.po | 280 +++++++++---
rocky/rocky/locale/fr/LC_MESSAGES/django.po | 280 +++++++++---
rocky/rocky/locale/fy/LC_MESSAGES/django.po | 411 +++++++++++++-----
rocky/rocky/locale/it/LC_MESSAGES/django.po | 287 +++++++++---
rocky/rocky/locale/nl/LC_MESSAGES/django.po | 373 ++++++++++++----
rocky/rocky/locale/pap/LC_MESSAGES/django.po | 285 +++++++++---
7 files changed, 1691 insertions(+), 505 deletions(-)
diff --git a/rocky/rocky/locale/de/LC_MESSAGES/django.po b/rocky/rocky/locale/de/LC_MESSAGES/django.po
index 4fa1ec3fce0..6bad84d4c6f 100644
--- a/rocky/rocky/locale/de/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
"PO-Revision-Date: 2024-07-17 09:09+0000\n"
"Last-Translator: LibreTranslate \n"
"Language-Team: German Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -4042,7 +4077,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4252,6 +4316,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4276,12 +4404,6 @@ msgstr ""
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4371,10 +4493,8 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4411,6 +4531,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr ""
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4550,6 +4676,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr ""
@@ -5360,12 +5520,6 @@ msgstr ""
msgid " Finding Details"
msgstr ""
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr ""
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5474,8 +5628,12 @@ msgid "findings"
msgstr ""
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -5863,6 +6021,11 @@ msgstr ""
msgid "Score"
msgstr ""
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr ""
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr ""
@@ -5946,7 +6109,7 @@ msgid "Save %(display_type)s"
msgstr ""
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
+msgid "Currently no findings have been identified for OOI"
msgstr ""
#: rocky/templates/oois/ooi_list.html
@@ -5961,10 +6124,6 @@ msgstr ""
msgid "Objects "
msgstr ""
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr ""
@@ -6079,6 +6238,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr ""
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr ""
@@ -6099,10 +6262,6 @@ msgstr ""
msgid "Save organization"
msgstr ""
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr ""
@@ -6116,6 +6275,15 @@ msgstr ""
msgid "Tags"
msgstr ""
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr ""
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr ""
@@ -6241,10 +6409,6 @@ msgstr ""
msgid "Add indemnification"
msgstr ""
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr ""
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr ""
@@ -6690,10 +6854,6 @@ msgstr ""
msgid "Download meta data"
msgstr ""
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr ""
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -6713,7 +6873,7 @@ msgstr ""
msgid "List of tasks for boefjes"
msgstr ""
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
diff --git a/rocky/rocky/locale/en@pirate/LC_MESSAGES/django.po b/rocky/rocky/locale/en@pirate/LC_MESSAGES/django.po
index 6c9f118771a..7fc976beb52 100644
--- a/rocky/rocky/locale/en@pirate/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/en@pirate/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
"PO-Revision-Date: 2023-11-18 13:03+0000\n"
"Last-Translator: jan klopper \n"
"Language-Team: English (Pirate) Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -3860,7 +3895,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4070,6 +4134,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4094,12 +4222,6 @@ msgstr ""
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4189,10 +4311,8 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4229,6 +4349,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr ""
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4368,6 +4494,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr ""
@@ -5178,12 +5338,6 @@ msgstr ""
msgid " Finding Details"
msgstr ""
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr ""
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5292,8 +5446,12 @@ msgid "findings"
msgstr ""
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -5681,6 +5839,11 @@ msgstr ""
msgid "Score"
msgstr ""
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr ""
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr ""
@@ -5764,7 +5927,7 @@ msgid "Save %(display_type)s"
msgstr ""
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
+msgid "Currently no findings have been identified for OOI"
msgstr ""
#: rocky/templates/oois/ooi_list.html
@@ -5779,10 +5942,6 @@ msgstr ""
msgid "Objects "
msgstr ""
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr ""
@@ -5897,6 +6056,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr ""
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr ""
@@ -5917,10 +6080,6 @@ msgstr ""
msgid "Save organization"
msgstr ""
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr ""
@@ -5934,6 +6093,15 @@ msgstr ""
msgid "Tags"
msgstr ""
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr ""
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr ""
@@ -6059,10 +6227,6 @@ msgstr ""
msgid "Add indemnification"
msgstr ""
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr ""
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr ""
@@ -6508,10 +6672,6 @@ msgstr ""
msgid "Download meta data"
msgstr ""
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr ""
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -6531,7 +6691,7 @@ msgstr ""
msgid "List of tasks for boefjes"
msgstr ""
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
diff --git a/rocky/rocky/locale/fr/LC_MESSAGES/django.po b/rocky/rocky/locale/fr/LC_MESSAGES/django.po
index 3c941ab1622..4fd6a02ef13 100644
--- a/rocky/rocky/locale/fr/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/fr/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -30,6 +30,10 @@ msgstr ""
#: reports/report_types/dns_report/report.html
#: reports/report_types/tls_report/report.html
#: reports/templates/partials/report_names_form.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -348,6 +352,7 @@ msgstr ""
#: account/templates/account_detail.html
#: rocky/templates/crisis_room/crisis_room_findings_block.html
+#: rocky/templates/tasks/normalizers.html
msgid "Organization"
msgstr ""
@@ -599,20 +604,16 @@ msgid ""
msgstr ""
#: katalogus/client.py
-msgid "Boefje with this name already exists."
-msgstr ""
-
-#: katalogus/client.py
-msgid "Boefje with this ID already exists."
+#, python-format
+msgid "An HTTP %d error occurred. Check logs for more info."
msgstr ""
#: katalogus/client.py
-msgid "Editing this boefje is not allowed because it is static."
+msgid "Boefje with this name already exists."
msgstr ""
#: katalogus/client.py
-#, python-format
-msgid "An HTTP %d error occurred. Check logs for more info."
+msgid "Boefje with this ID already exists."
msgstr ""
#: katalogus/forms/katalogus_filter.py
@@ -939,7 +940,6 @@ msgstr ""
#: katalogus/templates/partials/boefje_tile.html
#: katalogus/templates/partials/plugin_tile.html
#: katalogus/templates/partials/plugin_tile_modal.html
-#: katalogus/templates/partials/plugins.html
msgid "See details"
msgstr ""
@@ -1006,7 +1006,6 @@ msgstr ""
#: katalogus/templates/plugin_settings_list.html
#: katalogus/views/katalogus_settings.py tools/view_helpers.py
#: rocky/templates/header.html
-#: rocky/templates/organizations/organization_settings.html
msgid "Settings"
msgstr ""
@@ -1018,6 +1017,18 @@ msgstr ""
msgid "Tableview"
msgstr ""
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Required for"
+msgstr ""
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "report types"
+msgstr ""
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Report types for "
+msgstr ""
+
#: katalogus/templates/partials/objects_to_scan.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/forms/widgets/checkbox_group_table.html
@@ -1120,10 +1131,16 @@ msgid "Plugin description"
msgstr ""
#: katalogus/templates/partials/plugins.html
+#: reports/templates/report_overview/report_history_table.html
+#: rocky/templates/organizations/organization_list.html
#: rocky/templates/organizations/organization_settings.html
msgid "Actions"
msgstr ""
+#: katalogus/templates/partials/plugins.html
+msgid "Detail page"
+msgstr ""
+
#: katalogus/templates/partials/plugins_navigation.html
#: reports/templates/report_overview/report_overview_navigation.html
msgid "Plugins Navigation"
@@ -1256,6 +1273,8 @@ msgid "Boefje ID"
msgstr ""
#: katalogus/templates/plugin_container_image.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -1355,6 +1374,8 @@ msgstr ""
#: katalogus/templates/plugin_settings_delete.html
#: katalogus/views/plugin_settings_delete.py
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/report_history_table.html
#: rocky/templates/admin/delete_confirmation.html rocky/views/ooi_delete.py
msgid "Delete"
msgstr ""
@@ -2021,6 +2042,8 @@ msgstr ""
#: onboarding/templates/step_3c_setup_scan_ooi_detail.html
#: reports/report_types/dns_report/report.html
#: reports/templates/partials/report_ooi_list.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/summary/ooi_selection.html tools/forms/ooi.py
#: rocky/templates/oois/ooi_list.html
#: rocky/templates/partials/elements/ooi_tree_condensed_table.html
@@ -2395,15 +2418,19 @@ msgid "Different date"
msgstr ""
#: reports/forms.py
-msgid "Start date"
+msgid "No, just once"
msgstr ""
#: reports/forms.py
-msgid "No, just once"
+msgid "Yes, repeat"
msgstr ""
#: reports/forms.py
-msgid "Yes, repeat"
+msgid "Start date"
+msgstr ""
+
+#: reports/forms.py
+msgid "Start time (UTC)"
msgstr ""
#: reports/forms.py
@@ -2485,6 +2512,7 @@ msgstr ""
#: reports/report_types/aggregate_organisation_report/appendix.html
#: reports/templates/partials/plugin_overview_table.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -3004,7 +3032,6 @@ msgid "Other findings found"
msgstr ""
#: reports/report_types/dns_report/report.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/oois/ooi_detail_findings_list.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
@@ -3044,7 +3071,6 @@ msgstr ""
#: reports/report_types/findings_report/report.html
#: reports/report_types/vulnerability_report/report.html
#: reports/templates/partials/report_severity_totals_table.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
#: rocky/templates/partials/ooi_report_findings_block_table.html
#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
@@ -3089,7 +3115,8 @@ msgid "First seen"
msgstr ""
#: reports/report_types/findings_report/report.html
-msgid "No findings have been found."
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "No findings have been identified yet."
msgstr ""
#: reports/report_types/findings_report/report.py
@@ -3658,7 +3685,7 @@ msgid "Has a certificate"
msgstr ""
#: reports/report_types/web_system_report/report.html
-msgid "Certificate is not expired"
+msgid "Certificate is valid"
msgstr ""
#: reports/report_types/web_system_report/report.html
@@ -3689,6 +3716,13 @@ msgid ""
"single occasion, select the one-time option."
msgstr ""
+#: reports/templates/partials/export_report_settings.html
+msgid ""
+"Please choose a start date, time and recurrence for scheduling your "
+"report(s). If you select a date on the 28th-31st of the month, it will "
+"always be scheduled on the last day of the month."
+msgstr ""
+
#: reports/templates/partials/export_report_settings.html
msgid ""
"The date you select will be the reference date for the data set for your "
@@ -3808,20 +3842,21 @@ msgid ""
msgstr ""
#: reports/templates/partials/report_names_header.html
+#, python-brace-format
msgid ""
"To make the report names more descriptive, you can include placeholders for "
"the object name, the report type and/or the reference date. For subreports "
-"and reports over a single object, use the placeholder \"{ooi}\" for the "
-"object name, \"{report type}\" for the report type and use a Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -3857,7 +3892,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4067,6 +4131,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4091,12 +4219,6 @@ msgstr ""
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4186,10 +4308,8 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4226,6 +4346,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr ""
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4365,6 +4491,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr ""
@@ -5175,12 +5335,6 @@ msgstr ""
msgid " Finding Details"
msgstr ""
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr ""
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5289,8 +5443,12 @@ msgid "findings"
msgstr ""
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -5678,6 +5836,11 @@ msgstr ""
msgid "Score"
msgstr ""
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr ""
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr ""
@@ -5761,7 +5924,7 @@ msgid "Save %(display_type)s"
msgstr ""
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
+msgid "Currently no findings have been identified for OOI"
msgstr ""
#: rocky/templates/oois/ooi_list.html
@@ -5776,10 +5939,6 @@ msgstr ""
msgid "Objects "
msgstr ""
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr ""
@@ -5894,6 +6053,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr ""
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr ""
@@ -5914,10 +6077,6 @@ msgstr ""
msgid "Save organization"
msgstr ""
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr ""
@@ -5931,6 +6090,15 @@ msgstr ""
msgid "Tags"
msgstr ""
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr ""
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr ""
@@ -6056,10 +6224,6 @@ msgstr ""
msgid "Add indemnification"
msgstr ""
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr ""
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr ""
@@ -6505,10 +6669,6 @@ msgstr ""
msgid "Download meta data"
msgstr ""
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr ""
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -6528,7 +6688,7 @@ msgstr ""
msgid "List of tasks for boefjes"
msgstr ""
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
diff --git a/rocky/rocky/locale/fy/LC_MESSAGES/django.po b/rocky/rocky/locale/fy/LC_MESSAGES/django.po
index 6fce6a3eb4f..81f6c980f88 100644
--- a/rocky/rocky/locale/fy/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/fy/LC_MESSAGES/django.po
@@ -9,17 +9,17 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
-"PO-Revision-Date: 2024-11-02 20:00+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
+"PO-Revision-Date: 2024-11-22 17:00+0000\n"
"Last-Translator: Wim Benes \n"
-"Language-Team: Frisian \n"
+"Language-Team: Frisian \n"
"Language: fy\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.8.2\n"
+"X-Generator: Weblate 5.9-dev\n"
#: account/admin.py
msgid "Permissions"
@@ -34,6 +34,10 @@ msgstr "Wichtige datums"
#: reports/report_types/dns_report/report.html
#: reports/report_types/tls_report/report.html
#: reports/templates/partials/report_names_form.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -375,6 +379,7 @@ msgstr "Soarte fan lid"
#: account/templates/account_detail.html
#: rocky/templates/crisis_room/crisis_room_findings_block.html
+#: rocky/templates/tasks/normalizers.html
msgid "Organization"
msgstr "Organisaasje"
@@ -657,6 +662,12 @@ msgstr ""
"De KATalogus hat in ûnferwachte flater oprûn. Kontrolearje de lochboeken "
"foar mear details."
+#: katalogus/client.py
+#, python-format
+msgid "An HTTP %d error occurred. Check logs for more info."
+msgstr ""
+"Der is in HTTP-%d-flater bard. Kontrolearje de lochboeken foar mear ynfo."
+
#: katalogus/client.py
msgid "Boefje with this name already exists."
msgstr "Boefje mei dizze namme bestiet al."
@@ -665,16 +676,6 @@ msgstr "Boefje mei dizze namme bestiet al."
msgid "Boefje with this ID already exists."
msgstr "Boefje mei dizze ID bestiet al."
-#: katalogus/client.py
-msgid "Editing this boefje is not allowed because it is static."
-msgstr "Dit Boefje bewurkje is net tastien, omdat it statysk is."
-
-#: katalogus/client.py
-#, python-format
-msgid "An HTTP %d error occurred. Check logs for more info."
-msgstr ""
-"Der is in HTTP-%d-flater bard. Kontrolearje de lochboeken foar mear ynfo."
-
#: katalogus/forms/katalogus_filter.py
msgid "Show all"
msgstr "Alles toane"
@@ -823,8 +824,8 @@ msgstr ""
" Jo kinne in nij Boefje meitsje. As jo hjir mear ynfo "
"oer wolle,\n"
" kinne jo de dokumintaasje neilêze.\n"
+"developer_documentation/development_tutorial/creating_a_boefje."
+"html\">dokumintaasje neilêze.\n"
" "
#: katalogus/templates/boefje_setup.html
@@ -1035,7 +1036,6 @@ msgstr "Utjouwer:"
#: katalogus/templates/partials/boefje_tile.html
#: katalogus/templates/partials/plugin_tile.html
#: katalogus/templates/partials/plugin_tile_modal.html
-#: katalogus/templates/partials/plugins.html
msgid "See details"
msgstr "Details besjen"
@@ -1102,7 +1102,6 @@ msgstr "In oersjoch fan alle beskikbere ynstekkers."
#: katalogus/templates/plugin_settings_list.html
#: katalogus/views/katalogus_settings.py tools/view_helpers.py
#: rocky/templates/header.html
-#: rocky/templates/organizations/organization_settings.html
msgid "Settings"
msgstr "Ynstellingen"
@@ -1114,6 +1113,18 @@ msgstr "Rasterwerjefte"
msgid "Tableview"
msgstr "Tabelwerjefte"
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Required for"
+msgstr "Fereaske foar"
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "report types"
+msgstr "rapporttypen"
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Report types for "
+msgstr "Rapporttypen foar "
+
#: katalogus/templates/partials/objects_to_scan.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/forms/widgets/checkbox_group_table.html
@@ -1231,10 +1242,16 @@ msgid "Plugin description"
msgstr "Ynstekkerbeskriuwing"
#: katalogus/templates/partials/plugins.html
+#: reports/templates/report_overview/report_history_table.html
+#: rocky/templates/organizations/organization_list.html
#: rocky/templates/organizations/organization_settings.html
msgid "Actions"
msgstr "Aksjes"
+#: katalogus/templates/partials/plugins.html
+msgid "Detail page"
+msgstr "Detailside"
+
#: katalogus/templates/partials/plugins_navigation.html
#: reports/templates/report_overview/report_overview_navigation.html
msgid "Plugins Navigation"
@@ -1373,6 +1390,8 @@ msgid "Boefje ID"
msgstr "Boefje-ID"
#: katalogus/templates/plugin_container_image.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -1500,6 +1519,8 @@ msgstr ""
#: katalogus/templates/plugin_settings_delete.html
#: katalogus/views/plugin_settings_delete.py
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/report_history_table.html
#: rocky/templates/admin/delete_confirmation.html rocky/views/ooi_delete.py
msgid "Delete"
msgstr "Fuortsmite"
@@ -2291,6 +2312,8 @@ msgstr "URL"
#: onboarding/templates/step_3c_setup_scan_ooi_detail.html
#: reports/report_types/dns_report/report.html
#: reports/templates/partials/report_ooi_list.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/summary/ooi_selection.html tools/forms/ooi.py
#: rocky/templates/oois/ooi_list.html
#: rocky/templates/partials/elements/ooi_tree_condensed_table.html
@@ -2690,10 +2713,6 @@ msgstr "Hjoed"
msgid "Different date"
msgstr "Oare datum"
-#: reports/forms.py
-msgid "Start date"
-msgstr "Startdatum"
-
#: reports/forms.py
msgid "No, just once"
msgstr "Nee, mar ien kear"
@@ -2702,6 +2721,14 @@ msgstr "Nee, mar ien kear"
msgid "Yes, repeat"
msgstr "Ja, werhelje"
+#: reports/forms.py
+msgid "Start date"
+msgstr "Startdatum"
+
+#: reports/forms.py
+msgid "Start time (UTC)"
+msgstr ""
+
#: reports/forms.py
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Recurrence"
@@ -2781,6 +2808,7 @@ msgstr "Selektearre rapporttypen"
#: reports/report_types/aggregate_organisation_report/appendix.html
#: reports/templates/partials/plugin_overview_table.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -3302,7 +3330,6 @@ msgid "Other findings found"
msgstr "Oare befiningen fûn"
#: reports/report_types/dns_report/report.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/oois/ooi_detail_findings_list.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
@@ -3342,7 +3369,6 @@ msgstr "Befiningenynformaasje"
#: reports/report_types/findings_report/report.html
#: reports/report_types/vulnerability_report/report.html
#: reports/templates/partials/report_severity_totals_table.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
#: rocky/templates/partials/ooi_report_findings_block_table.html
#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
@@ -3387,8 +3413,9 @@ msgid "First seen"
msgstr "Earst sjoen"
#: reports/report_types/findings_report/report.html
-msgid "No findings have been found."
-msgstr "Der binne gjin befiningen fûn."
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "No findings have been identified yet."
+msgstr ""
#: reports/report_types/findings_report/report.py
msgid "Findings Report"
@@ -3772,6 +3799,8 @@ msgid ""
"Shows whether the IP is covered by a valid RPKI ROA. For a hostname it shows "
"the IP addresses and whether they are covered by a valid RPKI ROA."
msgstr ""
+"Toant oft in IP falt ûnder in falide RPKI ROA. Toant foar in hostnamme de IP-"
+"adressen en oft se dekt binne troch in falide RPKI ROA."
#: reports/report_types/safe_connections_report/report.html
msgid ""
@@ -3785,15 +3814,15 @@ msgstr ""
#: reports/report_types/safe_connections_report/report.html
msgid "Safe connections compliance"
-msgstr ""
+msgstr "Compliance feilige ferbiningen"
#: reports/report_types/safe_connections_report/report.py
msgid "Safe Connections Report"
-msgstr ""
+msgstr "Feilige Ferbiningen-rapport"
#: reports/report_types/safe_connections_report/report.py
msgid "Shows whether the IPService contains safe ciphers."
-msgstr ""
+msgstr "Toant oft de IP-service feilige fersiferingen brûkt."
#: reports/report_types/systems_report/report.html
msgid ""
@@ -3807,43 +3836,47 @@ msgstr ""
#: reports/report_types/systems_report/report.html
msgid "Selected assets"
-msgstr ""
+msgstr "Selektearre assets"
#: reports/report_types/systems_report/report.html
msgid "No system types have been identified on this system."
-msgstr ""
+msgstr "Der binne gjin systeemtypen op dit systeem identifisearre."
#: reports/report_types/systems_report/report.py
msgid "System Report"
-msgstr ""
+msgstr "Systeemrapport"
#: reports/report_types/systems_report/report.py
msgid "Combine IP addresses, hostnames and services into systems."
-msgstr ""
+msgstr "Kombinearje IP-adressen, hostnammen en services yn systemen."
#: reports/report_types/tls_report/report.html
msgid ""
"The TLS Report shows which TLS protocols and ciphers were identified on the "
"host for the provided port."
msgstr ""
+"It TLS-rapport toant hokker TLS-protokollen en -fersiferingen identifisearre "
+"binne op de host foar de opjûne poarte."
#: reports/report_types/tls_report/report.html
msgid ""
"The table below provides an overview of the identified TLS protocols and "
"ciphers, including a status suggestion."
msgstr ""
+"Understeande tabel jout in oersjoch fan de identifisearre TLS-protokollen en "
+"-fersiferingen, wêrûnder in statussuggestje."
#: reports/report_types/tls_report/report.html
msgid "Ciphers"
-msgstr ""
+msgstr "Ciphers"
#: reports/report_types/tls_report/report.html
msgid "Protocol"
-msgstr ""
+msgstr "Protokol"
#: reports/report_types/tls_report/report.html
msgid "Encryption Algorithm"
-msgstr ""
+msgstr "Enkrypsjealgoritme"
#: reports/report_types/tls_report/report.html
msgid "Bits"
@@ -3851,26 +3884,28 @@ msgstr "Bits"
#: reports/report_types/tls_report/report.html
msgid "Key Size"
-msgstr ""
+msgstr "Kaaigrutte"
#: reports/report_types/tls_report/report.html
#: rocky/templates/organizations/organization_list.html
#: rocky/templates/organizations/organization_settings.html
msgid "Code"
-msgstr ""
+msgstr "Koade"
#: reports/report_types/tls_report/report.html
msgid "Phase out"
-msgstr ""
+msgstr "Utfasearje"
#: reports/report_types/tls_report/report.html
msgid "Good"
-msgstr ""
+msgstr "Goed"
#: reports/report_types/tls_report/report.html
msgid ""
"No ciphers were found for this combination of IP address, port and service."
msgstr ""
+"Der binne gjin fersiferingen fûn foar dizze kombinaasje fan IP-adres, poarte "
+"en tsjinst."
#: reports/report_types/tls_report/report.html
msgid ""
@@ -3881,17 +3916,19 @@ msgstr ""
#: reports/report_types/tls_report/report.py
msgid "TLS Report"
-msgstr ""
+msgstr "TLS-rapport"
#: reports/report_types/tls_report/report.py
msgid ""
"TLS Report assesses the security of data encryption and transmission "
"protocols."
msgstr ""
+"TLS-rapport beoardielet de feilichheid fan gegevensenkripsje en "
+"transmisjeprotokollen."
#: reports/report_types/vulnerability_report/report.html
msgid "No vulnerabilities have been found on this system."
-msgstr ""
+msgstr "Der binne gjin kwetsberheden op dit systeem fûn."
#: reports/report_types/vulnerability_report/report.html
msgid ""
@@ -3903,23 +3940,23 @@ msgstr ""
#: reports/report_types/vulnerability_report/report.html
msgid "Advice"
-msgstr ""
+msgstr "Advys"
#: reports/report_types/vulnerability_report/report.py
msgid "Vulnerability Report"
-msgstr ""
+msgstr "Kwetsberhedenrapport"
#: reports/report_types/vulnerability_report/report.py
msgid "Vulnerabilities found are grouped for each system."
-msgstr ""
+msgstr "De fûne kwetsberheden binne per systeem groepearre."
#: reports/report_types/vulnerability_report/report.py
msgid "Last seen"
-msgstr ""
+msgstr "Lêst sjoen"
#: reports/report_types/vulnerability_report/report.py
msgid "Evidence"
-msgstr ""
+msgstr "Bewiis"
#: reports/report_types/web_system_report/report.html
msgid ""
@@ -3933,59 +3970,60 @@ msgstr ""
#: reports/report_types/web_system_report/report.html
msgid "Web system compliance"
-msgstr ""
+msgstr "Compliance websysteem"
#: reports/report_types/web_system_report/report.html
msgid "CSP Present"
-msgstr ""
+msgstr "CSP oanwêzich"
#: reports/report_types/web_system_report/report.html
msgid "webservers compliant"
-msgstr ""
+msgstr "webservers compliant"
#: reports/report_types/web_system_report/report.html
msgid "Secure CSP Header"
-msgstr ""
+msgstr "Feilige CSP-header"
#: reports/report_types/web_system_report/report.html
msgid "Redirects HTTP to HTTPS"
-msgstr ""
+msgstr "Ferwiist HTTP troch nei HTTPS"
#: reports/report_types/web_system_report/report.html
msgid "Offers HTTPS"
-msgstr ""
+msgstr "HTTPS is beskikber"
#: reports/report_types/web_system_report/report.html
msgid "Has a Security.txt"
-msgstr ""
+msgstr "Hat in security.txt"
#: reports/report_types/web_system_report/report.html
msgid "Has a certificate"
-msgstr ""
+msgstr "Hat in sertifikaat"
#: reports/report_types/web_system_report/report.html
-msgid "Certificate is not expired"
-msgstr ""
+msgid "Certificate is valid"
+msgstr "Sertifikaat is jildich"
#: reports/report_types/web_system_report/report.html
msgid "Certificate is not expiring soon"
-msgstr ""
+msgstr "Sertifikaat ferrint ynkoarten net"
#: reports/report_types/web_system_report/report.html
msgid "No webservers have been found on this system."
-msgstr ""
+msgstr "Der binne gjin webservers op dit systeem fûn."
#: reports/report_types/web_system_report/report.py
msgid "Web System Report"
-msgstr ""
+msgstr "Websysteem-rapport"
#: reports/report_types/web_system_report/report.py
msgid "Web System Reports check web systems on basic security standards."
msgstr ""
+"Websysteemrapport kontrolearret websystemen op basisbefeiligingsstanderts."
#: reports/templates/partials/export_report_settings.html
msgid "Report schedule"
-msgstr ""
+msgstr "Rapportskema"
#: reports/templates/partials/export_report_settings.html
msgid ""
@@ -3995,6 +4033,13 @@ msgid ""
"single occasion, select the one-time option."
msgstr ""
+#: reports/templates/partials/export_report_settings.html
+msgid ""
+"Please choose a start date, time and recurrence for scheduling your "
+"report(s). If you select a date on the 28th-31st of the month, it will "
+"always be scheduled on the last day of the month."
+msgstr ""
+
#: reports/templates/partials/export_report_settings.html
msgid ""
"The date you select will be the reference date for the data set for your "
@@ -4010,7 +4055,7 @@ msgstr "Rapport generearje"
#: reports/templates/partials/generate_report_sidemenu.html
#: reports/templates/partials/report_sidemenu.html
msgid "Table of contents"
-msgstr ""
+msgstr "Ynhâldsopjefte"
#: reports/templates/partials/main_navigation.html
msgid "Generate a report"
@@ -4021,40 +4066,44 @@ msgid ""
"To generate a report you can start by selecting report types or by selecting "
"objects."
msgstr ""
+"Om in rapport te generearjen begjinne jo mei it selektearjen fan de winske "
+"rapporten of objekten."
#: reports/templates/partials/plugin_overview_table.html
#: reports/templates/partials/report_sidemenu.html
#: rocky/templates/oois/ooi_page_tabs.html
msgid "Overview"
-msgstr ""
+msgstr "Oersjoch"
#: reports/templates/partials/plugin_overview_table.html
msgid "Plugin overview table"
-msgstr ""
+msgstr "Ynstekkeroersjochtabel"
#: reports/templates/partials/plugin_overview_table.html
#: reports/templates/partials/report_setup_scan.html
msgid "Required plugins"
-msgstr ""
+msgstr "Nedige ynstekkers"
#: reports/templates/partials/plugin_overview_table.html
#: reports/templates/partials/report_setup_scan.html
msgid "Suggested plugins"
-msgstr ""
+msgstr "Oanrekommandearre ynstekkers"
#: reports/templates/partials/plugin_overview_table.html
msgid "Action required"
-msgstr ""
+msgstr "Aksje fereaske"
#: reports/templates/partials/plugin_overview_table.html
msgid "Ready"
-msgstr ""
+msgstr "Dien"
#: reports/templates/partials/report_header.html
msgid ""
"All selected report types for the selected objects are displayed one below "
"the other."
msgstr ""
+"Alle selektearre rapporttypen foar de selektearre objekten wurde ûnder inoar "
+"toand."
#: reports/templates/partials/report_introduction.html
msgid ""
@@ -4114,20 +4163,21 @@ msgid ""
msgstr ""
#: reports/templates/partials/report_names_header.html
+#, python-brace-format
msgid ""
"To make the report names more descriptive, you can include placeholders for "
"the object name, the report type and/or the reference date. For subreports "
-"and reports over a single object, use the placeholder \"{ooi}\" for the "
-"object name, \"{report type}\" for the report type and use a Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -4163,7 +4213,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4373,6 +4452,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4397,12 +4540,6 @@ msgstr "Rapporten:"
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4492,10 +4629,8 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4532,6 +4667,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr ""
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4671,6 +4812,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr "1: Selektearje objekten"
@@ -5481,12 +5656,6 @@ msgstr ""
msgid " Finding Details"
msgstr ""
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr ""
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5595,8 +5764,12 @@ msgid "findings"
msgstr ""
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -5984,6 +6157,11 @@ msgstr ""
msgid "Score"
msgstr ""
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr ""
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr ""
@@ -6067,7 +6245,7 @@ msgid "Save %(display_type)s"
msgstr ""
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
+msgid "Currently no findings have been identified for OOI"
msgstr ""
#: rocky/templates/oois/ooi_list.html
@@ -6082,10 +6260,6 @@ msgstr ""
msgid "Objects "
msgstr "Objekten "
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr ""
@@ -6200,6 +6374,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr ""
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr ""
@@ -6220,10 +6398,6 @@ msgstr ""
msgid "Save organization"
msgstr ""
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr ""
@@ -6237,6 +6411,15 @@ msgstr ""
msgid "Tags"
msgstr ""
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr ""
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr ""
@@ -6362,10 +6545,6 @@ msgstr ""
msgid "Add indemnification"
msgstr ""
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr ""
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr ""
@@ -6811,10 +6990,6 @@ msgstr ""
msgid "Download meta data"
msgstr ""
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr ""
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -6834,7 +7009,7 @@ msgstr ""
msgid "List of tasks for boefjes"
msgstr ""
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
@@ -7502,21 +7677,27 @@ msgstr ""
#: rocky/views/upload_csv.py
msgid "Object(s) successfully added."
-msgstr ""
+msgstr "Objekten mei sukses tafoege."
#: rocky/views/upload_raw.py
#, python-format
msgid "Raw file could not be uploaded to Bytes: status code %d"
-msgstr ""
+msgstr "Raw-bestân kin net nei Bytes oplaad wurde: statuskoade %d"
#: rocky/views/upload_raw.py
#, python-format
msgid "Raw file could not be uploaded to Bytes: %s"
-msgstr ""
+msgstr "Raw-bestân kin net nei Bytes oplaad wurde: %s"
#: rocky/views/upload_raw.py
msgid "Raw file successfully added."
-msgstr ""
+msgstr "Raw-bestân mei sukses tafoege."
+
+#~ msgid "No findings have been found."
+#~ msgstr "Der binne gjin befiningen fûn."
+
+#~ msgid "Editing this boefje is not allowed because it is static."
+#~ msgstr "Dit Boefje bewurkje is net tastien, omdat it statysk is."
#~ msgid "A HTTP error occurred. Check logs for more info."
#~ msgstr ""
diff --git a/rocky/rocky/locale/it/LC_MESSAGES/django.po b/rocky/rocky/locale/it/LC_MESSAGES/django.po
index 607852df5a7..6d2446989c9 100644
--- a/rocky/rocky/locale/it/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/it/LC_MESSAGES/django.po
@@ -5,7 +5,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
"PO-Revision-Date: 2023-11-16 20:05+0000\n"
"Last-Translator: Luca Racchetti \n"
"Language-Team: Italian Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -4194,7 +4229,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4404,6 +4468,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4428,12 +4556,6 @@ msgstr ""
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4523,11 +4645,9 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
-msgstr "Oggetto di Input"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
+msgstr "Oggetto di input"
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Show report details"
@@ -4563,6 +4683,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr "Oggetto di Input"
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4702,6 +4828,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr ""
@@ -5539,12 +5699,6 @@ msgstr "Totale dei Rilevamenti"
msgid " Finding Details"
msgstr "Dettagli Rilevamento"
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr "Dettagli del rilevamento"
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5656,8 +5810,12 @@ msgid "findings"
msgstr "rilevamenti"
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -6080,6 +6238,11 @@ msgstr ""
msgid "Score"
msgstr "Punteggio"
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr "Dettagli del rilevamento"
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr "Panoramica del numero di rilevamenti e della loro gravità trovati su"
@@ -6166,8 +6329,8 @@ msgid "Save %(display_type)s"
msgstr "Salva %(display_type)s"
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
-msgstr "Attualmente non ci sono rilevamenti per OOI"
+msgid "Currently no findings have been identified for OOI"
+msgstr ""
#: rocky/templates/oois/ooi_list.html
#, python-format
@@ -6185,10 +6348,6 @@ msgstr ""
msgid "Objects "
msgstr ""
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr "Elimina oggetto(i)"
@@ -6321,6 +6480,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr "Top 10 dei rilevamenti più gravi"
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr "Tipo di rilevamento:"
@@ -6341,10 +6504,6 @@ msgstr "Modifica organizzazione"
msgid "Save organization"
msgstr "Salva organizzazione"
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr "Aggiungi nuova organizzazione"
@@ -6358,6 +6517,15 @@ msgstr "Panoramica dell'organizzazione:"
msgid "Tags"
msgstr "Tag"
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr "Riavvia tutti i bit"
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr " configurazione dell'account del membro"
@@ -6494,10 +6662,6 @@ msgstr ""
msgid "Add indemnification"
msgstr "Aggiungi indennizzo"
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr "Riavvia tutti i bit"
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr "Osservato il"
@@ -6980,10 +7144,6 @@ msgstr "Scarica dati meta e raw"
msgid "Download meta data"
msgstr "Scarica dati meta"
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr "Oggetto di input"
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -7003,7 +7163,7 @@ msgstr "Non ci sono compiti per boefjes"
msgid "List of tasks for boefjes"
msgstr "Elenco dei compiti per boefjes"
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
@@ -7758,6 +7918,9 @@ msgstr ""
msgid "Raw file successfully added."
msgstr "File raw aggiunto con successo."
+#~ msgid "Currently there are no findings for OOI"
+#~ msgstr "Attualmente non ci sono rilevamenti per OOI"
+
#, fuzzy
#~ msgid "Select your language"
#~ msgstr "Seleziona organizzazione"
diff --git a/rocky/rocky/locale/nl/LC_MESSAGES/django.po b/rocky/rocky/locale/nl/LC_MESSAGES/django.po
index 07bda72db83..edc3e629c58 100644
--- a/rocky/rocky/locale/nl/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/nl/LC_MESSAGES/django.po
@@ -14,17 +14,17 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
-"PO-Revision-Date: 2024-11-02 20:00+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
+"PO-Revision-Date: 2024-11-22 17:00+0000\n"
"Last-Translator: Wim Benes \n"
-"Language-Team: Dutch \n"
+"Language-Team: Dutch \n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.8.2\n"
+"X-Generator: Weblate 5.9-dev\n"
#: account/admin.py
msgid "Permissions"
@@ -39,6 +39,10 @@ msgstr "Belangrijke datums"
#: reports/report_types/dns_report/report.html
#: reports/report_types/tls_report/report.html
#: reports/templates/partials/report_names_form.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -379,6 +383,7 @@ msgstr "Soort lid"
#: account/templates/account_detail.html
#: rocky/templates/crisis_room/crisis_room_findings_block.html
+#: rocky/templates/tasks/normalizers.html
msgid "Organization"
msgstr "Organisatie"
@@ -663,6 +668,12 @@ msgstr ""
"De KATalogus heeft een onverwachte fout opgelopen. Controleer de logboeken "
"voor verdere details."
+#: katalogus/client.py
+#, python-format
+msgid "An HTTP %d error occurred. Check logs for more info."
+msgstr ""
+"Er is een HTTP-%d-fout opgetreden. Controleer de logboeken voor meer info."
+
#: katalogus/client.py
msgid "Boefje with this name already exists."
msgstr "Boefje met deze naam bestaat al."
@@ -671,16 +682,6 @@ msgstr "Boefje met deze naam bestaat al."
msgid "Boefje with this ID already exists."
msgstr "Boefje met deze ID bestaat al."
-#: katalogus/client.py
-msgid "Editing this boefje is not allowed because it is static."
-msgstr "Dit Boefje bewerken is niet toegestaan, omdat het statisch is."
-
-#: katalogus/client.py
-#, python-format
-msgid "An HTTP %d error occurred. Check logs for more info."
-msgstr ""
-"Er is een HTTP-%d-fout opgetreden. Controleer de logboeken voor meer info."
-
#: katalogus/forms/katalogus_filter.py
msgid "Show all"
msgstr "Alles tonen"
@@ -1042,7 +1043,6 @@ msgstr "Uitgever:"
#: katalogus/templates/partials/boefje_tile.html
#: katalogus/templates/partials/plugin_tile.html
#: katalogus/templates/partials/plugin_tile_modal.html
-#: katalogus/templates/partials/plugins.html
msgid "See details"
msgstr "Details bekijken"
@@ -1109,7 +1109,6 @@ msgstr "Een overzicht van alle beschikbare plug-ins."
#: katalogus/templates/plugin_settings_list.html
#: katalogus/views/katalogus_settings.py tools/view_helpers.py
#: rocky/templates/header.html
-#: rocky/templates/organizations/organization_settings.html
msgid "Settings"
msgstr "Instellingen"
@@ -1121,6 +1120,18 @@ msgstr "Rasterweergave"
msgid "Tableview"
msgstr "Tabelweergave"
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Required for"
+msgstr "Vereist voor"
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "report types"
+msgstr "rapporttypen"
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Report types for "
+msgstr "Rapporttypen voor "
+
#: katalogus/templates/partials/objects_to_scan.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/forms/widgets/checkbox_group_table.html
@@ -1239,10 +1250,16 @@ msgid "Plugin description"
msgstr "Plug-inbeschrijving"
#: katalogus/templates/partials/plugins.html
+#: reports/templates/report_overview/report_history_table.html
+#: rocky/templates/organizations/organization_list.html
#: rocky/templates/organizations/organization_settings.html
msgid "Actions"
msgstr "Acties"
+#: katalogus/templates/partials/plugins.html
+msgid "Detail page"
+msgstr "Detailpagina"
+
#: katalogus/templates/partials/plugins_navigation.html
#: reports/templates/report_overview/report_overview_navigation.html
msgid "Plugins Navigation"
@@ -1381,6 +1398,8 @@ msgid "Boefje ID"
msgstr "Boefje-ID"
#: katalogus/templates/plugin_container_image.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -1508,6 +1527,8 @@ msgstr ""
#: katalogus/templates/plugin_settings_delete.html
#: katalogus/views/plugin_settings_delete.py
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/report_history_table.html
#: rocky/templates/admin/delete_confirmation.html rocky/views/ooi_delete.py
msgid "Delete"
msgstr "Verwijderen"
@@ -2299,6 +2320,8 @@ msgstr "URL"
#: onboarding/templates/step_3c_setup_scan_ooi_detail.html
#: reports/report_types/dns_report/report.html
#: reports/templates/partials/report_ooi_list.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/summary/ooi_selection.html tools/forms/ooi.py
#: rocky/templates/oois/ooi_list.html
#: rocky/templates/partials/elements/ooi_tree_condensed_table.html
@@ -2765,10 +2788,6 @@ msgstr "Vandaag"
msgid "Different date"
msgstr "Andere datum"
-#: reports/forms.py
-msgid "Start date"
-msgstr "Startdatum"
-
#: reports/forms.py
msgid "No, just once"
msgstr "Nee, maar een keer"
@@ -2777,6 +2796,14 @@ msgstr "Nee, maar een keer"
msgid "Yes, repeat"
msgstr "Ja, herhalen"
+#: reports/forms.py
+msgid "Start date"
+msgstr "Startdatum"
+
+#: reports/forms.py
+msgid "Start time (UTC)"
+msgstr ""
+
#: reports/forms.py
#: reports/templates/report_overview/scheduled_reports_table.html
msgid "Recurrence"
@@ -2856,6 +2883,7 @@ msgstr "Geselecteerde rapporttypen"
#: reports/report_types/aggregate_organisation_report/appendix.html
#: reports/templates/partials/plugin_overview_table.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -3455,7 +3483,6 @@ msgid "Other findings found"
msgstr "Andere bevindingen gevonden"
#: reports/report_types/dns_report/report.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/oois/ooi_detail_findings_list.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
@@ -3495,7 +3522,6 @@ msgstr "Bevindingeninformatie"
#: reports/report_types/findings_report/report.html
#: reports/report_types/vulnerability_report/report.html
#: reports/templates/partials/report_severity_totals_table.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
#: rocky/templates/partials/ooi_report_findings_block_table.html
#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
@@ -3548,8 +3574,9 @@ msgid "First seen"
msgstr "Eerst gezien"
#: reports/report_types/findings_report/report.html
-msgid "No findings have been found."
-msgstr "Er zijn geen bevindingen gevonden."
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "No findings have been identified yet."
+msgstr ""
#: reports/report_types/findings_report/report.py
msgid "Findings Report"
@@ -4190,8 +4217,8 @@ msgid "Has a certificate"
msgstr "Heeft een certificaat"
#: reports/report_types/web_system_report/report.html
-msgid "Certificate is not expired"
-msgstr "Certificaat is niet verlopen"
+msgid "Certificate is valid"
+msgstr "Certificaat is geldig"
#: reports/report_types/web_system_report/report.html
msgid "Certificate is not expiring soon"
@@ -4226,6 +4253,13 @@ msgstr ""
"intervallen, zoals dagelijks, wekelijks, of maandelijks. Als u het rapport "
"nodig hebt voor een enkele gelegenheid, kies dan de eenmalige optie."
+#: reports/templates/partials/export_report_settings.html
+msgid ""
+"Please choose a start date, time and recurrence for scheduling your "
+"report(s). If you select a date on the 28th-31st of the month, it will "
+"always be scheduled on the last day of the month."
+msgstr ""
+
#: reports/templates/partials/export_report_settings.html
msgid ""
"The date you select will be the reference date for the data set for your "
@@ -4357,31 +4391,23 @@ msgstr ""
"worden toegepast op alle gegenereerde (sub)rapporten."
#: reports/templates/partials/report_names_header.html
+#, python-brace-format
msgid ""
"To make the report names more descriptive, you can include placeholders for "
"the object name, the report type and/or the reference date. For subreports "
-"and reports over a single object, use the placeholder \"{ooi}\" for the "
-"object name, \"{report type}\" for the report type and use a Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
-"Om de rapportnamen meer informatief te maken, kunt u plaatshouders opnemen "
-"voor de objectennaam, het rapporttype en/of de referentiedatum. Gebruik voor "
-"sub-rapporten en rapporten over een enkel object, de plaatshouder ‘{ooi}’, ‘{"
-"report type}’ voor het rapporttype en Python strftime-code voor de "
-"referentiedatum van de objectnaam. Gebruik voor rapporten over meerdere "
-"objecten, ‘{oois_count}’ voor het aantal objecten in het rapport."
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
-"Bijvoorbeeld, het format ‘{report type} voor {ooi} op %%x’ genereert dit "
-"resultaat: ‘DNS-rapport vior example.com op 01/01/25’."
#: reports/templates/partials/report_names_header.html
msgid ""
@@ -4391,9 +4417,9 @@ msgid ""
"strftime code in the report name."
msgstr ""
"Geef uw rapport(en) een aangpaste naam en voeg optioneel de referentiedatum "
-"toe. Om dit te doen kunt u een standaard optie selecteren of een Python strftime-"
-"code in de rapportnaam gebruiken."
+"toe. Om dit te doen kunt u een standaard optie selecteren of een Python "
+"strftime-code in de rapportnaam gebruiken."
#: reports/templates/partials/report_navigation.html
msgid "Report Navigation"
@@ -4419,8 +4445,37 @@ msgstr[0] "Selecteer object (%(total_oois)s)"
msgstr[1] "Selecteer objecten (%(total_oois)s)"
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
-msgstr "Selecteer de objecten die u op wilt nemen in het rapport."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
+msgstr "Doorgaan met liveset"
#: reports/templates/partials/report_ooi_list.html
#: reports/templates/summary/report_asset_overview.html
@@ -4651,6 +4706,70 @@ msgstr "Selecteer alle rapporttypes"
msgid "%(btn_text)s"
msgstr "%(btn_text)s"
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr "Verwijder de volgende rapport(en):"
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr "Referentiedatum"
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr "Hernoem de volgende rapport(en):"
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr "Hernoemen"
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr "Genereer de volgende rapport(en) opnieuw:"
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr "Opnieuw genereren"
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr "Rapportgeschiedenis"
@@ -4677,12 +4796,6 @@ msgstr "Rapporten:"
msgid "Input Objects"
msgstr "Input objecten"
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr "Referentiedatum"
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr "Bovenliggende rapportdetails tonen"
@@ -4783,10 +4896,8 @@ msgid "Scheduled Reports:"
msgstr "Ingeplande rapporten:"
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr "Inputobject"
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4823,6 +4934,12 @@ msgstr "Rapportdetails tonen"
msgid "Subreports:"
msgstr "Subrapporten:"
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr "Inputobject"
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4974,6 +5091,42 @@ msgstr "Multi-rapport"
msgid "View report"
msgstr "Toon rapport"
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+"Er is een onverwachte fout opgetreden, controleer de logbestanden voor meer "
+"info."
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr "Met succes verwijderd."
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr "Opnieuw genereren met succes voltooid"
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr "Hernoemen mislukt. Lege rapportnaam gevonden."
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr "Rapportnamen en rapporten komen niet overeen."
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr "Rapporten met succes hernoemd."
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr "Rapport {} kon niet worden hernoemd."
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr "1: Selecteer objecten"
@@ -5303,7 +5456,8 @@ msgstr "Voer de datum en tijd van uw bevinding in (UTC)"
#: tools/forms/settings.py
msgid "Add the date and time of when the raw file was generated (UTC)"
-msgstr "Voeg de datum en tijd toe wanneer het rraw-bestand gegenereerd is (UTC)"
+msgstr ""
+"Voeg de datum en tijd toe wanneer het rraw-bestand gegenereerd is (UTC)"
#: tools/forms/settings.py
msgid ""
@@ -5387,8 +5541,8 @@ msgid ""
msgstr ""
"Selecteer een vrijwaringsniveau voor uw Boefje. Lees voor meer informatie "
"over de verschillende vrijwaringsniveaus de "
-"documentatie.
"
+"manual/usermanual.html#scan-levels-clearance-indemnities'> documentatie."
+"
"
#: tools/forms/settings.py
msgid "Depth of the tree."
@@ -5858,12 +6012,6 @@ msgstr "Totaal aantal bevindingen"
msgid " Finding Details"
msgstr " Details bevindingen"
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr "Bevindingsdetails"
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5975,9 +6123,13 @@ msgid "findings"
msgstr "bevindingen"
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
-msgstr "Bevindingentabel"
+msgid "Findings table "
+msgstr "Bevindingentabel "
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
+msgstr "kolomkoppen met knoppen zijn te sorteren"
#: rocky/templates/findings/finding_list.html
#: rocky/templates/oois/ooi_page_tabs.html
@@ -6390,6 +6542,11 @@ msgstr "Overzicht van bevindingen voor"
msgid "Score"
msgstr "Score"
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr "Bevindingsdetails"
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr "Overzicht van het aantal bevindingen en de ernst daarvan op"
@@ -6477,8 +6634,8 @@ msgid "Save %(display_type)s"
msgstr "%(display_type)s opslaan"
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
-msgstr "Er zijn geen bevindingen voor het object"
+msgid "Currently no findings have been identified for OOI"
+msgstr ""
#: rocky/templates/oois/ooi_list.html
#, python-format
@@ -6496,10 +6653,6 @@ msgstr ""
msgid "Objects "
msgstr "Objecten "
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr "kolomkoppen met knoppen zijn te sorteren"
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr "Object(en) verwijderen"
@@ -6626,6 +6779,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr "Top 10 meest ernstige bevindingen"
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr "Bevindingentabel"
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr "Bevindingstype:"
@@ -6646,10 +6803,6 @@ msgstr "Organisatie bewerken"
msgid "Save organization"
msgstr "Organisatie opslaan"
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr "Draai nogmaals alle bits voor al mijn organisaties"
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr "Nieuwe organisatie toevoegen"
@@ -6663,6 +6816,15 @@ msgstr "Organisatie-overzicht:"
msgid "Tags"
msgstr "Labels"
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr "Uit te voeren acties voor al uw organisaties."
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr "Alle bits opnieuw starten"
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr " lidaccount instellen"
@@ -6799,10 +6961,6 @@ msgstr ""
msgid "Add indemnification"
msgstr "Vrijwaring toevoegen"
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr "Alle bits opnieuw starten"
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr "Gevonden op"
@@ -7283,10 +7441,6 @@ msgstr "Meta- en raw-gegevens downloaden"
msgid "Download meta data"
msgstr "Meta-gegevens downloaden"
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr "Inputobject"
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -7312,7 +7466,7 @@ msgstr "Er zijn geen taken voor Boefjes"
msgid "List of tasks for boefjes"
msgstr "Takenlijst van Boefjes"
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr "Organisatiecode"
@@ -8070,6 +8224,51 @@ msgstr "Raw-bestand kan niet naar Bytes worden geüpload: %s"
msgid "Raw file successfully added."
msgstr "Raw-bestand met succes toegevoegd."
+#~ msgid "No findings have been found."
+#~ msgstr "Er zijn geen bevindingen gevonden."
+
+#~ msgid "Currently there are no findings for OOI"
+#~ msgstr "Er zijn geen bevindingen voor het object"
+
+#~ msgid "Editing this boefje is not allowed because it is static."
+#~ msgstr "Dit Boefje bewerken is niet toegestaan, omdat het statisch is."
+
+#~ msgid "Certificate is not expired"
+#~ msgstr "Certificaat is niet verlopen"
+
+#~ msgid ""
+#~ "To make the report names more descriptive, you can include placeholders "
+#~ "for the object name, the report type and/or the reference date. For "
+#~ "subreports and reports over a single object, use the placeholder "
+#~ "\"{ooi}\" for the object name, \"{report type}\" for the report type and "
+#~ "use a Python strftime code for the reference date. For "
+#~ "reports over multiple objects, use \"{oois_count}\" for the number of "
+#~ "objects in the report."
+#~ msgstr ""
+#~ "Om de rapportnamen meer informatief te maken, kunt u plaatshouders "
+#~ "opnemen voor de objectennaam, het rapporttype en/of de referentiedatum. "
+#~ "Gebruik voor sub-rapporten en rapporten over een enkel object, de "
+#~ "plaatshouder ‘{ooi}’, ‘{report type}’ voor het rapporttype en Python "
+#~ "strftime-code voor de referentiedatum van de objectnaam. Gebruik voor "
+#~ "rapporten over meerdere objecten, ‘{oois_count}’ voor het aantal objecten "
+#~ "in het rapport."
+
+#, python-format
+#~ msgid ""
+#~ "For example, the format \"{report type} for {ooi} at %%x\" could "
+#~ "generate: \"DNS Report for example.com at 01/01/25\"."
+#~ msgstr ""
+#~ "Bijvoorbeeld, het format ‘{report type} voor {ooi} op %%x’ genereert dit "
+#~ "resultaat: ‘DNS-rapport vior example.com op 01/01/25’."
+
+#~ msgid "Select which objects you want to include in your report."
+#~ msgstr "Selecteer de objecten die u op wilt nemen in het rapport."
+
+#~ msgid "Rerun all bits for all my organizations"
+#~ msgstr "Draai nogmaals alle bits voor al mijn organisaties"
+
#~ msgid "Select your language"
#~ msgstr "Taal selecteren"
diff --git a/rocky/rocky/locale/pap/LC_MESSAGES/django.po b/rocky/rocky/locale/pap/LC_MESSAGES/django.po
index 4739ca919d7..e8973cbd0ad 100644
--- a/rocky/rocky/locale/pap/LC_MESSAGES/django.po
+++ b/rocky/rocky/locale/pap/LC_MESSAGES/django.po
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-10-29 11:51+0000\n"
+"POT-Creation-Date: 2024-11-18 15:24+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -26,6 +26,10 @@ msgstr "Fechanan importante"
#: reports/report_types/dns_report/report.html
#: reports/report_types/tls_report/report.html
#: reports/templates/partials/report_names_form.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -363,6 +367,7 @@ msgstr "Tipo di miembro"
#: account/templates/account_detail.html
#: rocky/templates/crisis_room/crisis_room_findings_block.html
+#: rocky/templates/tasks/normalizers.html
msgid "Organization"
msgstr "Organisashon"
@@ -633,20 +638,16 @@ msgid ""
msgstr ""
#: katalogus/client.py
-msgid "Boefje with this name already exists."
-msgstr ""
-
-#: katalogus/client.py
-msgid "Boefje with this ID already exists."
+#, python-format
+msgid "An HTTP %d error occurred. Check logs for more info."
msgstr ""
#: katalogus/client.py
-msgid "Editing this boefje is not allowed because it is static."
+msgid "Boefje with this name already exists."
msgstr ""
#: katalogus/client.py
-#, python-format
-msgid "An HTTP %d error occurred. Check logs for more info."
+msgid "Boefje with this ID already exists."
msgstr ""
#: katalogus/forms/katalogus_filter.py
@@ -999,7 +1000,6 @@ msgstr ""
#: katalogus/templates/partials/boefje_tile.html
#: katalogus/templates/partials/plugin_tile.html
#: katalogus/templates/partials/plugin_tile_modal.html
-#: katalogus/templates/partials/plugins.html
msgid "See details"
msgstr "Habri detayes"
@@ -1066,7 +1066,6 @@ msgstr "Un bista general di tur plug-innan disponibel."
#: katalogus/templates/plugin_settings_list.html
#: katalogus/views/katalogus_settings.py tools/view_helpers.py
#: rocky/templates/header.html
-#: rocky/templates/organizations/organization_settings.html
msgid "Settings"
msgstr "Settings"
@@ -1078,6 +1077,18 @@ msgstr "Mustra Grid"
msgid "Tableview"
msgstr "Aparensia tablatura"
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Required for"
+msgstr ""
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "report types"
+msgstr ""
+
+#: katalogus/templates/partials/modal_report_types.html
+msgid "Report types for "
+msgstr ""
+
#: katalogus/templates/partials/objects_to_scan.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/forms/widgets/checkbox_group_table.html
@@ -1196,10 +1207,16 @@ msgid "Plugin description"
msgstr "Deskripshon di Plug-in"
#: katalogus/templates/partials/plugins.html
+#: reports/templates/report_overview/report_history_table.html
+#: rocky/templates/organizations/organization_list.html
#: rocky/templates/organizations/organization_settings.html
msgid "Actions"
msgstr "Akshonnan"
+#: katalogus/templates/partials/plugins.html
+msgid "Detail page"
+msgstr ""
+
#: katalogus/templates/partials/plugins_navigation.html
#: reports/templates/report_overview/report_overview_navigation.html
msgid "Plugins Navigation"
@@ -1332,6 +1349,8 @@ msgid "Boefje ID"
msgstr ""
#: katalogus/templates/plugin_container_image.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -1449,6 +1468,8 @@ msgstr "Segur bo ke bo ke eliminá tur ajuste pa e plug-in %(plugin_name)s?"
#: katalogus/templates/plugin_settings_delete.html
#: katalogus/views/plugin_settings_delete.py
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/report_history_table.html
#: rocky/templates/admin/delete_confirmation.html rocky/views/ooi_delete.py
msgid "Delete"
msgstr "Eliminá"
@@ -2213,6 +2234,8 @@ msgstr "URL"
#: onboarding/templates/step_3c_setup_scan_ooi_detail.html
#: reports/report_types/dns_report/report.html
#: reports/templates/partials/report_ooi_list.html
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
#: reports/templates/summary/ooi_selection.html tools/forms/ooi.py
#: rocky/templates/oois/ooi_list.html
#: rocky/templates/partials/elements/ooi_tree_condensed_table.html
@@ -2674,15 +2697,19 @@ msgid "Different date"
msgstr ""
#: reports/forms.py
-msgid "Start date"
+msgid "No, just once"
msgstr ""
#: reports/forms.py
-msgid "No, just once"
+msgid "Yes, repeat"
msgstr ""
#: reports/forms.py
-msgid "Yes, repeat"
+msgid "Start date"
+msgstr ""
+
+#: reports/forms.py
+msgid "Start time (UTC)"
msgstr ""
#: reports/forms.py
@@ -2764,6 +2791,7 @@ msgstr ""
#: reports/report_types/aggregate_organisation_report/appendix.html
#: reports/templates/partials/plugin_overview_table.html
+#: reports/templates/report_overview/modal_partials/rename_modal.html
#: reports/templates/report_overview/report_history_table.html
#: reports/templates/report_overview/scheduled_reports_table.html
#: reports/templates/report_overview/subreports_table.html
@@ -3283,7 +3311,6 @@ msgid "Other findings found"
msgstr ""
#: reports/report_types/dns_report/report.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/findings/finding_list.html
#: rocky/templates/oois/ooi_detail_findings_list.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
@@ -3323,7 +3350,6 @@ msgstr ""
#: reports/report_types/findings_report/report.html
#: reports/report_types/vulnerability_report/report.html
#: reports/templates/partials/report_severity_totals_table.html
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/oois/ooi_detail_findings_overview.html
#: rocky/templates/partials/ooi_report_findings_block_table.html
#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
@@ -3368,7 +3394,8 @@ msgid "First seen"
msgstr ""
#: reports/report_types/findings_report/report.html
-msgid "No findings have been found."
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "No findings have been identified yet."
msgstr ""
#: reports/report_types/findings_report/report.py
@@ -3937,7 +3964,7 @@ msgid "Has a certificate"
msgstr ""
#: reports/report_types/web_system_report/report.html
-msgid "Certificate is not expired"
+msgid "Certificate is valid"
msgstr ""
#: reports/report_types/web_system_report/report.html
@@ -3968,6 +3995,13 @@ msgid ""
"single occasion, select the one-time option."
msgstr ""
+#: reports/templates/partials/export_report_settings.html
+msgid ""
+"Please choose a start date, time and recurrence for scheduling your "
+"report(s). If you select a date on the 28th-31st of the month, it will "
+"always be scheduled on the last day of the month."
+msgstr ""
+
#: reports/templates/partials/export_report_settings.html
msgid ""
"The date you select will be the reference date for the data set for your "
@@ -4087,20 +4121,21 @@ msgid ""
msgstr ""
#: reports/templates/partials/report_names_header.html
+#, python-brace-format
msgid ""
"To make the report names more descriptive, you can include placeholders for "
"the object name, the report type and/or the reference date. For subreports "
-"and reports over a single object, use the placeholder \"{ooi}\" for the "
-"object name, \"{report type}\" for the report type and use a Python "
"strftime code for the reference date. For reports over multiple objects, "
-"use \"{oois_count}\" for the number of objects in the report."
+"use \"${oois_count}\" for the number of objects in the report."
msgstr ""
#: reports/templates/partials/report_names_header.html
-#, python-format
+#, python-format, python-brace-format
msgid ""
-"For example, the format \"{report type} for {ooi} at %%x\" could generate: "
+"For example, the format \"${report_type} for ${ooi} at %%x\" could generate: "
"\"DNS Report for example.com at 01/01/25\"."
msgstr ""
@@ -4136,7 +4171,36 @@ msgstr[0] ""
msgstr[1] ""
#: reports/templates/partials/report_ooi_list.html
-msgid "Select which objects you want to include in your report."
+msgid ""
+"\n"
+" Select which objects you want to include in your report. You "
+"can either continue\n"
+" with a live set or you can select the objects manually from "
+"the table below.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid ""
+"\n"
+" A live set is a set of objects based on the applied "
+"filters.\n"
+" Any object that matches this applied filter (now or in the "
+"future) will be used as\n"
+" input for the scheduled report. If your live set filter (e."
+"g. 'hostnames' with\n"
+" 'L2 clearance' that are 'declared') shows 2 hostnames that "
+"match the filter today,\n"
+" the scheduled report will run for those 2 hostnames. If you "
+"add 3 more hostnames\n"
+" tomorrow (with the same filter criteria), your next "
+"scheduled report will contain\n"
+" 5 hostnames. Your live set will update as you go.\n"
+" "
+msgstr ""
+
+#: reports/templates/partials/report_ooi_list.html
+msgid "Continue with live set"
msgstr ""
#: reports/templates/partials/report_ooi_list.html
@@ -4346,6 +4410,70 @@ msgstr ""
msgid "%(btn_text)s"
msgstr ""
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid "Delete the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" Deleted reports are removed in the view from the moment of deletion. "
+"The report can still be accessed on timestamps before the deletion. Only the "
+"report is removed from the view, not the data it is based on.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/share_modal.html
+msgid ""
+"\n"
+" It is still possible to generate a new report for same date. If the "
+"report is part of a combined report, it will remain available in the "
+"combined report.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Input objects"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/delete_modal.html
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+#: reports/templates/report_overview/scheduled_reports_table.html
+#: reports/templates/report_overview/subreports_table.html
+msgid "Reference date"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+msgid "Rename the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rename_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rename"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid "Rerun the following report(s):"
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+msgid ""
+"\n"
+" By submitting you're generating the selected reports again, using the "
+"current data.\n"
+" "
+msgstr ""
+
+#: reports/templates/report_overview/modal_partials/rerun_modal.html
+#: reports/templates/report_overview/report_history_table.html
+msgid "Rerun"
+msgstr ""
+
#: reports/templates/report_overview/report_history.html
msgid "Reports history"
msgstr ""
@@ -4370,12 +4498,6 @@ msgstr ""
msgid "Input Objects"
msgstr ""
-#: reports/templates/report_overview/report_history_table.html
-#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-msgid "Reference date"
-msgstr ""
-
#: reports/templates/report_overview/report_history_table.html
msgid "Shows parent report details"
msgstr ""
@@ -4465,10 +4587,8 @@ msgid "Scheduled Reports:"
msgstr ""
#: reports/templates/report_overview/scheduled_reports_table.html
-#: reports/templates/report_overview/subreports_table.html
-#: rocky/templates/tasks/boefjes.html
-#: rocky/templates/tasks/plugin_detail_task_list.html
-msgid "Input Object"
+#: rocky/templates/tasks/boefje_task_detail.html
+msgid "Input object"
msgstr "Opheto di entrada"
#: reports/templates/report_overview/scheduled_reports_table.html
@@ -4505,6 +4625,12 @@ msgstr ""
msgid "Subreports:"
msgstr ""
+#: reports/templates/report_overview/subreports_table.html
+#: rocky/templates/tasks/boefjes.html
+#: rocky/templates/tasks/plugin_detail_task_list.html
+msgid "Input Object"
+msgstr "Opheto di entrada"
+
#: reports/templates/summary/report_asset_overview.html
msgid ""
"The objects listed in the table below were used to generate this report. For "
@@ -4644,6 +4770,40 @@ msgstr ""
msgid "View report"
msgstr ""
+#: reports/views/report_overview.py
+msgid "An unexpected error occurred, please check logs for more info."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Deletion successful."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid ""
+"Multi organization reports cannot be rescheduled. It consists of imported "
+"data from different organizations and not based on new generated data."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Rerun successful"
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Renaming failed. Empty report name found."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report names and reports does not match."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Reports successfully renamed."
+msgstr ""
+
+#: reports/views/report_overview.py
+msgid "Report {} could not be renamed."
+msgstr ""
+
#: reports/views/view_helpers.py
msgid "1: Select objects"
msgstr ""
@@ -5476,12 +5636,6 @@ msgstr "Diskubrimentu Totál"
msgid " Finding Details"
msgstr "Detayes di diskubrimentu"
-#: rocky/templates/crisis_room/crisis_room_findings_block.html
-#: rocky/templates/oois/ooi_detail_findings_list.html
-#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
-msgid "Finding details"
-msgstr "Detaye di búskeda"
-
#: rocky/templates/crisis_room/crisis_room_findings_block.html
#: rocky/templates/organizations/organization_list.html
msgid "There were no organizations found for your user account"
@@ -5594,8 +5748,12 @@ msgid "findings"
msgstr "diskubrimentunan"
#: rocky/templates/findings/finding_list.html
-#: rocky/templates/organizations/organization_crisis_room.html
-msgid "Findings table"
+msgid "Findings table "
+msgstr ""
+
+#: rocky/templates/findings/finding_list.html
+#: rocky/templates/oois/ooi_list.html
+msgid "column headers with buttons are sortable"
msgstr ""
#: rocky/templates/findings/finding_list.html
@@ -6011,6 +6169,11 @@ msgstr ""
msgid "Score"
msgstr "Punto"
+#: rocky/templates/oois/ooi_detail_findings_list.html
+#: rocky/templates/partials/ooi_report_findings_block_table_expanded_row.html
+msgid "Finding details"
+msgstr "Detaye di búskeda"
+
#: rocky/templates/oois/ooi_detail_findings_overview.html
msgid "Overview of the number of findings and their severity found on"
msgstr "Resumen di e kantidad di diskubrimentu i nan gravedat enkontrá riba"
@@ -6097,8 +6260,8 @@ msgid "Save %(display_type)s"
msgstr "Save %(display_type)s"
#: rocky/templates/oois/ooi_findings.html
-msgid "Currently there are no findings for OOI"
-msgstr "Aktualmente no a diskubri nada pa OOI"
+msgid "Currently no findings have been identified for OOI"
+msgstr ""
#: rocky/templates/oois/ooi_list.html
#, fuzzy, python-format
@@ -6115,10 +6278,6 @@ msgstr ""
msgid "Objects "
msgstr ""
-#: rocky/templates/oois/ooi_list.html
-msgid "column headers with buttons are sortable"
-msgstr ""
-
#: rocky/templates/oois/ooi_list.html
msgid "Delete object(s)"
msgstr "Kita opheto(nan)"
@@ -6245,6 +6404,10 @@ msgstr ""
msgid "Top 10 most severe Findings"
msgstr "Top 10 di e diskubrimentunan mas serio."
+#: rocky/templates/organizations/organization_crisis_room.html
+msgid "Findings table"
+msgstr ""
+
#: rocky/templates/organizations/organization_crisis_room.html
msgid "Finding type:"
msgstr "Tipo di diskubrimentu:"
@@ -6265,10 +6428,6 @@ msgstr "Edita organisashon"
msgid "Save organization"
msgstr "Warda organisashon"
-#: rocky/templates/organizations/organization_list.html
-msgid "Rerun all bits for all my organizations"
-msgstr ""
-
#: rocky/templates/organizations/organization_list.html
msgid "Add new organization"
msgstr "Añadi organisashon nobo"
@@ -6282,6 +6441,15 @@ msgstr "Resúmen di organisashon:"
msgid "Tags"
msgstr "Labelnan"
+#: rocky/templates/organizations/organization_list.html
+msgid "Actions to perform for all of your organizations."
+msgstr ""
+
+#: rocky/templates/organizations/organization_list.html
+#: rocky/templates/organizations/organization_settings.html
+msgid "Rerun all bits"
+msgstr "Pone bits kore atrobe"
+
#: rocky/templates/organizations/organization_member_add.html
msgid " member account setup"
msgstr " konfigurashon di kuenta di miembro"
@@ -6418,10 +6586,6 @@ msgstr ""
msgid "Add indemnification"
msgstr "Añadi indemnisashon"
-#: rocky/templates/organizations/organization_settings.html
-msgid "Rerun all bits"
-msgstr "Pone bits kore atrobe"
-
#: rocky/templates/partials/elements/ooi_detail_settings.html
msgid "Observed at"
msgstr "Observá na"
@@ -6901,10 +7065,6 @@ msgstr "Download meta data i data krudo"
msgid "Download meta data"
msgstr "Deskarga meta datonan"
-#: rocky/templates/tasks/boefje_task_detail.html
-msgid "Input object"
-msgstr "Opheto di entrada"
-
#: rocky/templates/tasks/boefjes.html
#, python-format
msgid ""
@@ -6924,7 +7084,7 @@ msgstr "No tin tareanan pa boefjes"
msgid "List of tasks for boefjes"
msgstr "Lista di tareanan pa boefjes"
-#: rocky/templates/tasks/boefjes.html rocky/templates/tasks/normalizers.html
+#: rocky/templates/tasks/boefjes.html
msgid "Organization Code"
msgstr ""
@@ -7664,6 +7824,9 @@ msgstr ""
msgid "Raw file successfully added."
msgstr "Arkivo crudo añadi ku èxito."
+#~ msgid "Currently there are no findings for OOI"
+#~ msgstr "Aktualmente no a diskubri nada pa OOI"
+
#~ msgid "Select your language"
#~ msgstr "Selekshoná bo idioma"
From 19a3a6900c4e2da3f80eaf8a903d46f1478ac384 Mon Sep 17 00:00:00 2001
From: JP Bruins Slot
Date: Wed, 27 Nov 2024 15:42:38 +0100
Subject: [PATCH 10/44] Update scheduler folder structure (#3883)
Co-authored-by: ammar92
---
docs/source/developer-documentation/mula.md | 78 +++++++-----
mula/Makefile | 6 +-
mula/entrypoint.sh | 2 +-
mula/scheduler/app.py | 9 +-
mula/scheduler/clients/__init__.py | 6 +
.../listeners => clients/amqp}/__init__.py | 0
.../listeners => clients/amqp}/listeners.py | 0
.../listeners => clients/amqp}/raw_data.py | 0
.../amqp}/scan_profile.py | 0
.../{connectors => clients}/connector.py | 0
.../{connectors => clients}/errors.py | 0
mula/scheduler/clients/http/__init__.py | 2 +
mula/scheduler/clients/http/client.py | 77 ++++++++++++
.../http/external}/__init__.py | 0
.../http/external}/bytes.py | 5 +-
.../http/external}/katalogus.py | 114 +++++++++---------
.../http/external}/octopoes.py | 5 +-
.../http/external}/rocky.py | 2 +-
.../services.py => clients/http/service.py} | 0
mula/scheduler/config/__init__.py | 1 +
.../scheduler/connectors/services/__init__.py | 5 -
mula/scheduler/context/context.py | 22 ++--
mula/scheduler/schedulers/__init__.py | 4 +-
.../{queues => schedulers/queue}/__init__.py | 0
.../{queues => schedulers/queue}/errors.py | 0
.../{queues => schedulers/queue}/pq.py | 4 +-
.../{ => schedulers}/rankers/__init__.py | 2 +-
.../{ => schedulers}/rankers/boefje.py | 0
.../{ => schedulers}/rankers/normalizer.py | 0
.../{ => schedulers}/rankers/ranker.py | 0
mula/scheduler/schedulers/scheduler.py | 30 ++---
.../schedulers/schedulers/__init__.py | 3 +
.../schedulers/{ => schedulers}/boefje.py | 20 +--
.../schedulers/{ => schedulers}/normalizer.py | 20 +--
.../schedulers/{ => schedulers}/report.py | 12 +-
mula/scheduler/server/handlers/queues.py | 9 +-
mula/scheduler/storage/__init__.py | 5 +-
mula/scheduler/storage/connection.py | 51 ++++++++
.../migrations}/__init__.py | 0
.../{ => storage/migrations}/alembic.ini | 2 +-
.../{alembic => storage/migrations}/env.py | 0
.../migrations}/script.py.mako | 0
.../versions/0001_initial_migration.py | 0
.../migrations}/versions/0002_update_tasks.py | 0
.../versions/0003_add_type_field_to_tasks.py | 0
.../versions/0004_add_server_default.py | 0
.../versions/0005_size_limit_hash.py | 0
.../0006_add_jsonb_fields_add_jsonb_fields.py | 0
.../0007_add_cancelled_status_for_tasks.py | 0
.../versions/0008_add_task_schedule.py | 0
.../migrations/versions}/__init__.py | 0
mula/scheduler/storage/stores/__init__.py | 3 +
.../storage/{pq_store.py => stores/pq.py} | 9 +-
.../{schedule_store.py => stores/schedule.py} | 11 +-
.../storage/{task_store.py => stores/task.py} | 23 ++--
mula/tests/integration/test_api.py | 7 +-
mula/tests/integration/test_app.py | 5 +-
.../integration/test_boefje_scheduler.py | 27 ++---
.../{test_services.py => test_clients.py} | 35 +++---
mula/tests/integration/test_listeners.py | 4 +-
.../integration/test_normalizer_scheduler.py | 13 +-
mula/tests/integration/test_pq_store.py | 5 +-
.../integration/test_report_scheduler.py | 7 +-
mula/tests/integration/test_schedule_store.py | 6 +-
mula/tests/integration/test_scheduler.py | 18 +--
mula/tests/integration/test_task_store.py | 5 +-
mula/tests/mocks/listener.py | 2 +-
mula/tests/mocks/queue.py | 5 +-
mula/tests/unit/test_queue.py | 22 ++--
69 files changed, 425 insertions(+), 278 deletions(-)
create mode 100644 mula/scheduler/clients/__init__.py
rename mula/scheduler/{connectors/listeners => clients/amqp}/__init__.py (100%)
rename mula/scheduler/{connectors/listeners => clients/amqp}/listeners.py (100%)
rename mula/scheduler/{connectors/listeners => clients/amqp}/raw_data.py (100%)
rename mula/scheduler/{connectors/listeners => clients/amqp}/scan_profile.py (100%)
rename mula/scheduler/{connectors => clients}/connector.py (100%)
rename mula/scheduler/{connectors => clients}/errors.py (100%)
create mode 100644 mula/scheduler/clients/http/__init__.py
create mode 100644 mula/scheduler/clients/http/client.py
rename mula/scheduler/{alembic => clients/http/external}/__init__.py (100%)
rename mula/scheduler/{connectors/services => clients/http/external}/bytes.py (96%)
rename mula/scheduler/{connectors/services => clients/http/external}/katalogus.py (77%)
rename mula/scheduler/{connectors/services => clients/http/external}/octopoes.py (97%)
rename mula/scheduler/{connectors/services => clients/http/external}/rocky.py (50%)
rename mula/scheduler/{connectors/services/services.py => clients/http/service.py} (100%)
delete mode 100644 mula/scheduler/connectors/services/__init__.py
rename mula/scheduler/{queues => schedulers/queue}/__init__.py (100%)
rename mula/scheduler/{queues => schedulers/queue}/errors.py (100%)
rename mula/scheduler/{queues => schedulers/queue}/pq.py (98%)
rename mula/scheduler/{ => schedulers}/rankers/__init__.py (54%)
rename mula/scheduler/{ => schedulers}/rankers/boefje.py (100%)
rename mula/scheduler/{ => schedulers}/rankers/normalizer.py (100%)
rename mula/scheduler/{ => schedulers}/rankers/ranker.py (100%)
create mode 100644 mula/scheduler/schedulers/schedulers/__init__.py
rename mula/scheduler/schedulers/{ => schedulers}/boefje.py (98%)
rename mula/scheduler/schedulers/{ => schedulers}/normalizer.py (96%)
rename mula/scheduler/schedulers/{ => schedulers}/report.py (94%)
create mode 100644 mula/scheduler/storage/connection.py
rename mula/scheduler/{alembic/versions => storage/migrations}/__init__.py (100%)
rename mula/scheduler/{ => storage/migrations}/alembic.ini (98%)
rename mula/scheduler/{alembic => storage/migrations}/env.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/script.py.mako (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0001_initial_migration.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0002_update_tasks.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0003_add_type_field_to_tasks.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0004_add_server_default.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0005_size_limit_hash.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0006_add_jsonb_fields_add_jsonb_fields.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0007_add_cancelled_status_for_tasks.py (100%)
rename mula/scheduler/{alembic => storage/migrations}/versions/0008_add_task_schedule.py (100%)
rename mula/scheduler/{connectors => storage/migrations/versions}/__init__.py (100%)
create mode 100644 mula/scheduler/storage/stores/__init__.py
rename mula/scheduler/storage/{pq_store.py => stores/pq.py} (97%)
rename mula/scheduler/storage/{schedule_store.py => stores/schedule.py} (93%)
rename mula/scheduler/storage/{task_store.py => stores/task.py} (91%)
rename mula/tests/integration/{test_services.py => test_clients.py} (91%)
diff --git a/docs/source/developer-documentation/mula.md b/docs/source/developer-documentation/mula.md
index 9005e197a52..492caebc825 100644
--- a/docs/source/developer-documentation/mula.md
+++ b/docs/source/developer-documentation/mula.md
@@ -6,8 +6,8 @@ The scheduler is responsible for scheduling the execution of tasks. The
execution of those tasks are being prioritized / scored by a ranker. The tasks
are then pushed onto a priority queue.
-Within the project of KAT, the scheduler is tasked with scheduling boefje and
-normalizer tasks.
+Within the project of KAT, the scheduler is tasked with scheduling boefje,
+normalizer, and report tasks.
## Architecture
@@ -20,12 +20,12 @@ rankers.
### Stack, packages and libraries
-| Name | Version | Description |
-| ---------- | -------- | ------------------- |
-| Python | ^3.8 | |
-| FastAPI | ^0.109.0 | Used for api server |
-| SQLAlchemy | ^2.0.23 | |
-| pydantic | ^2.5.2 | |
+| Name | Version | Description |
+| ---------- | --------- | ------------------- |
+| Python | ^3.10 | |
+| FastAPI | ^0.1115.2 | Used for api server |
+| SQLAlchemy | ^2.0.23 | |
+| pydantic | ^2.7.2 | |
### External services
@@ -41,36 +41,34 @@ The scheduler interfaces with the following services:
### Project structure
```
-$ tree -L 3 --dirsfirst
.
├── docs/ # additional documentation
├── scheduler/ # scheduler python module
-│  ├── config # application settings configuration
-│  ├── connectors # external service connectors
-│  │  ├── listeners # channel/socket listeners
-│  │  ├── services # rest api connectors
-│  │  └── __init__.py
-│  ├── context/ # shared application context
-│  ├── models/ # internal model definitions
-│  ├── queues/ # priority queue
-│  ├── rankers/ # priority/score calculations
-│  ├── storage/ # data abstraction layer
-│  ├── schedulers/ # schedulers
-│  ├── server/ # http rest api server
-│  ├── utils/ # common utility functions
+│ ├── clients/ # external service clients
+│ │ ├── amqp/ # rabbitmq clients
+│ │ └── http/ # http clients
+│ ├── context/ # shared application context, and configuration
+│ ├── models/ # internal model definitions
+│ ├── schedulers/ # schedulers
+│ │ ├── queue/ # priority queue
+│ │ ├── rankers/ # priority/score calculations
+│ │ └── schedulers/ # schedulers implementations
+│ ├── server/ # http rest api server
+│ ├── storage/ # data abstraction layer
+│ │ ├── migrations/ # database migrations
+│ │ └── stores/ # data stores
+│ ├── utils/ # common utility functions
│  ├── __init__.py
│  ├── __main__.py
-│  ├── app.py # kat scheduler app implementation
+│  ├── app.py # OpenKAT scheduler app implementation
│  └── version.py # version information
-└─── tests/
-   ├── factories/
-   ├── integration/
-   ├── mocks/
-   ├── scripts/
-   ├── simulation/
-   ├── unit/
-   ├── utils/
-   └── __init__.py
+└─── tests/ # test suite
+   ├── factories/ # factories for test data
+   ├── integration/ # integration tests
+   ├── mocks/ # mocks for testing
+   ├── simulation/ # simulation tests
+   ├── unit/ # unit tests
+   └── utils/ # utility functions for tests
```
## Running / Developing
@@ -93,6 +91,22 @@ scheduler. See the environment settings section under Installation and Deploymen
$ docker compose up --build -d scheduler
```
+### Migrations
+
+Creating a migration:
+
+```
+# Run migrations
+make revid=0008 m="add_task_schedule" migrations
+```
+
+Sometimes it is helpful to run the migrations in a clean environment:
+
+```
+docker system prune
+docker volume prune --force --all
+```
+
## Testing
```
diff --git a/mula/Makefile b/mula/Makefile
index c152665e536..7d9724afed5 100644
--- a/mula/Makefile
+++ b/mula/Makefile
@@ -74,7 +74,7 @@ cov: ## Generate a test coverage report
sql: ## Generate raw sql for the migrations.
docker compose run --rm scheduler \
- alembic --config /app/scheduler/scheduler/alembic.ini \
+ alembic --config /app/scheduler/scheduler/storage/migrations/alembic.ini \
upgrade $(rev1):$(rev2) --sql
migrations: ## Create migration.
@@ -84,14 +84,14 @@ else ifeq ($(revid),)
$(HIDE) (echo "ERROR: Specify a message with m={message} and a rev-id with revid={revid} (e.g. 0001 etc.)"; exit 1)
else
docker compose run --rm scheduler \
- alembic --config /app/scheduler/scheduler/alembic.ini \
+ alembic --config /app/scheduler/scheduler/storage/migrations/alembic.ini \
revision --autogenerate \
-m "$(m)" --rev-id "$(revid)"
endif
migrate: ## Run migrations using alembic.
docker compose run scheduler \
- alembic --config /app/scheduler/scheduler/alembic.ini \
+ alembic --config /app/scheduler/scheduler/storage/migrations/alembic.ini \
upgrade head
##
diff --git a/mula/entrypoint.sh b/mula/entrypoint.sh
index 7e52612a54a..cdaf19c6b8c 100755
--- a/mula/entrypoint.sh
+++ b/mula/entrypoint.sh
@@ -5,7 +5,7 @@ set -e
shopt -s nocasematch
if [ "$DATABASE_MIGRATION" = "1" ] || [[ $DATABASE_MIGRATION == "true" ]]; then
- python -m alembic --config /app/scheduler/scheduler/alembic.ini upgrade head
+ python -m alembic --config /app/scheduler/scheduler/storage/migrations/alembic.ini upgrade head
fi
exec "$@"
diff --git a/mula/scheduler/app.py b/mula/scheduler/app.py
index 58a6e0890ac..d8770730762 100644
--- a/mula/scheduler/app.py
+++ b/mula/scheduler/app.py
@@ -4,8 +4,7 @@
import structlog
from opentelemetry import trace
-from scheduler import context, schedulers, server
-from scheduler.connectors.errors import ExternalServiceError
+from scheduler import clients, context, schedulers, server
from scheduler.utils import thread
tracer = trace.get_tracer(__name__)
@@ -83,7 +82,7 @@ def monitor_organisations(self) -> None:
}
try:
orgs = self.ctx.services.katalogus.get_organisations()
- except ExternalServiceError:
+ except clients.errors.ExternalServiceError:
self.logger.exception("Failed to get organisations from Katalogus")
return
@@ -117,7 +116,7 @@ def monitor_organisations(self) -> None:
for org_id in additions:
try:
org = self.ctx.services.katalogus.get_organisation(org_id)
- except ExternalServiceError as e:
+ except clients.errors.ExternalServiceError as e:
self.logger.error("Failed to get organisation from Katalogus", error=e, org_id=org_id)
continue
@@ -166,7 +165,7 @@ def start_schedulers(self) -> None:
# Initialize the schedulers
try:
orgs = self.ctx.services.katalogus.get_organisations()
- except ExternalServiceError as e:
+ except clients.errors.ExternalServiceError as e:
self.logger.error("Failed to get organisations from Katalogus", error=e)
return
diff --git a/mula/scheduler/clients/__init__.py b/mula/scheduler/clients/__init__.py
new file mode 100644
index 00000000000..0a306fe0e41
--- /dev/null
+++ b/mula/scheduler/clients/__init__.py
@@ -0,0 +1,6 @@
+from .amqp.raw_data import RawData
+from .amqp.scan_profile import ScanProfileMutation
+from .http.external.bytes import Bytes
+from .http.external.katalogus import Katalogus
+from .http.external.octopoes import Octopoes
+from .http.external.rocky import Rocky
diff --git a/mula/scheduler/connectors/listeners/__init__.py b/mula/scheduler/clients/amqp/__init__.py
similarity index 100%
rename from mula/scheduler/connectors/listeners/__init__.py
rename to mula/scheduler/clients/amqp/__init__.py
diff --git a/mula/scheduler/connectors/listeners/listeners.py b/mula/scheduler/clients/amqp/listeners.py
similarity index 100%
rename from mula/scheduler/connectors/listeners/listeners.py
rename to mula/scheduler/clients/amqp/listeners.py
diff --git a/mula/scheduler/connectors/listeners/raw_data.py b/mula/scheduler/clients/amqp/raw_data.py
similarity index 100%
rename from mula/scheduler/connectors/listeners/raw_data.py
rename to mula/scheduler/clients/amqp/raw_data.py
diff --git a/mula/scheduler/connectors/listeners/scan_profile.py b/mula/scheduler/clients/amqp/scan_profile.py
similarity index 100%
rename from mula/scheduler/connectors/listeners/scan_profile.py
rename to mula/scheduler/clients/amqp/scan_profile.py
diff --git a/mula/scheduler/connectors/connector.py b/mula/scheduler/clients/connector.py
similarity index 100%
rename from mula/scheduler/connectors/connector.py
rename to mula/scheduler/clients/connector.py
diff --git a/mula/scheduler/connectors/errors.py b/mula/scheduler/clients/errors.py
similarity index 100%
rename from mula/scheduler/connectors/errors.py
rename to mula/scheduler/clients/errors.py
diff --git a/mula/scheduler/clients/http/__init__.py b/mula/scheduler/clients/http/__init__.py
new file mode 100644
index 00000000000..52343f6deae
--- /dev/null
+++ b/mula/scheduler/clients/http/__init__.py
@@ -0,0 +1,2 @@
+from .client import HTTPClient
+from .service import HTTPService
diff --git a/mula/scheduler/clients/http/client.py b/mula/scheduler/clients/http/client.py
new file mode 100644
index 00000000000..24202afb211
--- /dev/null
+++ b/mula/scheduler/clients/http/client.py
@@ -0,0 +1,77 @@
+import socket
+import time
+from collections.abc import Callable
+
+import httpx
+import structlog
+
+
+class HTTPClient:
+ """A class that provides methods to check if a host is available and healthy."""
+
+ def __init__(self):
+ self.logger = structlog.get_logger(self.__class__.__name__)
+
+ def is_host_available(self, hostname: str, port: int) -> bool:
+ """Check if the host is available.
+
+ Args:
+ hostname: A string representing the hostname.
+ port: An integer representing the port number.
+
+ Returns:
+ A boolean
+ """
+ try:
+ socket.create_connection((hostname, port))
+ return True
+ except OSError:
+ return False
+
+ def is_host_healthy(self, host: str, health_endpoint: str) -> bool:
+ """Check if host is healthy by inspecting the host's health endpoint.
+
+ Args:
+ host: A string representing the hostname.
+ health_endpoint: A string representing the health endpoint.
+
+ Returns:
+ A boolean
+ """
+ try:
+ url = f"{host}/{health_endpoint}"
+ response = httpx.get(url, timeout=5)
+ healthy = response.json().get("healthy")
+ return healthy
+ except httpx.HTTPError as exc:
+ self.logger.warning("Exception: %s", exc)
+ return False
+
+ def retry(self, func: Callable, *args, **kwargs) -> bool:
+ """Retry a function until it returns True.
+
+ Args:
+ func: A python callable that needs to be retried.
+
+ Returns:
+ A boolean signifying whether or not the func was executed successfully.
+ """
+ for i in range(10):
+ if func(*args, **kwargs):
+ self.logger.info(
+ "Function %s, executed successfully. Retry count: %d",
+ func.__name__,
+ i,
+ name=func.__name__,
+ args=args,
+ kwargs=kwargs,
+ )
+ return True
+
+ self.logger.warning(
+ "Function %s, failed. Retry count: %d", func.__name__, i, name=func.__name__, args=args, kwargs=kwargs
+ )
+
+ time.sleep(10)
+
+ return False
diff --git a/mula/scheduler/alembic/__init__.py b/mula/scheduler/clients/http/external/__init__.py
similarity index 100%
rename from mula/scheduler/alembic/__init__.py
rename to mula/scheduler/clients/http/external/__init__.py
diff --git a/mula/scheduler/connectors/services/bytes.py b/mula/scheduler/clients/http/external/bytes.py
similarity index 96%
rename from mula/scheduler/connectors/services/bytes.py
rename to mula/scheduler/clients/http/external/bytes.py
index 86a5e434433..bfceab892a8 100644
--- a/mula/scheduler/connectors/services/bytes.py
+++ b/mula/scheduler/clients/http/external/bytes.py
@@ -6,11 +6,10 @@
import httpx
-from scheduler.connectors.errors import ExternalServiceResponseError, exception_handler
+from scheduler.clients.errors import ExternalServiceResponseError, exception_handler
+from scheduler.clients.http import HTTPService
from scheduler.models import BoefjeMeta
-from .services import HTTPService
-
ClientSessionMethod = Callable[..., Any]
diff --git a/mula/scheduler/connectors/services/katalogus.py b/mula/scheduler/clients/http/external/katalogus.py
similarity index 77%
rename from mula/scheduler/connectors/services/katalogus.py
rename to mula/scheduler/clients/http/external/katalogus.py
index 99c4b3a011f..ba174259de5 100644
--- a/mula/scheduler/connectors/services/katalogus.py
+++ b/mula/scheduler/clients/http/external/katalogus.py
@@ -2,12 +2,11 @@
import httpx
-from scheduler.connectors.errors import exception_handler
+from scheduler.clients.errors import exception_handler
+from scheduler.clients.http import HTTPService
from scheduler.models import Boefje, Organisation, Plugin
from scheduler.utils import dict_utils
-from .services import HTTPService
-
class Katalogus(HTTPService):
"""A class that provides methods to interact with the Katalogus API."""
@@ -44,95 +43,90 @@ def __init__(self, host: str, source: str, timeout: int, pool_connections: int,
def flush_caches(self) -> None:
self.flush_plugin_cache()
- self.flush_boefje_cache(self.plugin_cache)
- self.flush_normalizer_cache(self.plugin_cache)
+ self.flush_normalizer_cache()
+ self.flush_boefje_cache()
- def flush_plugin_cache(self):
+ def flush_plugin_cache(self) -> None:
self.logger.debug("Flushing the katalogus plugin cache for organisations")
- plugin_cache: dict = {}
- orgs = self.get_organisations()
- for org in orgs:
- plugin_cache.setdefault(org.id, {})
-
- plugins = self.get_plugins_by_organisation(org.id)
- plugin_cache[org.id] = {plugin.id: plugin for plugin in plugins if plugin.enabled}
-
with self.plugin_cache_lock:
# First, we reset the cache, to make sure we won't get any ExpiredError
self.plugin_cache.expiration_enabled = False
self.plugin_cache.reset()
- self.plugin_cache.cache = plugin_cache
+
+ orgs = self.get_organisations()
+ for org in orgs:
+ self.plugin_cache.setdefault(org.id, {})
+
+ plugins = self.get_plugins_by_organisation(org.id)
+ self.plugin_cache[org.id] = {plugin.id: plugin for plugin in plugins if plugin.enabled}
+
self.plugin_cache.expiration_enabled = True
self.logger.debug("Flushed the katalogus plugin cache for organisations")
- def flush_boefje_cache(self, plugins=None) -> None:
+ def flush_boefje_cache(self) -> None:
"""boefje.consumes -> plugin type boefje"""
self.logger.debug("Flushing the katalogus boefje type cache for organisations")
- boefje_cache: dict = {}
- orgs = self.get_organisations()
- for org in orgs:
- boefje_cache.setdefault(org.id, {})
+ with self.boefje_cache_lock:
+ # First, we reset the cache, to make sure we won't get any ExpiredError
+ self.boefje_cache.expiration_enabled = False
+ self.boefje_cache.reset()
- org_plugins = plugins[org.id].values() if plugins else self.get_plugins_by_organisation(org.id)
- for plugin in org_plugins:
- if plugin.type != "boefje":
- continue
+ orgs = self.get_organisations()
+ for org in orgs:
+ self.boefje_cache[org.id] = {}
- if plugin.enabled is False:
- continue
+ for plugin in self.get_plugins_by_organisation(org.id):
+ if plugin.type != "boefje":
+ continue
- if not plugin.consumes:
- continue
+ if plugin.enabled is False:
+ continue
- # NOTE: backwards compatibility, when it is a boefje the
- # consumes field is a string field.
- if isinstance(plugin.consumes, str):
- boefje_cache[org.id].setdefault(plugin.consumes, []).append(plugin)
- continue
+ if not plugin.consumes:
+ continue
- for type_ in plugin.consumes:
- boefje_cache[org.id].setdefault(type_, []).append(plugin)
+ # NOTE: backwards compatibility, when it is a boefje the
+ # consumes field is a string field.
+ if isinstance(plugin.consumes, str):
+ self.boefje_cache[org.id].setdefault(plugin.consumes, []).append(plugin)
+ continue
+
+ for type_ in plugin.consumes:
+ self.boefje_cache[org.id].setdefault(type_, []).append(plugin)
- with self.boefje_cache_lock:
- # First, we reset the cache, to make sure we won't get any ExpiredError
- self.boefje_cache.expiration_enabled = False
- self.boefje_cache.reset()
- self.boefje_cache.cache = boefje_cache
self.boefje_cache.expiration_enabled = True
self.logger.debug("Flushed the katalogus boefje type cache for organisations")
- def flush_normalizer_cache(self, plugins=None) -> None:
+ def flush_normalizer_cache(self) -> None:
"""normalizer.consumes -> plugin type normalizer"""
self.logger.debug("Flushing the katalogus normalizer type cache for organisations")
- normalizer_cache: dict = {}
- orgs = self.get_organisations()
- for org in orgs:
- normalizer_cache.setdefault(org.id, {})
+ with self.normalizer_cache_lock:
+ # First, we reset the cache, to make sure we won't get any ExpiredError
+ self.normalizer_cache.expiration_enabled = False
+ self.normalizer_cache.reset()
+
+ orgs = self.get_organisations()
+ for org in orgs:
+ self.normalizer_cache[org.id] = {}
- org_plugins = plugins[org.id].values() if plugins else self.get_plugins_by_organisation(org.id)
- for plugin in org_plugins:
- if plugin.type != "normalizer":
- continue
+ for plugin in self.get_plugins_by_organisation(org.id):
+ if plugin.type != "normalizer":
+ continue
- if plugin.enabled is False:
- continue
+ if plugin.enabled is False:
+ continue
- if not plugin.consumes:
- continue
+ if not plugin.consumes:
+ continue
- for type_ in plugin.consumes:
- normalizer_cache[org.id].setdefault(type_, []).append(plugin)
+ for type_ in plugin.consumes:
+ self.normalizer_cache[org.id].setdefault(type_, []).append(plugin)
- with self.normalizer_cache_lock:
- # First, we reset the cache, to make sure we won't get any ExpiredError
- self.normalizer_cache.expiration_enabled = False
- self.normalizer_cache.reset()
- self.normalizer_cache.cache = normalizer_cache
self.normalizer_cache.expiration_enabled = True
self.logger.debug("Flushed the katalogus normalizer type cache for organisations")
diff --git a/mula/scheduler/connectors/services/octopoes.py b/mula/scheduler/clients/http/external/octopoes.py
similarity index 97%
rename from mula/scheduler/connectors/services/octopoes.py
rename to mula/scheduler/clients/http/external/octopoes.py
index 4632f8414a9..6d3538b0e46 100644
--- a/mula/scheduler/connectors/services/octopoes.py
+++ b/mula/scheduler/clients/http/external/octopoes.py
@@ -3,11 +3,10 @@
import httpx
from pydantic import BaseModel
-from scheduler.connectors.errors import exception_handler
+from scheduler.clients.errors import exception_handler
+from scheduler.clients.http import HTTPService
from scheduler.models import OOI, Organisation
-from .services import HTTPService
-
class ListObjectsResponse(BaseModel):
count: int
diff --git a/mula/scheduler/connectors/services/rocky.py b/mula/scheduler/clients/http/external/rocky.py
similarity index 50%
rename from mula/scheduler/connectors/services/rocky.py
rename to mula/scheduler/clients/http/external/rocky.py
index b4c0fea8df1..558882e2791 100644
--- a/mula/scheduler/connectors/services/rocky.py
+++ b/mula/scheduler/clients/http/external/rocky.py
@@ -1,4 +1,4 @@
-from .services import HTTPService
+from scheduler.clients.http import HTTPService
class Rocky(HTTPService):
diff --git a/mula/scheduler/connectors/services/services.py b/mula/scheduler/clients/http/service.py
similarity index 100%
rename from mula/scheduler/connectors/services/services.py
rename to mula/scheduler/clients/http/service.py
diff --git a/mula/scheduler/config/__init__.py b/mula/scheduler/config/__init__.py
index e69de29bb2d..906791fa29d 100644
--- a/mula/scheduler/config/__init__.py
+++ b/mula/scheduler/config/__init__.py
@@ -0,0 +1 @@
+from .settings import Settings
diff --git a/mula/scheduler/connectors/services/__init__.py b/mula/scheduler/connectors/services/__init__.py
deleted file mode 100644
index 2082f2c95e6..00000000000
--- a/mula/scheduler/connectors/services/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .bytes import Bytes
-from .katalogus import Katalogus
-from .octopoes import Octopoes
-from .rocky import Rocky
-from .services import HTTPService
diff --git a/mula/scheduler/context/context.py b/mula/scheduler/context/context.py
index 6fb5ea80105..00b4d8f16f4 100644
--- a/mula/scheduler/context/context.py
+++ b/mula/scheduler/context/context.py
@@ -7,9 +7,9 @@
from prometheus_client import CollectorRegistry, Gauge, Info
import scheduler
-from scheduler import storage
+from scheduler import clients, storage
from scheduler.config import settings
-from scheduler.connectors import services
+from scheduler.storage import stores
from scheduler.utils import remove_trailing_slash
@@ -116,7 +116,7 @@ def __init__(self) -> None:
self.logger: structlog.BoundLogger = structlog.get_logger(__name__)
# Services
- katalogus_service = services.Katalogus(
+ katalogus_service = clients.Katalogus(
host=remove_trailing_slash(str(self.config.host_katalogus)),
source=f"scheduler/{scheduler.__version__}",
timeout=self.config.katalogus_request_timeout,
@@ -124,7 +124,7 @@ def __init__(self) -> None:
cache_ttl=self.config.katalogus_cache_ttl,
)
- bytes_service = services.Bytes(
+ bytes_service = clients.Bytes(
host=remove_trailing_slash(str(self.config.host_bytes)),
source=f"scheduler/{scheduler.__version__}",
user=self.config.host_bytes_user,
@@ -133,7 +133,7 @@ def __init__(self) -> None:
pool_connections=self.config.bytes_pool_connections,
)
- octopoes_service = services.Octopoes(
+ octopoes_service = clients.Octopoes(
host=remove_trailing_slash(str(self.config.host_octopoes)),
source=f"scheduler/{scheduler.__version__}",
timeout=self.config.octopoes_request_timeout,
@@ -145,9 +145,9 @@ def __init__(self) -> None:
# notation
self.services: SimpleNamespace = SimpleNamespace(
**{
- services.Katalogus.name: katalogus_service,
- services.Octopoes.name: octopoes_service,
- services.Bytes.name: bytes_service,
+ clients.Katalogus.name: katalogus_service,
+ clients.Octopoes.name: octopoes_service,
+ clients.Bytes.name: bytes_service,
}
)
@@ -165,9 +165,9 @@ def __init__(self) -> None:
# Datastores, SimpleNamespace allows us to use dot notation
self.datastores: SimpleNamespace = SimpleNamespace(
**{
- storage.ScheduleStore.name: storage.ScheduleStore(dbconn),
- storage.TaskStore.name: storage.TaskStore(dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(dbconn),
+ stores.TaskStore.name: stores.TaskStore(dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(dbconn),
}
)
diff --git a/mula/scheduler/schedulers/__init__.py b/mula/scheduler/schedulers/__init__.py
index 4c82914aee5..0ea877f4541 100644
--- a/mula/scheduler/schedulers/__init__.py
+++ b/mula/scheduler/schedulers/__init__.py
@@ -1,4 +1,2 @@
-from .boefje import BoefjeScheduler
-from .normalizer import NormalizerScheduler
-from .report import ReportScheduler
from .scheduler import Scheduler
+from .schedulers import BoefjeScheduler, NormalizerScheduler, ReportScheduler
diff --git a/mula/scheduler/queues/__init__.py b/mula/scheduler/schedulers/queue/__init__.py
similarity index 100%
rename from mula/scheduler/queues/__init__.py
rename to mula/scheduler/schedulers/queue/__init__.py
diff --git a/mula/scheduler/queues/errors.py b/mula/scheduler/schedulers/queue/errors.py
similarity index 100%
rename from mula/scheduler/queues/errors.py
rename to mula/scheduler/schedulers/queue/errors.py
diff --git a/mula/scheduler/queues/pq.py b/mula/scheduler/schedulers/queue/pq.py
similarity index 98%
rename from mula/scheduler/queues/pq.py
rename to mula/scheduler/schedulers/queue/pq.py
index 7cb160c7c2e..4a1914451a6 100644
--- a/mula/scheduler/queues/pq.py
+++ b/mula/scheduler/schedulers/queue/pq.py
@@ -58,7 +58,7 @@ def __init__(
pq_id: str,
maxsize: int,
item_type: Any,
- pq_store: storage.PriorityQueueStore,
+ pq_store: storage.stores.PriorityQueueStore,
allow_replace: bool = False,
allow_updates: bool = False,
allow_priority_updates: bool = False,
@@ -94,7 +94,7 @@ def __init__(
self.allow_replace: bool = allow_replace
self.allow_updates: bool = allow_updates
self.allow_priority_updates: bool = allow_priority_updates
- self.pq_store: storage.PriorityQueueStore = pq_store
+ self.pq_store: storage.stores.PriorityQueueStore = pq_store
self.lock: threading.Lock = threading.Lock()
def pop(self, filters: storage.filters.FilterRequest | None = None) -> models.Task | None:
diff --git a/mula/scheduler/rankers/__init__.py b/mula/scheduler/schedulers/rankers/__init__.py
similarity index 54%
rename from mula/scheduler/rankers/__init__.py
rename to mula/scheduler/schedulers/rankers/__init__.py
index 49a565268ec..9fd14d2b21e 100644
--- a/mula/scheduler/rankers/__init__.py
+++ b/mula/scheduler/schedulers/rankers/__init__.py
@@ -1,3 +1,3 @@
-from .boefje import BoefjeRanker
+from .boefje import BoefjeRanker, BoefjeRankerTimeBased
from .normalizer import NormalizerRanker
from .ranker import Ranker
diff --git a/mula/scheduler/rankers/boefje.py b/mula/scheduler/schedulers/rankers/boefje.py
similarity index 100%
rename from mula/scheduler/rankers/boefje.py
rename to mula/scheduler/schedulers/rankers/boefje.py
diff --git a/mula/scheduler/rankers/normalizer.py b/mula/scheduler/schedulers/rankers/normalizer.py
similarity index 100%
rename from mula/scheduler/rankers/normalizer.py
rename to mula/scheduler/schedulers/rankers/normalizer.py
diff --git a/mula/scheduler/rankers/ranker.py b/mula/scheduler/schedulers/rankers/ranker.py
similarity index 100%
rename from mula/scheduler/rankers/ranker.py
rename to mula/scheduler/schedulers/rankers/ranker.py
diff --git a/mula/scheduler/schedulers/scheduler.py b/mula/scheduler/schedulers/scheduler.py
index 22eaf56af4c..b81e1efacf8 100644
--- a/mula/scheduler/schedulers/scheduler.py
+++ b/mula/scheduler/schedulers/scheduler.py
@@ -9,7 +9,9 @@
import structlog
from opentelemetry import trace
-from scheduler import connectors, context, models, queues, storage, utils
+from scheduler import clients, context, models, storage, utils
+from scheduler.schedulers.queue import PriorityQueue
+from scheduler.schedulers.queue.errors import InvalidItemError, NotAllowedError, QueueEmptyError, QueueFullError
from scheduler.utils import cron, thread
tracer = trace.get_tracer(__name__)
@@ -26,7 +28,7 @@ class Scheduler(abc.ABC):
Application context of shared data (e.g. configuration, external
services connections).
queue:
- A queues.PriorityQueue instance
+ A queue.PriorityQueue instance
callback:
A callback function to call when the scheduler is stopped.
scheduler_id:
@@ -57,7 +59,7 @@ def __init__(
self,
ctx: context.AppContext,
scheduler_id: str,
- queue: queues.PriorityQueue | None = None,
+ queue: PriorityQueue | None = None,
callback: Callable[..., None] | None = None,
max_tries: int = -1,
create_schedule: bool = False,
@@ -72,7 +74,7 @@ def __init__(
scheduler_id:
The id of the scheduler.
queue:
- A queues.PriorityQueue instance
+ A queue.PriorityQueue instance
callback:
A callback function to call when the scheduler is stopped.
max_tries:
@@ -93,7 +95,7 @@ def __init__(
self._last_activity: datetime | None = None
# Queue
- self.queue = queue or queues.PriorityQueue(
+ self.queue = queue or PriorityQueue(
pq_id=scheduler_id,
maxsize=self.ctx.config.pq_maxsize,
item_type=self.ITEM_TYPE,
@@ -101,7 +103,7 @@ def __init__(
)
# Listeners
- self.listeners: dict[str, connectors.listeners.Listener] = {}
+ self.listeners: dict[str, clients.amqp.Listener] = {}
# Threads
self.lock: threading.Lock = threading.Lock()
@@ -141,7 +143,7 @@ def push_items_to_queue(self, items: list[models.Task]) -> None:
for item in items:
try:
self.push_item_to_queue(item)
- except (queues.errors.NotAllowedError, queues.errors.QueueFullError, queues.errors.InvalidItemError) as exc:
+ except (NotAllowedError, QueueFullError, InvalidItemError) as exc:
self.logger.debug(
"Unable to push item %s to queue %s (%s)",
item.id,
@@ -188,7 +190,7 @@ def push_item_to_queue_with_timeout(self, item: models.Task, max_tries: int = 5,
tries += 1
if tries >= max_tries and max_tries != -1:
- raise queues.errors.QueueFullError()
+ raise QueueFullError()
self.push_item_to_queue(item)
@@ -211,14 +213,14 @@ def push_item_to_queue(self, item: models.Task) -> models.Task:
queue_id=self.queue.pq_id,
scheduler_id=self.scheduler_id,
)
- raise queues.errors.NotAllowedError("Scheduler is disabled")
+ raise NotAllowedError("Scheduler is disabled")
try:
if item.type is None:
item.type = self.ITEM_TYPE.type
item.status = models.TaskStatus.QUEUED
item = self.queue.push(item)
- except queues.errors.NotAllowedError as exc:
+ except NotAllowedError as exc:
self.logger.warning(
"Not allowed to push to queue %s (%s)",
self.queue.pq_id,
@@ -228,7 +230,7 @@ def push_item_to_queue(self, item: models.Task) -> models.Task:
scheduler_id=self.scheduler_id,
)
raise exc
- except queues.errors.QueueFullError as exc:
+ except QueueFullError as exc:
self.logger.warning(
"Queue %s is full, not pushing new items (%s)",
self.queue.pq_id,
@@ -239,7 +241,7 @@ def push_item_to_queue(self, item: models.Task) -> models.Task:
scheduler_id=self.scheduler_id,
)
raise exc
- except queues.errors.InvalidItemError as exc:
+ except InvalidItemError as exc:
self.logger.warning(
"Invalid item %s",
item.id,
@@ -357,11 +359,11 @@ def pop_item_from_queue(self, filters: storage.filters.FilterRequest | None = No
queue_qsize=self.queue.qsize(),
scheduler_id=self.scheduler_id,
)
- raise queues.errors.NotAllowedError("Scheduler is disabled")
+ raise NotAllowedError("Scheduler is disabled")
try:
item = self.queue.pop(filters)
- except queues.QueueEmptyError as exc:
+ except QueueEmptyError as exc:
raise exc
if item is not None:
diff --git a/mula/scheduler/schedulers/schedulers/__init__.py b/mula/scheduler/schedulers/schedulers/__init__.py
new file mode 100644
index 00000000000..66ab1de1a08
--- /dev/null
+++ b/mula/scheduler/schedulers/schedulers/__init__.py
@@ -0,0 +1,3 @@
+from .boefje import BoefjeScheduler
+from .normalizer import NormalizerScheduler
+from .report import ReportScheduler
diff --git a/mula/scheduler/schedulers/boefje.py b/mula/scheduler/schedulers/schedulers/boefje.py
similarity index 98%
rename from mula/scheduler/schedulers/boefje.py
rename to mula/scheduler/schedulers/schedulers/boefje.py
index c229a0f99d7..c13b62f194e 100644
--- a/mula/scheduler/schedulers/boefje.py
+++ b/mula/scheduler/schedulers/schedulers/boefje.py
@@ -8,9 +8,8 @@
import structlog
from opentelemetry import trace
-from scheduler import context, queues, rankers, storage, utils
-from scheduler.connectors import listeners
-from scheduler.connectors.errors import ExternalServiceError
+from scheduler import clients, context, storage, utils
+from scheduler.clients.errors import ExternalServiceError
from scheduler.models import (
OOI,
Boefje,
@@ -22,10 +21,11 @@
Task,
TaskStatus,
)
+from scheduler.schedulers import Scheduler
+from scheduler.schedulers.queue import PriorityQueue, QueueFullError
+from scheduler.schedulers.rankers import BoefjeRanker
from scheduler.storage import filters
-from .scheduler import Scheduler
-
tracer = trace.get_tracer(__name__)
@@ -45,7 +45,7 @@ def __init__(
ctx: context.AppContext,
scheduler_id: str,
organisation: Organisation,
- queue: queues.PriorityQueue | None = None,
+ queue: PriorityQueue | None = None,
callback: Callable[..., None] | None = None,
):
"""Initializes the BoefjeScheduler.
@@ -60,7 +60,7 @@ def __init__(
self.logger: structlog.BoundLogger = structlog.getLogger(__name__)
self.organisation: Organisation = organisation
- self.queue = queue or queues.PriorityQueue(
+ self.queue = queue or PriorityQueue(
pq_id=scheduler_id,
maxsize=ctx.config.pq_maxsize,
item_type=self.ITEM_TYPE,
@@ -78,7 +78,7 @@ def __init__(
)
# Priority ranker
- self.priority_ranker = rankers.BoefjeRanker(self.ctx)
+ self.priority_ranker = BoefjeRanker(self.ctx)
def run(self) -> None:
"""The run method is called when the scheduler is started. It will
@@ -97,7 +97,7 @@ def run(self) -> None:
reschedule it.
"""
# Scan profile mutations
- self.listeners["scan_profile_mutations"] = listeners.ScanProfileMutation(
+ self.listeners["scan_profile_mutations"] = clients.ScanProfileMutation(
dsn=str(self.ctx.config.host_raw_data),
queue=f"{self.organisation.id}__scan_profile_mutations",
func=self.push_tasks_for_scan_profile_mutations,
@@ -583,7 +583,7 @@ def push_boefje_task(self, boefje_task: BoefjeTask, caller: str = "") -> None:
try:
self.push_item_to_queue_with_timeout(task, self.max_tries)
- except queues.QueueFullError:
+ except QueueFullError:
self.logger.warning(
"Could not add task to queue, queue was full: %s",
boefje_task.hash,
diff --git a/mula/scheduler/schedulers/normalizer.py b/mula/scheduler/schedulers/schedulers/normalizer.py
similarity index 96%
rename from mula/scheduler/schedulers/normalizer.py
rename to mula/scheduler/schedulers/schedulers/normalizer.py
index d633b061274..47db57e7c97 100644
--- a/mula/scheduler/schedulers/normalizer.py
+++ b/mula/scheduler/schedulers/schedulers/normalizer.py
@@ -7,12 +7,12 @@
import structlog
from opentelemetry import trace
-from scheduler import context, models, queues, rankers
-from scheduler.connectors import listeners
-from scheduler.connectors.errors import ExternalServiceError
+from scheduler import clients, context, models
+from scheduler.clients.errors import ExternalServiceError
from scheduler.models import Normalizer, NormalizerTask, Organisation, Plugin, RawDataReceivedEvent, Task, TaskStatus
-
-from .scheduler import Scheduler
+from scheduler.schedulers import Scheduler
+from scheduler.schedulers.queue import PriorityQueue, QueueFullError
+from scheduler.schedulers.rankers import NormalizerRanker
tracer = trace.get_tracer(__name__)
@@ -33,13 +33,13 @@ def __init__(
ctx: context.AppContext,
scheduler_id: str,
organisation: Organisation,
- queue: queues.PriorityQueue | None = None,
+ queue: PriorityQueue | None = None,
callback: Callable[..., None] | None = None,
):
self.logger: structlog.BoundLogger = structlog.getLogger(__name__)
self.organisation: Organisation = organisation
- self.queue = queue or queues.PriorityQueue(
+ self.queue = queue or PriorityQueue(
pq_id=scheduler_id,
maxsize=ctx.config.pq_maxsize,
item_type=self.ITEM_TYPE,
@@ -56,7 +56,7 @@ def __init__(
auto_calculate_deadline=False,
)
- self.ranker = rankers.NormalizerRanker(ctx=self.ctx)
+ self.ranker = NormalizerRanker(ctx=self.ctx)
def run(self) -> None:
"""The run method is called when the scheduler is started. It will
@@ -68,7 +68,7 @@ def run(self) -> None:
for each normalizer that is registered for the mime type of the raw
file.
"""
- listener = listeners.RawData(
+ listener = clients.RawData(
dsn=str(self.ctx.config.host_raw_data),
queue=f"{self.organisation.id}__raw_file_received",
func=self.push_tasks_for_received_raw_data,
@@ -255,7 +255,7 @@ def push_normalizer_task(self, normalizer_task: models.NormalizerTask, caller: s
try:
self.push_item_to_queue_with_timeout(task, self.max_tries)
- except queues.QueueFullError:
+ except QueueFullError:
self.logger.warning(
"Could not add task to queue, queue was full: %s",
task.id,
diff --git a/mula/scheduler/schedulers/report.py b/mula/scheduler/schedulers/schedulers/report.py
similarity index 94%
rename from mula/scheduler/schedulers/report.py
rename to mula/scheduler/schedulers/schedulers/report.py
index 833bbed3008..099c21642d9 100644
--- a/mula/scheduler/schedulers/report.py
+++ b/mula/scheduler/schedulers/schedulers/report.py
@@ -6,12 +6,12 @@
import structlog
from opentelemetry import trace
-from scheduler import context, queues, storage
+from scheduler import context, storage
from scheduler.models import Organisation, ReportTask, Task
+from scheduler.schedulers import Scheduler
+from scheduler.schedulers.queue import PriorityQueue, QueueFullError
from scheduler.storage import filters
-from .scheduler import Scheduler
-
tracer = trace.get_tracer(__name__)
@@ -23,12 +23,12 @@ def __init__(
ctx: context.AppContext,
scheduler_id: str,
organisation: Organisation,
- queue: queues.PriorityQueue | None = None,
+ queue: PriorityQueue | None = None,
callback: Callable[..., None] | None = None,
):
self.logger: structlog.BoundLogger = structlog.get_logger(__name__)
self.organisation = organisation
- self.queue = queue or queues.PriorityQueue(
+ self.queue = queue or PriorityQueue(
pq_id=scheduler_id,
maxsize=ctx.config.pq_maxsize,
item_type=self.ITEM_TYPE,
@@ -118,7 +118,7 @@ def push_report_task(self, report_task: ReportTask, caller: str = "") -> None:
try:
self.push_item_to_queue_with_timeout(task, self.max_tries)
- except queues.QueueFullError:
+ except QueueFullError:
self.logger.warning(
"Could not add task %s to queue, queue was full",
report_task.hash,
diff --git a/mula/scheduler/server/handlers/queues.py b/mula/scheduler/server/handlers/queues.py
index 6507a15a2cc..461c897c5e9 100644
--- a/mula/scheduler/server/handlers/queues.py
+++ b/mula/scheduler/server/handlers/queues.py
@@ -4,7 +4,8 @@
import structlog
from fastapi import status
-from scheduler import context, models, queues, schedulers, storage
+from scheduler import context, models, schedulers, storage
+from scheduler.schedulers.queue import NotAllowedError, QueueEmptyError, QueueFullError
from scheduler.server import serializers
from scheduler.server.errors import BadRequestError, ConflictError, NotFoundError, TooManyRequestsError
@@ -70,7 +71,7 @@ def pop(self, queue_id: str, filters: storage.filters.FilterRequest | None = Non
try:
item = s.pop_item_from_queue(filters)
- except queues.QueueEmptyError:
+ except QueueEmptyError:
return None
if item is None:
@@ -94,9 +95,9 @@ def push(self, queue_id: str, item_in: serializers.Task) -> Any:
pushed_item = s.push_item_to_queue(new_item)
except ValueError:
raise BadRequestError("malformed item")
- except queues.QueueFullError:
+ except QueueFullError:
raise TooManyRequestsError("queue is full")
- except queues.errors.NotAllowedError:
+ except NotAllowedError:
raise ConflictError("queue is not allowed to push items")
return pushed_item
diff --git a/mula/scheduler/storage/__init__.py b/mula/scheduler/storage/__init__.py
index 7ef0497775c..2891e0f29d3 100644
--- a/mula/scheduler/storage/__init__.py
+++ b/mula/scheduler/storage/__init__.py
@@ -1,6 +1,3 @@
+from .connection import DBConn
from .filters import apply_filter
-from .pq_store import PriorityQueueStore
-from .schedule_store import ScheduleStore
-from .storage import DBConn
-from .task_store import TaskStore
from .utils import retry
diff --git a/mula/scheduler/storage/connection.py b/mula/scheduler/storage/connection.py
new file mode 100644
index 00000000000..dc381191528
--- /dev/null
+++ b/mula/scheduler/storage/connection.py
@@ -0,0 +1,51 @@
+import json
+from functools import partial
+
+import sqlalchemy
+import structlog
+
+from scheduler.config import settings
+from scheduler.storage.errors import StorageError
+
+
+class DBConn:
+ def __init__(self, dsn: str, pool_size: int = 25):
+ self.logger: structlog.BoundLogger = structlog.get_logger(__name__)
+
+ self.dsn = dsn
+ self.pool_size = pool_size
+
+ def connect(self) -> None:
+ db_uri_redacted = sqlalchemy.engine.make_url(name_or_url=self.dsn).render_as_string(hide_password=True)
+
+ pool_size = settings.Settings().db_connection_pool_size
+
+ self.logger.debug(
+ "Connecting to database %s with pool size %s...",
+ self.dsn,
+ pool_size,
+ dsn=db_uri_redacted,
+ pool_size=pool_size,
+ )
+
+ try:
+ serializer = partial(json.dumps, default=str)
+ self.engine = sqlalchemy.create_engine(
+ self.dsn,
+ pool_pre_ping=True,
+ pool_size=pool_size,
+ pool_recycle=300,
+ json_serializer=serializer,
+ connect_args={"options": "-c timezone=utc"},
+ )
+ except sqlalchemy.exc.SQLAlchemyError as e:
+ self.logger.error("Failed to connect to database %s: %s", self.dsn, e, dsn=db_uri_redacted)
+ raise StorageError("Failed to connect to database.")
+
+ self.logger.debug("Connected to database %s.", db_uri_redacted, dsn=db_uri_redacted)
+
+ try:
+ self.session = sqlalchemy.orm.sessionmaker(bind=self.engine)
+ except sqlalchemy.exc.SQLAlchemyError as e:
+ self.logger.error("Failed to create session: %s", e)
+ raise StorageError("Failed to create session.")
diff --git a/mula/scheduler/alembic/versions/__init__.py b/mula/scheduler/storage/migrations/__init__.py
similarity index 100%
rename from mula/scheduler/alembic/versions/__init__.py
rename to mula/scheduler/storage/migrations/__init__.py
diff --git a/mula/scheduler/alembic.ini b/mula/scheduler/storage/migrations/alembic.ini
similarity index 98%
rename from mula/scheduler/alembic.ini
rename to mula/scheduler/storage/migrations/alembic.ini
index 76c3ea8eab2..13a39bc3f11 100644
--- a/mula/scheduler/alembic.ini
+++ b/mula/scheduler/storage/migrations/alembic.ini
@@ -2,7 +2,7 @@
[alembic]
# path to migration scripts
-script_location = scheduler/alembic
+script_location = scheduler/storage/migrations
# template used to generate migration files
file_template = %%(rev)s_%%(slug)s
diff --git a/mula/scheduler/alembic/env.py b/mula/scheduler/storage/migrations/env.py
similarity index 100%
rename from mula/scheduler/alembic/env.py
rename to mula/scheduler/storage/migrations/env.py
diff --git a/mula/scheduler/alembic/script.py.mako b/mula/scheduler/storage/migrations/script.py.mako
similarity index 100%
rename from mula/scheduler/alembic/script.py.mako
rename to mula/scheduler/storage/migrations/script.py.mako
diff --git a/mula/scheduler/alembic/versions/0001_initial_migration.py b/mula/scheduler/storage/migrations/versions/0001_initial_migration.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0001_initial_migration.py
rename to mula/scheduler/storage/migrations/versions/0001_initial_migration.py
diff --git a/mula/scheduler/alembic/versions/0002_update_tasks.py b/mula/scheduler/storage/migrations/versions/0002_update_tasks.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0002_update_tasks.py
rename to mula/scheduler/storage/migrations/versions/0002_update_tasks.py
diff --git a/mula/scheduler/alembic/versions/0003_add_type_field_to_tasks.py b/mula/scheduler/storage/migrations/versions/0003_add_type_field_to_tasks.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0003_add_type_field_to_tasks.py
rename to mula/scheduler/storage/migrations/versions/0003_add_type_field_to_tasks.py
diff --git a/mula/scheduler/alembic/versions/0004_add_server_default.py b/mula/scheduler/storage/migrations/versions/0004_add_server_default.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0004_add_server_default.py
rename to mula/scheduler/storage/migrations/versions/0004_add_server_default.py
diff --git a/mula/scheduler/alembic/versions/0005_size_limit_hash.py b/mula/scheduler/storage/migrations/versions/0005_size_limit_hash.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0005_size_limit_hash.py
rename to mula/scheduler/storage/migrations/versions/0005_size_limit_hash.py
diff --git a/mula/scheduler/alembic/versions/0006_add_jsonb_fields_add_jsonb_fields.py b/mula/scheduler/storage/migrations/versions/0006_add_jsonb_fields_add_jsonb_fields.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0006_add_jsonb_fields_add_jsonb_fields.py
rename to mula/scheduler/storage/migrations/versions/0006_add_jsonb_fields_add_jsonb_fields.py
diff --git a/mula/scheduler/alembic/versions/0007_add_cancelled_status_for_tasks.py b/mula/scheduler/storage/migrations/versions/0007_add_cancelled_status_for_tasks.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0007_add_cancelled_status_for_tasks.py
rename to mula/scheduler/storage/migrations/versions/0007_add_cancelled_status_for_tasks.py
diff --git a/mula/scheduler/alembic/versions/0008_add_task_schedule.py b/mula/scheduler/storage/migrations/versions/0008_add_task_schedule.py
similarity index 100%
rename from mula/scheduler/alembic/versions/0008_add_task_schedule.py
rename to mula/scheduler/storage/migrations/versions/0008_add_task_schedule.py
diff --git a/mula/scheduler/connectors/__init__.py b/mula/scheduler/storage/migrations/versions/__init__.py
similarity index 100%
rename from mula/scheduler/connectors/__init__.py
rename to mula/scheduler/storage/migrations/versions/__init__.py
diff --git a/mula/scheduler/storage/stores/__init__.py b/mula/scheduler/storage/stores/__init__.py
new file mode 100644
index 00000000000..244e81eb087
--- /dev/null
+++ b/mula/scheduler/storage/stores/__init__.py
@@ -0,0 +1,3 @@
+from .pq import PriorityQueueStore
+from .schedule import ScheduleStore
+from .task import TaskStore
diff --git a/mula/scheduler/storage/pq_store.py b/mula/scheduler/storage/stores/pq.py
similarity index 97%
rename from mula/scheduler/storage/pq_store.py
rename to mula/scheduler/storage/stores/pq.py
index 9e67997f072..feb62bd01c7 100644
--- a/mula/scheduler/storage/pq_store.py
+++ b/mula/scheduler/storage/stores/pq.py
@@ -1,11 +1,10 @@
from uuid import UUID
from scheduler import models
-
-from .errors import exception_handler
-from .filters import FilterRequest, apply_filter
-from .storage import DBConn
-from .utils import retry
+from scheduler.storage import DBConn
+from scheduler.storage.errors import exception_handler
+from scheduler.storage.filters import FilterRequest, apply_filter
+from scheduler.storage.utils import retry
class PriorityQueueStore:
diff --git a/mula/scheduler/storage/schedule_store.py b/mula/scheduler/storage/stores/schedule.py
similarity index 93%
rename from mula/scheduler/storage/schedule_store.py
rename to mula/scheduler/storage/stores/schedule.py
index d26c10d5f5e..a91b680d03b 100644
--- a/mula/scheduler/storage/schedule_store.py
+++ b/mula/scheduler/storage/stores/schedule.py
@@ -3,11 +3,10 @@
from sqlalchemy import exc
from scheduler import models
-
-from .errors import StorageError, exception_handler
-from .filters import FilterRequest, apply_filter
-from .storage import DBConn
-from .utils import retry
+from scheduler.storage import DBConn
+from scheduler.storage.errors import StorageError, exception_handler
+from scheduler.storage.filters import FilterRequest, apply_filter
+from scheduler.storage.utils import retry
class ScheduleStore:
@@ -22,7 +21,7 @@ def get_schedules(
self,
scheduler_id: str | None = None,
schedule_hash: str | None = None,
- enabled: bool | None = None,
+ enabled: bool | None = True, # FIXME: None?
min_deadline_at: datetime | None = None,
max_deadline_at: datetime | None = None,
min_created_at: datetime | None = None,
diff --git a/mula/scheduler/storage/task_store.py b/mula/scheduler/storage/stores/task.py
similarity index 91%
rename from mula/scheduler/storage/task_store.py
rename to mula/scheduler/storage/stores/task.py
index 266b6764e8e..437e10ca538 100644
--- a/mula/scheduler/storage/task_store.py
+++ b/mula/scheduler/storage/stores/task.py
@@ -3,11 +3,10 @@
from sqlalchemy import exc, func
from scheduler import models
-
-from .errors import StorageError, exception_handler
-from .filters import FilterRequest, apply_filter
-from .storage import DBConn
-from .utils import retry
+from scheduler.storage import DBConn
+from scheduler.storage.errors import StorageError, exception_handler
+from scheduler.storage.filters import FilterRequest, apply_filter
+from scheduler.storage.utils import retry
class TaskStore:
@@ -74,14 +73,14 @@ def get_task(self, task_id: str) -> models.Task | None:
@retry()
@exception_handler
- def get_tasks_by_hash(self, task_hash: str) -> list[models.Task] | None:
+ def get_tasks_by_hash(self, task_hash: str, limit: int | None = None) -> list[models.Task] | None:
with self.dbconn.session.begin() as session:
- tasks_orm = (
- session.query(models.TaskDB)
- .filter(models.TaskDB.hash == task_hash)
- .order_by(models.TaskDB.created_at.desc())
- .all()
- )
+ query = session.query(models.TaskDB).filter(models.TaskDB.hash == task_hash)
+
+ if limit is not None:
+ query = query.limit(limit)
+
+ tasks_orm = query.order_by(models.TaskDB.created_at.desc()).all()
if tasks_orm is None:
return None
diff --git a/mula/tests/integration/test_api.py b/mula/tests/integration/test_api.py
index a487f765dba..6eaa82086c2 100644
--- a/mula/tests/integration/test_api.py
+++ b/mula/tests/integration/test_api.py
@@ -9,6 +9,7 @@
from fastapi.testclient import TestClient
from scheduler import config, models, server, storage, utils
from scheduler.server import serializers
+from scheduler.storage import stores
from tests.factories import OrganisationFactory
from tests.mocks import queue as mock_queue
@@ -31,9 +32,9 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
}
)
diff --git a/mula/tests/integration/test_app.py b/mula/tests/integration/test_app.py
index 99e79009efb..b75f0576883 100644
--- a/mula/tests/integration/test_app.py
+++ b/mula/tests/integration/test_app.py
@@ -5,6 +5,7 @@
import scheduler
from scheduler import config, models, server, storage
+from scheduler.storage import stores
from tests.factories import OrganisationFactory
from tests.mocks import MockKatalogusService
@@ -25,8 +26,8 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
}
)
diff --git a/mula/tests/integration/test_boefje_scheduler.py b/mula/tests/integration/test_boefje_scheduler.py
index 9b9986f8415..19abaeb555b 100644
--- a/mula/tests/integration/test_boefje_scheduler.py
+++ b/mula/tests/integration/test_boefje_scheduler.py
@@ -3,7 +3,8 @@
from types import SimpleNamespace
from unittest import mock
-from scheduler import config, connectors, models, schedulers, storage
+from scheduler import clients, config, models, schedulers, storage
+from scheduler.storage import stores
from structlog.testing import capture_logs
from tests.factories import (
@@ -24,21 +25,19 @@ def setUp(self):
self.mock_ctx.config = config.settings.Settings()
# Mock connectors: octopoes
- self.mock_octopoes = mock.create_autospec(spec=connectors.services.Octopoes, spec_set=True)
+ self.mock_octopoes = mock.create_autospec(spec=clients.Octopoes, spec_set=True)
self.mock_ctx.services.octopoes = self.mock_octopoes
# Mock connectors: Scan profile mutation
- self.mock_scan_profile_mutation = mock.create_autospec(
- spec=connectors.listeners.ScanProfileMutation, spec_set=True
- )
+ self.mock_scan_profile_mutation = mock.create_autospec(spec=clients.ScanProfileMutation, spec_set=True)
self.mock_ctx.services.scan_profile_mutation = self.mock_scan_profile_mutation
# Mock connectors: Katalogus
- self.mock_katalogus = mock.create_autospec(spec=connectors.services.Katalogus, spec_set=True)
+ self.mock_katalogus = mock.create_autospec(spec=clients.Katalogus, spec_set=True)
self.mock_ctx.services.katalogus = self.mock_katalogus
# Mock connectors: Bytes
- self.mock_bytes = mock.create_autospec(spec=connectors.services.Bytes, spec_set=True)
+ self.mock_bytes = mock.create_autospec(spec=clients.Bytes, spec_set=True)
self.mock_ctx.services.bytes = self.mock_bytes
# Database
@@ -49,9 +48,9 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
}
)
@@ -1333,8 +1332,8 @@ def test_push_tasks_for_new_boefjes_request_exception(self):
# Mocks
self.mock_get_objects_by_object_types.side_effect = [
- connectors.errors.ExternalServiceError("External service is not available."),
- connectors.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
]
self.mock_get_new_boefjes_by_org_id.return_value = [boefje]
@@ -1414,8 +1413,8 @@ def test_push_tasks_for_new_boefjes_get_objects_request_exception(self):
# Mocks
self.mock_get_objects_by_object_types.side_effect = [
- connectors.errors.ExternalServiceError("External service is not available."),
- connectors.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
]
self.mock_get_new_boefjes_by_org_id.return_value = [boefje]
diff --git a/mula/tests/integration/test_services.py b/mula/tests/integration/test_clients.py
similarity index 91%
rename from mula/tests/integration/test_services.py
rename to mula/tests/integration/test_clients.py
index 460d5f6b115..3012dfad972 100644
--- a/mula/tests/integration/test_services.py
+++ b/mula/tests/integration/test_clients.py
@@ -3,8 +3,7 @@
import unittest
from unittest import mock
-from scheduler import config, models, storage
-from scheduler.connectors import services
+from scheduler import clients, config, models, storage
from scheduler.utils import remove_trailing_slash
from tests.factories import PluginFactory
@@ -13,7 +12,7 @@
class BytesTestCase(unittest.TestCase):
def setUp(self) -> None:
self.config = config.settings.Settings()
- self.service_bytes = services.Bytes(
+ self.service_bytes = clients.Bytes(
host=remove_trailing_slash(str(self.config.host_bytes)),
user=self.config.host_bytes_user,
password=self.config.host_bytes_password,
@@ -48,7 +47,7 @@ def setUp(self) -> None:
self.dbconn = storage.DBConn(str(self.config.db_uri))
self.dbconn.connect()
- self.service_katalogus = services.Katalogus(
+ self.service_katalogus = clients.Katalogus(
host=remove_trailing_slash(str(self.config.host_katalogus)),
source="scheduler_test",
timeout=self.config.katalogus_request_timeout,
@@ -61,7 +60,7 @@ def tearDown(self) -> None:
self.service_katalogus.boefje_cache.reset()
self.service_katalogus.normalizer_cache.reset()
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_flush_plugin_cache(self, mock_get_organisations):
# Mock
mock_get_organisations.return_value = [
@@ -75,7 +74,7 @@ def test_flush_plugin_cache(self, mock_get_organisations):
# Assert
self.assertCountEqual(self.service_katalogus.plugin_cache.cache.keys(), ("org-1", "org-2"))
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_flush_plugin_cache_empty(self, mock_get_organisations):
# Mock
mock_get_organisations.return_value = []
@@ -86,8 +85,8 @@ def test_flush_plugin_cache_empty(self, mock_get_organisations):
# Assert
self.assertDictEqual(self.service_katalogus.plugin_cache.cache, {})
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_flush_boefje_cache(self, mock_get_organisations, mock_get_plugins_by_organisation):
# Mock
mock_get_organisations.return_value = [
@@ -114,8 +113,8 @@ def test_flush_boefje_cache(self, mock_get_organisations, mock_get_plugins_by_or
self.assertIsNotNone(self.service_katalogus.boefje_cache.get("org-2").get("Hostname"))
self.assertEqual(len(self.service_katalogus.boefje_cache.get("org-2").get("Hostname")), 2)
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_flush_normalizer_cache(self, mock_get_organisations, mock_get_plugins_by_organisation):
# Mock
mock_get_organisations.return_value = [
@@ -142,7 +141,7 @@ def test_flush_normalizer_cache(self, mock_get_organisations, mock_get_plugins_b
self.assertIsNotNone(self.service_katalogus.normalizer_cache.get("org-2").get("Hostname"))
self.assertEqual(len(self.service_katalogus.normalizer_cache.get("org-2").get("Hostname")), 2)
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
def test_get_new_boefjes_by_org_id(self, mock_get_plugins_by_organisation):
# Mock
mock_get_plugins_by_organisation.side_effect = [
@@ -197,8 +196,8 @@ def test_get_new_boefjes_by_org_id(self, mock_get_plugins_by_organisation):
self.assertEqual(len(new_boefjes), 1)
self.assertEqual(new_boefjes[0].id, "plugin-5")
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_plugin_cache_thread_safety(self, mock_get_organisations, mock_get_plugins_by_organisation):
# Mock
mock_get_organisations.return_value = [models.Organisation(id="org-1", name="org-1")]
@@ -241,8 +240,8 @@ def write_to_cache(event):
self.assertEqual(len(self.service_katalogus.plugin_cache.get("org-1")), 3)
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_boefje_cache_thread_safety(self, mock_get_organisations, mock_get_plugins_by_organisation):
# Mock
mock_get_organisations.return_value = [models.Organisation(id="org-1", name="org-1")]
@@ -287,8 +286,8 @@ def write_to_cache(event):
self.assertEqual(len(self.service_katalogus.boefje_cache.get("org-1").get("Hostname")), 2)
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
- @mock.patch("scheduler.connectors.services.Katalogus.get_organisations")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_organisations")
def test_normalizer_cache_thread_safety(self, mock_get_organisations, mock_get_plugins_by_organisation):
# Mock
mock_get_organisations.return_value = [models.Organisation(id="org-1", name="org-1")]
@@ -331,7 +330,7 @@ def write_to_cache(event):
self.assertEqual(len(self.service_katalogus.normalizer_cache.get("org-1").get("Hostname")), 2)
- @mock.patch("scheduler.connectors.services.Katalogus.get_plugins_by_organisation")
+ @mock.patch("scheduler.clients.http.external.katalogus.Katalogus.get_plugins_by_organisation")
def test_new_boefjes_cache_thread_safety(self, mock_get_plugins_by_organisation):
mock_get_plugins_by_organisation.side_effect = [
[
diff --git a/mula/tests/integration/test_listeners.py b/mula/tests/integration/test_listeners.py
index 5c316d590e1..fd56a43cf78 100644
--- a/mula/tests/integration/test_listeners.py
+++ b/mula/tests/integration/test_listeners.py
@@ -4,7 +4,7 @@
from unittest import mock
import pika
-from scheduler import connectors, utils
+from scheduler import clients, utils
from tests.mocks import listener
@@ -13,7 +13,7 @@ class RabbitMQTestCase(unittest.TestCase):
DSN = "amqp://guest:guest@ci_rabbitmq:5672/%2Fkat"
def setUp(self):
- self.listeners: list[connectors.listeners.Listener] = []
+ self.listeners: list[clients.listeners.Listener] = []
threading.excepthook = self.unhandled_exception
diff --git a/mula/tests/integration/test_normalizer_scheduler.py b/mula/tests/integration/test_normalizer_scheduler.py
index 78a25287d28..493b4bd3f54 100644
--- a/mula/tests/integration/test_normalizer_scheduler.py
+++ b/mula/tests/integration/test_normalizer_scheduler.py
@@ -3,7 +3,8 @@
from types import SimpleNamespace
from unittest import mock
-from scheduler import config, connectors, models, schedulers, storage
+from scheduler import clients, config, models, schedulers, storage
+from scheduler.storage import stores
from structlog.testing import capture_logs
from tests.factories import (
@@ -33,9 +34,9 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
}
)
@@ -160,8 +161,8 @@ def test_get_normalizers_for_mime_type(self, mock_get_normalizers_by_org_id_and_
def test_get_normalizers_for_mime_type_request_exception(self, mock_get_normalizers_by_org_id_and_type):
# Mocks
mock_get_normalizers_by_org_id_and_type.side_effect = [
- connectors.errors.ExternalServiceError("External service is not available."),
- connectors.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
+ clients.errors.ExternalServiceError("External service is not available."),
]
# Act
diff --git a/mula/tests/integration/test_pq_store.py b/mula/tests/integration/test_pq_store.py
index 6ebefce88ce..0ace0867758 100644
--- a/mula/tests/integration/test_pq_store.py
+++ b/mula/tests/integration/test_pq_store.py
@@ -4,6 +4,7 @@
from unittest import mock
from scheduler import config, models, storage
+from scheduler.storage import stores
from tests.factories import OrganisationFactory
from tests.utils import functions
@@ -23,8 +24,8 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
}
)
diff --git a/mula/tests/integration/test_report_scheduler.py b/mula/tests/integration/test_report_scheduler.py
index d60a25dd502..ee35f7ab25a 100644
--- a/mula/tests/integration/test_report_scheduler.py
+++ b/mula/tests/integration/test_report_scheduler.py
@@ -3,6 +3,7 @@
from unittest import mock
from scheduler import config, models, schedulers, storage
+from scheduler.storage import stores
from tests.factories import OrganisationFactory
@@ -21,9 +22,9 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
}
)
diff --git a/mula/tests/integration/test_schedule_store.py b/mula/tests/integration/test_schedule_store.py
index 369af4c6101..df957b82171 100644
--- a/mula/tests/integration/test_schedule_store.py
+++ b/mula/tests/integration/test_schedule_store.py
@@ -4,7 +4,7 @@
from unittest import mock
from scheduler import config, models, storage
-from scheduler.storage import filters
+from scheduler.storage import filters, stores
from tests.utils import functions
@@ -23,8 +23,8 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
}
)
diff --git a/mula/tests/integration/test_scheduler.py b/mula/tests/integration/test_scheduler.py
index 095b74d63a1..7483f5b9880 100644
--- a/mula/tests/integration/test_scheduler.py
+++ b/mula/tests/integration/test_scheduler.py
@@ -4,7 +4,9 @@
from types import SimpleNamespace
from unittest import mock
-from scheduler import config, models, queues, storage
+from scheduler import config, models, storage
+from scheduler.schedulers.queue import InvalidItemError, NotAllowedError, QueueEmptyError, QueueFullError
+from scheduler.storage import stores
from structlog.testing import capture_logs
from tests.mocks import item as mock_item
@@ -27,9 +29,9 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.ScheduleStore.name: storage.ScheduleStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.ScheduleStore.name: stores.ScheduleStore(self.dbconn),
}
)
@@ -138,7 +140,7 @@ def test_push_item_to_queue_full(self):
# Assert
self.assertEqual(1, self.scheduler.queue.qsize())
- with self.assertRaises(queues.errors.QueueFullError):
+ with self.assertRaises(QueueFullError):
self.scheduler.push_item_to_queue_with_timeout(item=item, max_tries=1)
self.assertEqual(1, self.scheduler.queue.qsize())
@@ -149,7 +151,7 @@ def test_push_item_to_queue_invalid(self):
item.data = {"invalid": "data"}
# Assert
- with self.assertRaises(queues.errors.InvalidItemError):
+ with self.assertRaises(InvalidItemError):
self.scheduler.push_item_to_queue(item)
def test_pop_item_from_queue(self):
@@ -167,7 +169,7 @@ def test_pop_item_from_queue(self):
def test_pop_item_from_queue_empty(self):
self.assertEqual(0, self.scheduler.queue.qsize())
- with self.assertRaises(queues.errors.QueueEmptyError):
+ with self.assertRaises(QueueEmptyError):
self.scheduler.pop_item_from_queue()
def test_post_push(self):
@@ -387,7 +389,7 @@ def test_disable_scheduler(self):
# Scheduler should be disabled
self.assertFalse(self.scheduler.is_enabled())
- with self.assertRaises(queues.errors.NotAllowedError):
+ with self.assertRaises(NotAllowedError):
self.scheduler.push_item_to_queue(item)
def test_enable_scheduler(self):
diff --git a/mula/tests/integration/test_task_store.py b/mula/tests/integration/test_task_store.py
index 7a733aba6a3..c672fc78557 100644
--- a/mula/tests/integration/test_task_store.py
+++ b/mula/tests/integration/test_task_store.py
@@ -4,6 +4,7 @@
from unittest import mock
from scheduler import config, models, storage
+from scheduler.storage import stores
from tests.factories import OrganisationFactory
from tests.utils import functions
@@ -23,8 +24,8 @@ def setUp(self):
self.mock_ctx.datastores = SimpleNamespace(
**{
- storage.PriorityQueueStore.name: storage.PriorityQueueStore(self.dbconn),
- storage.TaskStore.name: storage.TaskStore(self.dbconn),
+ stores.PriorityQueueStore.name: stores.PriorityQueueStore(self.dbconn),
+ stores.TaskStore.name: stores.TaskStore(self.dbconn),
}
)
diff --git a/mula/tests/mocks/listener.py b/mula/tests/mocks/listener.py
index f69bbb01cce..a69942c665f 100644
--- a/mula/tests/mocks/listener.py
+++ b/mula/tests/mocks/listener.py
@@ -1,6 +1,6 @@
import time
-from scheduler.connectors import listeners
+from scheduler.clients.amqp import listeners
class MockListener(listeners.Listener):
diff --git a/mula/tests/mocks/queue.py b/mula/tests/mocks/queue.py
index 426ae5a46b9..a7c50cc3acf 100644
--- a/mula/tests/mocks/queue.py
+++ b/mula/tests/mocks/queue.py
@@ -1,7 +1,8 @@
-from scheduler import models, queues
+from scheduler import models
+from scheduler.schedulers.queue import PriorityQueue
from scheduler.utils import dict_utils
-class MockPriorityQueue(queues.PriorityQueue):
+class MockPriorityQueue(PriorityQueue):
def create_hash(self, p_item: models.Task) -> str:
return dict_utils.deep_get(p_item.model_dump(), ["data", "id"])
diff --git a/mula/tests/unit/test_queue.py b/mula/tests/unit/test_queue.py
index a4aa478c541..2861d442257 100644
--- a/mula/tests/unit/test_queue.py
+++ b/mula/tests/unit/test_queue.py
@@ -6,7 +6,9 @@
import uuid
from unittest import mock
-from scheduler import config, models, queues, storage
+from scheduler import config, models, storage
+from scheduler.schedulers.queue import InvalidItemError, ItemNotFoundError, NotAllowedError, QueueEmptyError
+from scheduler.storage import stores
from tests.mocks import queue as mock_queue
from tests.utils import functions
@@ -22,7 +24,7 @@ def setUp(self) -> None:
models.Base.metadata.drop_all(self.dbconn.engine)
models.Base.metadata.create_all(self.dbconn.engine)
- self.pq_store = storage.PriorityQueueStore(self.dbconn)
+ self.pq_store = stores.PriorityQueueStore(self.dbconn)
# Priority Queue
self.pq = mock_queue.MockPriorityQueue(
@@ -50,7 +52,7 @@ def test_push(self):
self.assertEqual(1, self.pq.qsize())
- @mock.patch("scheduler.storage.PriorityQueueStore.push")
+ @mock.patch("scheduler.storage.stores.PriorityQueueStore.push")
def test_push_item_not_found_in_db(self, mock_push):
"""When adding an item to the priority queue, but the item is not
found in the database, the item shouldn't be added.
@@ -59,7 +61,7 @@ def test_push_item_not_found_in_db(self, mock_push):
mock_push.return_value = None
- with self.assertRaises(queues.errors.ItemNotFoundError):
+ with self.assertRaises(ItemNotFoundError):
self.pq.push(item)
self.assertEqual(0, self.pq.qsize())
@@ -73,7 +75,7 @@ def test_push_incorrect_item_type(self):
"""
item = {"priority": 1, "data": functions.TestModel(id=uuid.uuid4().hex, name=uuid.uuid4().hex)}
- with self.assertRaises(queues.errors.InvalidItemError):
+ with self.assertRaises(InvalidItemError):
self.pq.push(item)
self.assertEqual(0, self.pq.qsize())
@@ -85,7 +87,7 @@ def test_push_invalid_item(self):
item = functions.create_item(scheduler_id=self.pq.pq_id, priority=1)
item.data = {"invalid": "data"}
- with self.assertRaises(queues.errors.InvalidItemError):
+ with self.assertRaises(InvalidItemError):
self.pq.push(item)
self.assertEqual(0, self.pq.qsize())
@@ -104,7 +106,7 @@ def test_push_replace_not_allowed(self):
self.assertEqual(1, self.pq.qsize())
# Add the same item again
- with self.assertRaises(queues.errors.NotAllowedError):
+ with self.assertRaises(NotAllowedError):
self.pq.push(initial_item)
self.assertEqual(1, self.pq.qsize())
@@ -146,7 +148,7 @@ def test_push_updates_not_allowed(self):
updated_item.data["name"] = "updated-name"
# Add the same item again
- with self.assertRaises(queues.errors.NotAllowedError):
+ with self.assertRaises(NotAllowedError):
self.pq.push(updated_item)
self.assertEqual(1, self.pq.qsize())
@@ -197,7 +199,7 @@ def test_push_priority_updates_not_allowed(self):
updated_item.priority = 100
# Add the same item again
- with self.assertRaises(queues.errors.NotAllowedError):
+ with self.assertRaises(NotAllowedError):
self.pq.push(updated_item)
self.assertEqual(1, self.pq.qsize())
@@ -474,7 +476,7 @@ def test_pop_queue_empty(self):
"""When popping an item from an empty queue, it should raise an
exception.
"""
- with self.assertRaises(queues.errors.QueueEmptyError):
+ with self.assertRaises(QueueEmptyError):
self.pq.pop()
def test_pop_highest_priority(self):
From b34de71fa3643cb4d4dcd3e360c12d0ff095b7d6 Mon Sep 17 00:00:00 2001
From: Roelof Korporaal
Date: Wed, 27 Nov 2024 16:03:53 +0100
Subject: [PATCH 11/44] Feature/improve rename bulk modal (#3885)
Co-authored-by: Jan Klopper
---
rocky/assets/js/reportActionForms.js | 2 +-
.../modal_partials/rename_modal.html | 11 +-
.../report_overview/report_history.html | 14 +-
.../report_overview/report_history_table.html | 313 +++++++++---------
4 files changed, 170 insertions(+), 170 deletions(-)
diff --git a/rocky/assets/js/reportActionForms.js b/rocky/assets/js/reportActionForms.js
index 3f2523cc5a4..42a5dbc5a65 100644
--- a/rocky/assets/js/reportActionForms.js
+++ b/rocky/assets/js/reportActionForms.js
@@ -7,7 +7,7 @@ export function renderRenameSelection(modal, selection) {
references.push(input_element.value);
});
- let table_element = document.getElementById("rename-table");
+ let table_element = document.getElementById("report-name-table");
let table_body = table_element.querySelector("tbody");
let table_row = table_element.querySelector("tr.rename-table-row");
diff --git a/rocky/reports/templates/report_overview/modal_partials/rename_modal.html b/rocky/reports/templates/report_overview/modal_partials/rename_modal.html
index 67cb6a6ef1a..13cfe6d8093 100644
--- a/rocky/reports/templates/report_overview/modal_partials/rename_modal.html
+++ b/rocky/reports/templates/report_overview/modal_partials/rename_modal.html
@@ -7,11 +7,11 @@
{% fill "content" %}