diff --git a/boefjes/boefjes/dependencies/plugins.py b/boefjes/boefjes/dependencies/plugins.py index 0cfb57d855b..20dc9b7dc65 100644 --- a/boefjes/boefjes/dependencies/plugins.py +++ b/boefjes/boefjes/dependencies/plugins.py @@ -16,8 +16,8 @@ from boefjes.sql.plugin_storage import create_plugin_storage from boefjes.storage.interfaces import ( ConfigStorage, - ExistingPluginId, - ExistingPluginName, + DuplicatePlugin, + IntegrityError, NotFound, PluginNotFound, PluginStorage, @@ -107,28 +107,40 @@ def upsert_settings(self, settings: dict, organisation_id: str, plugin_id: str): def create_boefje(self, boefje: Boefje) -> None: try: self.local_repo.by_id(boefje.id) - raise ExistingPluginId(boefje.id) + raise DuplicatePlugin("id") except KeyError: try: plugin = self.local_repo.by_name(boefje.name) if plugin.type == "boefje": - raise ExistingPluginName(boefje.name) + raise DuplicatePlugin("name") else: - self.plugin_storage.create_boefje(boefje) + try: + with self.plugin_storage as storage: + storage.create_boefje(boefje) + except IntegrityError as error: + raise DuplicatePlugin(self._translate_duplicate_plugin(error.message)) except KeyError: - self.plugin_storage.create_boefje(boefje) + try: + with self.plugin_storage as storage: + storage.create_boefje(boefje) + except IntegrityError as error: + raise DuplicatePlugin(self._translate_duplicate_plugin(error.message)) + + def _translate_duplicate_plugin(self, error_message): + translations = {"boefje_plugin_id": "id", "boefje_name": "name"} + return next((value for key, value in translations.items() if key in error_message), None) def create_normalizer(self, normalizer: Normalizer) -> None: try: self.local_repo.by_id(normalizer.id) - raise ExistingPluginId(normalizer.id) + raise DuplicatePlugin("id") except KeyError: try: plugin = self.local_repo.by_name(normalizer.name) if plugin.types == "normalizer": - raise ExistingPluginName(normalizer.name) + raise DuplicatePlugin("name") else: self.plugin_storage.create_normalizer(normalizer) except KeyError: diff --git a/boefjes/boefjes/katalogus/plugins.py b/boefjes/boefjes/katalogus/plugins.py index d197e90fdfb..87065119feb 100644 --- a/boefjes/boefjes/katalogus/plugins.py +++ b/boefjes/boefjes/katalogus/plugins.py @@ -1,6 +1,7 @@ import datetime from functools import partial +import structlog from croniter import croniter from fastapi import APIRouter, Body, Depends, HTTPException, status from fastapi.responses import FileResponse, JSONResponse, Response @@ -17,7 +18,7 @@ from boefjes.katalogus.organisations import check_organisation_exists from boefjes.models import FilterParameters, PaginationParameters, PluginType from boefjes.sql.plugin_storage import get_plugin_storage -from boefjes.storage.interfaces import PluginStorage +from boefjes.storage.interfaces import DuplicatePlugin, IntegrityError, NotAllowed, PluginStorage router = APIRouter( prefix="/organisations/{organisation_id}", @@ -25,6 +26,8 @@ dependencies=[Depends(check_organisation_exists)], ) +logger = structlog.get_logger(__name__) + # check if query matches plugin id, name or description def _plugin_matches_query(plugin: PluginType, query: str) -> bool: @@ -96,14 +99,17 @@ def get_plugin( @router.post("/plugins", status_code=status.HTTP_201_CREATED) def add_plugin(plugin: PluginType, plugin_service: PluginService = Depends(get_plugin_service)): - with plugin_service as service: - plugin.static = False # Creation through the API implies that these cannot be static + try: + with plugin_service as service: + plugin.static = False # Creation through the API implies that these cannot be static - if plugin.type == "boefje": - return service.create_boefje(plugin) + if plugin.type == "boefje": + return service.create_boefje(plugin) - if plugin.type == "normalizer": - return service.create_normalizer(plugin) + if plugin.type == "normalizer": + return service.create_normalizer(plugin) + except DuplicatePlugin as error: + raise HTTPException(status.HTTP_400_BAD_REQUEST, error.message) raise HTTPException(status.HTTP_400_BAD_REQUEST, "Creation of Bits is not supported") @@ -164,8 +170,15 @@ def update_boefje( boefje: BoefjeIn, storage: PluginStorage = Depends(get_plugin_storage), ): - with storage as p: - p.update_boefje(boefje_id, boefje.model_dump(exclude_unset=True)) + # todo: update boefje should be done in the plugin service + try: + with storage as p: + try: + p.update_boefje(boefje_id, boefje.model_dump(exclude_unset=True)) + except NotAllowed: + raise HTTPException(status.HTTP_403_FORBIDDEN, "Updating a static plugin is not allowed") + except IntegrityError as error: + raise HTTPException(status.HTTP_400_BAD_REQUEST, error.message) @router.delete("/boefjes/{boefje_id}", status_code=status.HTTP_204_NO_CONTENT) diff --git a/boefjes/boefjes/sql/db.py b/boefjes/boefjes/sql/db.py index 0f31709206b..97fa858b75b 100644 --- a/boefjes/boefjes/sql/db.py +++ b/boefjes/boefjes/sql/db.py @@ -43,7 +43,7 @@ def session_managed_iterator(service_factory: Callable[[Session], Any]) -> Itera try: yield service except Exception as error: - logger.exception("An error occurred: %s. Rolling back session", error) + logger.error("An error occurred: %s. Rolling back session", error) session.rollback() raise error finally: diff --git a/boefjes/boefjes/sql/session.py b/boefjes/boefjes/sql/session.py index e1725c8435c..a48f238d410 100644 --- a/boefjes/boefjes/sql/session.py +++ b/boefjes/boefjes/sql/session.py @@ -30,7 +30,7 @@ def __enter__(self) -> Self: def __exit__(self, exc_type: type[Exception], exc_value: str, exc_traceback: str) -> None: # noqa: F841 if exc_type is not None: - logger.error("An error occurred: %s. Rolling back session", exc_value, exc_info=True) + logger.error("An error occurred: %s. Rolling back session", exc_value) self.session.rollback() return @@ -45,5 +45,6 @@ def __exit__(self, exc_type: type[Exception], exc_value: str, exc_traceback: str except exc.DatabaseError as e: raise StorageError("A storage error occurred") from e finally: - logger.exception("Committing failed, rolling back") - self.session.rollback() + if exc_type is not None or self.session.is_active: + logger.debug("Committing failed, rolling back") + self.session.rollback() diff --git a/boefjes/boefjes/storage/interfaces.py b/boefjes/boefjes/storage/interfaces.py index 08ef95c1392..24a7d77f9df 100644 --- a/boefjes/boefjes/storage/interfaces.py +++ b/boefjes/boefjes/storage/interfaces.py @@ -55,14 +55,9 @@ def __init__(self, plugin_id: str): super().__init__(f"Plugin with id '{plugin_id}' is static, so updating it is not allowed") -class ExistingPluginId(NotAllowed): - def __init__(self, plugin_id: str): - super().__init__(f"Plugin id '{plugin_id}' is already used") - - -class ExistingPluginName(NotAllowed): - def __init__(self, plugin_name: str): - super().__init__(f"Plugin name '{plugin_name}' is already used") +class DuplicatePlugin(NotAllowed): + def __init__(self, key: str): + super().__init__(f"Duplicate plugin {key}") class OrganisationStorage(ABC): diff --git a/boefjes/tests/conftest.py b/boefjes/tests/conftest.py index 7fa5d11b4a4..ddd4d98ff4f 100644 --- a/boefjes/tests/conftest.py +++ b/boefjes/tests/conftest.py @@ -121,7 +121,6 @@ def handle(self, item: BoefjeMeta | NormalizerMeta): time.sleep(self.sleep_time) if str(item.id) == "9071c9fd-2b9f-440f-a524-ef1ca4824fd4": - time.sleep(0.1) raise self.exception() self.queue.put(item) diff --git a/boefjes/tests/integration/test_api.py b/boefjes/tests/integration/test_api.py index 59f50b0a61c..f889edfe259 100644 --- a/boefjes/tests/integration/test_api.py +++ b/boefjes/tests/integration/test_api.py @@ -45,12 +45,12 @@ def test_cannot_add_plugin_reserved_id(test_client, organisation): boefje = Boefje(id="dns-records", name="My test boefje", static=False) response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.model_dump_json()) assert response.status_code == 400 - assert response.json() == {"message": "Plugin id 'dns-records' is already used"} + assert response.json() == {"detail": "Duplicate plugin id"} normalizer = Normalizer(id="kat_nmap_normalize", name="My test normalizer") response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.model_dump_json()) assert response.status_code == 400 - assert response.json() == {"message": "Plugin id 'kat_nmap_normalize' is already used"} + assert response.json() == {"detail": "Duplicate plugin id"} def test_add_boefje(test_client, organisation): @@ -80,7 +80,7 @@ def test_cannot_add_static_plugin_with_duplicate_name(test_client, organisation) boefje = Boefje(id="test_plugin", name="DNS records", static=False) response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.model_dump_json()) assert response.status_code == 400 - assert response.json() == {"message": "Plugin name 'DNS records' is already used"} + assert response.json() == {"detail": "Duplicate plugin name"} def test_cannot_add_plugin_with_duplicate_name(test_client, organisation): @@ -91,10 +91,7 @@ def test_cannot_add_plugin_with_duplicate_name(test_client, organisation): boefje = Boefje(id="test_plugin_2", name="My test boefje", static=False) response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.model_dump_json()) assert response.status_code == 400 - assert response.json() == { - "message": 'duplicate key value violates unique constraint "unique_boefje_name"\n' - "DETAIL: Key (name)=(My test boefje) already exists.\n" - } + assert response.json() == {"detail": "Duplicate plugin name"} normalizer = Normalizer(id="test_normalizer", name="My test normalizer", static=False) response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=normalizer.model_dump_json()) @@ -238,7 +235,7 @@ def test_cannot_update_static_plugins(test_client, organisation): assert response.json()["enabled"] is True response = test_client.patch(f"/v1/organisations/{organisation.id}/boefjes/dns-records", json={"version": "v1.2"}) - assert response.status_code == 400 + assert response.status_code == 403 response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/dns-records") assert response.json()["version"] != "v1.2" diff --git a/boefjes/tests/test_app.py b/boefjes/tests/test_app.py index 12b8d470619..39e1412469b 100644 --- a/boefjes/tests/test_app.py +++ b/boefjes/tests/test_app.py @@ -95,6 +95,7 @@ def test_two_processes_handler_exception(manager: SchedulerWorkerManager, item_h # We expect the first two patches to set the task status to running of both task and then process 1 to finish, as # the exception has been set up with a small delay. + assert len(patched_tasks) == 6 assert sorted(patched_tasks[:3]) == sorted( [ ("70da7d4f-f41f-4940-901b-d98a92e9014b", "running"), # Process 1 diff --git a/rocky/katalogus/client.py b/rocky/katalogus/client.py index bac071be34b..51c60439f17 100644 --- a/rocky/katalogus/client.py +++ b/rocky/katalogus/client.py @@ -1,3 +1,4 @@ +import json from io import BytesIO import httpx @@ -68,19 +69,47 @@ def serialize_produces(self, produces: set[type[OOI]]): class KATalogusError(Exception): - message: str = _("The KATalogus has an unexpected error. Check the logs for further details.") + @property + def message(self): + return self._message + + def __init__(self, message: str | None = None): + if message is None: + message = _("The KATalogus has an unexpected error. Check the logs for further details.") + + self._message = message + + super().__init__(message) def __str__(self): - return str(self.message) + return self._message + + +class DuplicatePluginError(KATalogusError): + def __init__(self, error_message: str): + super().__init__(error_message) + + +class DuplicateNameError(KATalogusError): + def __init__(self): + super().__init__(_("Boefje with this name already exists.")) + + +class DuplicateIdError(KATalogusError): + def __init__(self): + super().__init__(_("Boefje with this ID already exists.")) + + +class KATalogusNotAllowedError(KATalogusError): + def __init__(self): + super().__init__(_("Editing this boefje is not allowed because it is static.")) class KATalogusHTTPStatusError(KATalogusError): - def __init__(self, *args: object, status_code: str | None = None) -> None: - super().__init__(*args) - status_message = "" - if status_code is not None: - status_message = f"{status_code}: " - self.message = status_message + _("A HTTP error occurred. Check logs for more info.") + def __init__(self, error: httpx.HTTPStatusError): + self.error = error + + super().__init__(_("An HTTP %d error occurred. Check logs for more info.").format(error.response.status_code)) class KATalogusClientV1: @@ -111,7 +140,7 @@ def get_plugins(self, **params) -> list[Plugin]: response = self.session.get(f"{self.organization_uri}/plugins", params=params) response.raise_for_status() except httpx.HTTPStatusError as error: - raise KATalogusHTTPStatusError(status_code=str(error.response.status_code)) + raise KATalogusHTTPStatusError(error) return [parse_plugin(plugin) for plugin in response.json()] def get_plugin(self, plugin_id: str) -> Plugin: @@ -210,29 +239,42 @@ def get_cover(self, boefje_id: str) -> BytesIO: return BytesIO(response.content) def create_plugin(self, plugin: Plugin) -> None: - response = self.session.post( - f"{self.organization_uri}/plugins", - headers={"Content-Type": "application/json"}, - content=plugin.model_dump_json(exclude_none=True), - ) - response.raise_for_status() - - if response.status_code == codes.CREATED: - logger.info("Plugin %s", plugin.name) - else: - logger.info("Plugin %s could not be created", plugin.name) + try: + response = self.session.post( + f"{self.organization_uri}/plugins", + headers={"Content-Type": "application/json"}, + content=plugin.model_dump_json(exclude_none=True), + ) + response.raise_for_status() + except httpx.HTTPStatusError as error: + if error.response.status_code == codes.CREATED: + logger.info("Plugin %s created", plugin.name) + else: + logger.info("Plugin %s could not be created", plugin.name) + error_message = json.loads(error.response.text).get("detail") + if error.response.status_code == codes.BAD_REQUEST and "Duplicate plugin" in error_message: + raise DuplicatePluginError(error_message) + else: + raise error def edit_plugin(self, plugin: Plugin) -> None: - response = self.session.patch( - f"{self.organization_uri}/boefjes/{plugin.id}", - content=plugin.model_dump_json(exclude_none=True), - ) - response.raise_for_status() - - if response.status_code == codes.CREATED: - logger.info("Plugin %s", plugin.name) - else: - logger.info("Plugin %s could not be created", plugin.name) + try: + response = self.session.patch( + f"{self.organization_uri}/boefjes/{plugin.id}", + content=plugin.model_dump_json(exclude_none=True), + ) + response.raise_for_status() + except httpx.HTTPStatusError as error: + if error.response.status_code == codes.CREATED: + logger.info("Plugin %s updated", plugin.name) + else: + logger.info("Plugin %s could not be updated", plugin.name) + if error.response.status_code == codes.BAD_REQUEST and "duplicate key" in error.response.text: + raise DuplicatePluginError("Duplicate plugin name") + if error.response.status_code in [codes.FORBIDDEN, codes.NOT_FOUND]: + raise KATalogusNotAllowedError + else: + raise error def parse_boefje(boefje: dict) -> Boefje: diff --git a/rocky/katalogus/views/boefje_setup.py b/rocky/katalogus/views/boefje_setup.py index aaa5c3842ee..3c4d686facf 100644 --- a/rocky/katalogus/views/boefje_setup.py +++ b/rocky/katalogus/views/boefje_setup.py @@ -3,12 +3,11 @@ from urllib.parse import urlencode from account.mixins import OrganizationPermissionRequiredMixin, OrganizationView -from django.shortcuts import redirect from django.urls import reverse from django.views.generic.edit import FormView -from tools.forms.boefje import BoefjeAddForm +from tools.forms.boefje import BoefjeSetupForm -from katalogus.client import Boefje, get_katalogus +from katalogus.client import Boefje, DuplicatePluginError, KATalogusNotAllowedError, get_katalogus from octopoes.models.types import type_by_name @@ -16,36 +15,41 @@ class BoefjeSetupView(OrganizationPermissionRequiredMixin, OrganizationView, For """Setup view for creating new Boefjes and variants""" template_name = "boefje_setup.html" - form_class = BoefjeAddForm + form_class = BoefjeSetupForm permission_required = "tools.can_add_boefje" - def form_valid(self, form): - """If the form is valid, redirect to the supplied URL.""" - form_data = form.cleaned_data - - plugin = create_boefje_with_form_data(form_data, self.plugin_id, str(datetime.now())) - - get_katalogus(self.organization.code).create_plugin(plugin) - query_params = urlencode({"new_variant": True}) + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.katalogus = get_katalogus(self.organization.code) + self.plugin_id = uuid.uuid4() + self.created = str(datetime.now()) + self.query_params = urlencode({"new_variant": True}) - return redirect( + def get_success_url(self) -> str: + return ( reverse( "boefje_detail", - kwargs={"organization_code": self.organization.code, "plugin_id": self.return_to_plugin_id}, + kwargs={"organization_code": self.organization.code, "plugin_id": self.plugin_id}, ) + "?" - + query_params + + self.query_params ) class AddBoefjeView(BoefjeSetupView): """View where the user can create a new Boefje""" - def setup(self, request, *args, **kwargs): - super().setup(request, *args, **kwargs) + def form_valid(self, form): + form_data = form.cleaned_data + plugin = create_boefje_with_form_data(form_data, self.plugin_id, self.created) - self.plugin_id = str(uuid.uuid4()) - self.return_to_plugin_id = self.plugin_id + try: + self.katalogus.create_plugin(plugin) + return super().form_valid(form) + except DuplicatePluginError as error: + if "name" in error.message: + form.add_error("name", ("Boefje with this name does already exist. Please choose another name.")) + return self.form_invalid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -67,10 +71,9 @@ class AddBoefjeVariantView(BoefjeSetupView): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - self.plugin_id = str(uuid.uuid4()) - self.return_to_plugin_id = self.kwargs.get("plugin_id") - katalogus = get_katalogus(self.organization.code) - self.plugin = katalogus.get_plugin(self.return_to_plugin_id) + self.based_on_plugin_id = self.kwargs.get("plugin_id") + + self.plugin = self.katalogus.get_plugin(self.based_on_plugin_id) def get_initial(self): initial = super().get_initial() @@ -90,24 +93,36 @@ def get_initial(self): return initial + def form_valid(self, form): + form_data = form.cleaned_data + plugin = create_boefje_with_form_data(form_data, self.plugin_id, self.created) + + try: + self.katalogus.create_plugin(plugin) + return super().form_valid(form) + except DuplicatePluginError as error: + if "name" in error.message: + form.add_error("name", ("Boefje with this name does already exist. Please choose another name.")) + return self.form_invalid(form) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["boefje_variant"] = True - context["return_to_plugin_id"] = self.return_to_plugin_id + context["return_to_plugin_id"] = self.based_on_plugin_id context["breadcrumbs"] = [ {"url": reverse("katalogus", kwargs={"organization_code": self.organization.code}), "text": "KAT-alogus"}, { "url": reverse( "boefje_detail", - kwargs={"organization_code": self.organization.code, "plugin_id": self.return_to_plugin_id}, + kwargs={"organization_code": self.organization.code, "plugin_id": self.based_on_plugin_id}, ), "text": "Boefje detail page", }, { "url": reverse( "boefje_variant_setup", - kwargs={"organization_code": self.organization.code, "plugin_id": self.return_to_plugin_id}, + kwargs={"organization_code": self.organization.code, "plugin_id": self.based_on_plugin_id}, ), "text": "Boefje variant setup", }, @@ -122,9 +137,10 @@ class EditBoefjeView(BoefjeSetupView): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - plugin_id = self.kwargs.get("plugin_id") - katalogus = get_katalogus(self.organization.code) - self.plugin = katalogus.get_plugin(plugin_id) + self.plugin_id = self.kwargs.get("plugin_id") + self.query_params = urlencode({"new_variant": False}) + self.plugin = self.katalogus.get_plugin(self.plugin_id) + self.created = self.plugin.created def get_initial(self): initial = super().get_initial() @@ -147,15 +163,25 @@ def get_initial(self): return initial def form_valid(self, form): - """If the form is valid, redirect to the supplied URL.""" form_data = form.cleaned_data - plugin = create_boefje_with_form_data(form_data, self.kwargs.get("plugin_id"), self.plugin.created) - - get_katalogus(self.organization.code).edit_plugin(plugin) - - return redirect( - reverse("boefje_detail", kwargs={"organization_code": self.organization.code, "plugin_id": plugin.id}) - ) + plugin = create_boefje_with_form_data(form_data, self.plugin_id, self.created) + + try: + self.katalogus.edit_plugin(plugin) + return super().form_valid(form) + except DuplicatePluginError as error: + if "name" in error.message: + form.add_error("name", ("Boefje with this name does already exist. Please choose another name.")) + return self.form_invalid(form) + except KATalogusNotAllowedError: + form.add_error( + "name", + ( + "Editing this Boefje is not allowed because it is static. " + "Please create a new variant of this static Boefje." + ), + ) + return self.form_invalid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -196,18 +222,18 @@ def create_boefje_with_form_data(form_data, plugin_id: str, created: str): arguments = [] if not form_data["oci_arguments"] else form_data["oci_arguments"].split() consumes = [] if not form_data["consumes"] else form_data["consumes"].strip("[]").replace("'", "").split(", ") produces = [] if not form_data["produces"] else form_data["produces"].split(",") - produces = [p.strip() for p in produces] + produces = {p.strip() for p in produces} interval = int(form_data.get("interval") or 0) or None - input_objects = [] + input_objects = set() for input_object in consumes: - input_objects.append(type_by_name(input_object)) + input_objects.add(type_by_name(input_object)) return Boefje( - id=plugin_id, - name=form_data.get("name"), + id=str(plugin_id), + name=form_data["name"], created=created, - description=form_data.get("description"), + description=form_data["description"], interval=interval, enabled=False, type="boefje", @@ -215,6 +241,6 @@ def create_boefje_with_form_data(form_data, plugin_id: str, created: str): consumes=input_objects, produces=produces, boefje_schema=form_data["boefje_schema"], - oci_image=form_data.get("oci_image"), + oci_image=form_data["oci_image"], oci_arguments=arguments, ) diff --git a/rocky/rocky/locale/django.pot b/rocky/rocky/locale/django.pot index 47ede056c5e..a6364f2cbbe 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-09-30 13:09+0000\n" +"POT-Creation-Date: 2024-10-01 14:17+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -600,7 +600,20 @@ msgid "" msgstr "" #: katalogus/client.py -msgid "A HTTP error occurred. Check logs for more info." +msgid "Boefje with this name already exists." +msgstr "" + +#: katalogus/client.py +msgid "Boefje with this ID already exists." +msgstr "" + +#: katalogus/client.py +msgid "Editing this boefje is not allowed because it is static." +msgstr "" + +#: katalogus/client.py +#, python-format +msgid "An HTTP %d error occurred. Check logs for more info." msgstr "" #: katalogus/forms/katalogus_filter.py diff --git a/rocky/tests/reports/test_plugins.py b/rocky/tests/reports/test_plugins.py index 2187f09b00f..940997a1b70 100644 --- a/rocky/tests/reports/test_plugins.py +++ b/rocky/tests/reports/test_plugins.py @@ -1,3 +1,5 @@ +from unittest.mock import MagicMock + from django.urls import resolve, reverse from katalogus.client import KATalogusHTTPStatusError from reports.views.generate_report import SetupScanGenerateReportView @@ -20,8 +22,7 @@ def test_generate_report_setup_scan_wrong_plugin_id( mock_organization_view_octopoes().list_objects.return_value = Paginated[OOIType]( count=len(listed_hostnames), items=listed_hostnames ) - - katalogus_client.get_plugins.side_effect = KATalogusHTTPStatusError + katalogus_client.get_plugins.side_effect = KATalogusHTTPStatusError(MagicMock()) mock_bytes_client().upload_raw.return_value = "raw_id" kwargs = {"organization_code": client_member.organization.code} @@ -42,4 +43,4 @@ def test_generate_report_setup_scan_wrong_plugin_id( response = SetupScanGenerateReportView.as_view()(request, organization_code=client_member.organization.code) assert response.status_code == 307 - assert list(request._messages)[0].message == "A HTTP error occurred. Check logs for more info." + assert list(request._messages)[0].message == "An HTTP %d error occurred. Check logs for more info." diff --git a/rocky/tools/forms/boefje.py b/rocky/tools/forms/boefje.py index 43db2f25783..56209705680 100644 --- a/rocky/tools/forms/boefje.py +++ b/rocky/tools/forms/boefje.py @@ -16,7 +16,7 @@ OOI_TYPE_CHOICES = sorted((ooi_type.get_object_type(), ooi_type.get_object_type()) for ooi_type in ALL_TYPES) -class BoefjeAddForm(BaseRockyForm): +class BoefjeSetupForm(BaseRockyForm): oci_image = forms.CharField( required=True, label=_("Container image"),