diff --git a/api_app/analyzers_manager/classes.py b/api_app/analyzers_manager/classes.py index 0e482573a9..ffbac29cb1 100644 --- a/api_app/analyzers_manager/classes.py +++ b/api_app/analyzers_manager/classes.py @@ -11,6 +11,7 @@ import requests from django.conf import settings +from api_app.decorators import classproperty from certego_saas.apps.user.models import User from ..choices import Classification, PythonModuleBasePaths @@ -67,8 +68,7 @@ def create_data_model(self): return data_model return None - @classmethod - @property + @classproperty def config_exception(cls): """Returns the AnalyzerConfigurationException class.""" return AnalyzerConfigurationException @@ -78,14 +78,12 @@ def analyzer_name(self) -> str: """Returns the name of the analyzer.""" return self._config.name - @classmethod - @property + @classproperty def report_model(cls): """Returns the AnalyzerReport model.""" return AnalyzerReport - @classmethod - @property + @classproperty def config_model(cls): """Returns the AnalyzerConfig model.""" return AnalyzerConfig @@ -183,8 +181,7 @@ def config(self, runtime_configuration: Dict): self.observable_name = self._job.analyzable.name self.observable_classification = self._job.analyzable.classification - @classmethod - @property + @classproperty def python_base_path(cls): return PythonModuleBasePaths.ObservableAnalyzer.value @@ -232,8 +229,7 @@ def config(self, runtime_configuration: Dict): self.__filepath = None self.file_mimetype = self._job.analyzable.mimetype - @classmethod - @property + @classproperty def python_base_path(cls) -> PosixPath: return PythonModuleBasePaths[FileAnalyzer.__name__].value diff --git a/api_app/analyzers_manager/models.py b/api_app/analyzers_manager/models.py index e49beb2647..4ec7852040 100644 --- a/api_app/analyzers_manager/models.py +++ b/api_app/analyzers_manager/models.py @@ -15,6 +15,7 @@ from api_app.choices import TLP, Classification, PythonModuleBasePaths from api_app.data_model_manager.fields import SetField from api_app.data_model_manager.models import BaseDataModel +from api_app.decorators import classproperty from api_app.fields import ChoiceArrayField from api_app.models import AbstractReport, PythonConfig, PythonModule @@ -300,8 +301,7 @@ class AnalyzerConfig(PythonConfig): blank=True, ) - @classmethod - @property + @classproperty def serializer_class(cls): from api_app.analyzers_manager.serializers import AnalyzerConfigSerializer @@ -341,13 +341,11 @@ def clean(self): self.clean_observable_supported() self.clean_filetypes() - @classmethod - @property + @classproperty def plugin_type(cls) -> str: return "1" - @classmethod - @property + @classproperty def config_exception(cls): return AnalyzerConfigurationException diff --git a/api_app/analyzers_manager/observable_analyzers/feodo_tracker.py b/api_app/analyzers_manager/observable_analyzers/feodo_tracker.py index 6b2c219a76..0ae7adf400 100644 --- a/api_app/analyzers_manager/observable_analyzers/feodo_tracker.py +++ b/api_app/analyzers_manager/observable_analyzers/feodo_tracker.py @@ -11,6 +11,7 @@ from api_app.analyzers_manager import classes from api_app.analyzers_manager.exceptions import AnalyzerRunException +from api_app.decorators import classproperty from api_app.mixins import AbuseCHMixin from api_app.models import PluginConfig @@ -27,15 +28,13 @@ class Feodo_Tracker(AbuseCHMixin, classes.ObservableAnalyzer): use_recommended_url: bool update_on_run: bool = True - @classmethod - @property + @classproperty def recommend_locations(cls) -> Tuple[str, str]: db_name = "feodotracker_abuse_ipblocklist.json" url = "https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.json" return f"{settings.MEDIA_ROOT}/{db_name}", url - @classmethod - @property + @classproperty def default_locations(cls) -> Tuple[str, str]: db_name = "feodotracker_abuse_ipblocklist_recommended.json" url = "https://feodotracker.abuse.ch/downloads/ipblocklist.json" diff --git a/api_app/analyzers_manager/views.py b/api_app/analyzers_manager/views.py index 5e0d8c8d07..e8ba59573b 100644 --- a/api_app/analyzers_manager/views.py +++ b/api_app/analyzers_manager/views.py @@ -5,6 +5,7 @@ from rest_framework import mixins from rest_framework.exceptions import NotFound +from api_app.decorators import classproperty from api_app.models import PluginConfig from ..permissions import isPluginActionsPermission @@ -40,8 +41,7 @@ def get_permissions(self): class AnalyzerActionViewSet(PythonReportActionViewSet): - @classmethod - @property + @classproperty def report_model(cls): return AnalyzerReport diff --git a/api_app/classes.py b/api_app/classes.py index 7a7d4a69b0..f56ef10edc 100644 --- a/api_app/classes.py +++ b/api_app/classes.py @@ -13,6 +13,7 @@ from django.utils.functional import cached_property from requests import HTTPError +from api_app.decorators import abstractclassproperty, classproperty from api_app.models import AbstractReport, Job, PythonConfig, PythonModule from certego_saas.apps.user.models import User @@ -52,9 +53,7 @@ def name(self): """ return self._config.name - @classmethod - @property - @abstractmethod + @abstractclassproperty def python_base_path(cls) -> PosixPath: NotImplementedError() @@ -243,18 +242,14 @@ def after_run_failed(self, e: Exception): if settings.STAGE_CI: raise e - @classmethod - @property - @abstractmethod + @abstractclassproperty def report_model(cls) -> typing.Type[AbstractReport]: """ Returns Model to be used for *init_report_object* """ raise NotImplementedError() - @classmethod - @property - @abstractmethod + @abstractclassproperty def config_model(cls) -> typing.Type[PythonConfig]: """ Returns Model to be used for *init_report_object* @@ -321,8 +316,7 @@ def _monkeypatch(cls, patches: list = None) -> None: for mock_fn in patches: cls.start = mock_fn(cls.start) - @classmethod - @property + @classproperty def python_module(cls) -> PythonModule: """ Get the Python module associated with the plugin. diff --git a/api_app/connectors_manager/classes.py b/api_app/connectors_manager/classes.py index 2e3da0a3d6..0d7ce4dd5b 100644 --- a/api_app/connectors_manager/classes.py +++ b/api_app/connectors_manager/classes.py @@ -4,6 +4,8 @@ import logging from typing import Type +from api_app.decorators import classproperty + from ..choices import PythonModuleBasePaths, ReportStatus from ..classes import Plugin from .exceptions import ConnectorConfigurationException, ConnectorRunException @@ -20,18 +22,15 @@ class Connector(Plugin, metaclass=abc.ABCMeta): and `run(self)` functions. """ - @classmethod - @property + @classproperty def python_base_path(cls): return PythonModuleBasePaths.Connector.value - @classmethod - @property + @classproperty def report_model(cls) -> Type[ConnectorReport]: return ConnectorReport - @classmethod - @property + @classproperty def config_model(cls) -> Type[ConnectorConfig]: return ConnectorConfig diff --git a/api_app/connectors_manager/models.py b/api_app/connectors_manager/models.py index cef6ca54ae..40d36bc1fc 100644 --- a/api_app/connectors_manager/models.py +++ b/api_app/connectors_manager/models.py @@ -6,6 +6,7 @@ from api_app.choices import TLP, PythonModuleBasePaths from api_app.connectors_manager.exceptions import ConnectorConfigurationException from api_app.connectors_manager.queryset import ConnectorReportQuerySet +from api_app.decorators import classproperty from api_app.models import AbstractReport, PythonConfig, PythonModule @@ -35,18 +36,15 @@ class ConnectorConfig(PythonConfig): "api_app.OrganizationPluginConfiguration", related_name="%(class)s" ) - @classmethod - @property + @classproperty def plugin_type(cls) -> str: return "2" - @classmethod - @property + @classproperty def config_exception(cls): return ConnectorConfigurationException - @classmethod - @property + @classproperty def serializer_class(cls): from api_app.connectors_manager.serializers import ConnectorConfigSerializer diff --git a/api_app/connectors_manager/views.py b/api_app/connectors_manager/views.py index e367cfbcdf..33d904753b 100644 --- a/api_app/connectors_manager/views.py +++ b/api_app/connectors_manager/views.py @@ -3,6 +3,8 @@ import logging +from api_app.decorators import classproperty + from ..views import PluginConfigViewSet, PythonConfigViewSet, PythonReportActionViewSet from .models import ConnectorConfig, ConnectorReport from .serializers import ConnectorConfigSerializer @@ -21,8 +23,7 @@ class ConnectorConfigViewSet(PythonConfigViewSet): class ConnectorActionViewSet(PythonReportActionViewSet): - @classmethod - @property + @classproperty def report_model(cls): return ConnectorReport diff --git a/api_app/decorators.py b/api_app/decorators.py index b5f5a03bd3..5d90917091 100644 --- a/api_app/decorators.py +++ b/api_app/decorators.py @@ -6,6 +6,26 @@ logger = logging.getLogger(__name__) +class classproperty(property): + """Read-only class property descriptor. + Replacement for deprecated @classmethod + @property. + """ + + def __get__(self, obj, owner=None): + return self.fget(owner if owner is not None else type(obj)) + + +class abstractclassproperty(property): + """Abstract read-only class property. + Enforced when the class uses ABCMeta metaclass. + """ + + __isabstractmethod__ = True + + def __get__(self, obj, owner=None): + return self.fget(owner if owner is not None else type(obj)) + + def deprecated_endpoint(deprecation_date=None, end_of_life_date=None): """ Returns a decorator which informs requester that diff --git a/api_app/ingestors_manager/classes.py b/api_app/ingestors_manager/classes.py index 18dfec5f6d..ea4d6826cd 100644 --- a/api_app/ingestors_manager/classes.py +++ b/api_app/ingestors_manager/classes.py @@ -8,6 +8,8 @@ from django.utils.functional import cached_property +from api_app.decorators import classproperty + from ..choices import TLP, PythonModuleBasePaths from ..classes import Plugin from .exceptions import IngestorConfigurationException, IngestorRunException @@ -25,8 +27,7 @@ class Ingestor(Plugin, metaclass=abc.ABCMeta): def __init__(self, config: IngestorConfig, **kwargs): super().__init__(config, **kwargs) - @classmethod - @property + @classproperty def python_base_path(cls): return PythonModuleBasePaths.Ingestor.value @@ -34,13 +35,11 @@ def python_base_path(cls): def run(self) -> typing.Iterator[Any]: raise NotImplementedError() - @classmethod - @property + @classproperty def report_model(cls) -> Type[IngestorReport]: return IngestorReport - @classmethod - @property + @classproperty def config_model(cls) -> Type[IngestorConfig]: return IngestorConfig diff --git a/api_app/ingestors_manager/models.py b/api_app/ingestors_manager/models.py index fe8ec58aa1..f4d96b7b36 100644 --- a/api_app/ingestors_manager/models.py +++ b/api_app/ingestors_manager/models.py @@ -9,6 +9,7 @@ from django_celery_beat.models import CrontabSchedule, PeriodicTask from api_app.choices import PythonModuleBasePaths +from api_app.decorators import classproperty from api_app.ingestors_manager.exceptions import IngestorConfigurationException from api_app.ingestors_manager.queryset import IngestorQuerySet, IngestorReportQuerySet from api_app.interfaces import CreateJobsFromPlaybookInterface @@ -123,18 +124,15 @@ class IngestorConfig(PythonConfig, CreateJobsFromPlaybookInterface): def disabled_in_organizations(self) -> QuerySet: return OrganizationPluginConfiguration.objects.none() - @classmethod - @property + @classproperty def plugin_type(cls) -> str: return "4" - @classmethod - @property + @classproperty def config_exception(cls): return IngestorConfigurationException - @classmethod - @property + @classproperty def serializer_class(cls): from api_app.ingestors_manager.serializers import IngestorConfigSerializer diff --git a/api_app/models.py b/api_app/models.py index 95ecc65668..0599aa9b23 100644 --- a/api_app/models.py +++ b/api_app/models.py @@ -1,5 +1,7 @@ # This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl # See the file 'LICENSE' for copying permission. +# pylint: disable=cyclic-import +# Reason: Harmless in Django due to bidirectional model relationships; resolved lazily at runtime via app registry import datetime import json import logging @@ -46,6 +48,7 @@ if typing.TYPE_CHECKING: from api_app.classes import Plugin +from api_app.decorators import classproperty from api_app.defaults import default_runtime from api_app.helpers import deprecated, get_now from api_app.queryset import ( @@ -1182,8 +1185,7 @@ def delete_class_cache_keys(cls, user: User = None): logger.debug(f"Deleting cache key {key}") cache.delete(key) - @classmethod - @property + @classproperty def python_path(cls) -> str: """ Returns the Python path of the class. @@ -1267,8 +1269,7 @@ def disabled_in_organizations(self) -> QuerySet: """ return self.orgs_configuration.filter(disabled=True) - @classmethod - @property + @classproperty def runtime_configuration_key(cls) -> str: """ Returns the runtime configuration key for the configuration. @@ -1278,8 +1279,7 @@ def runtime_configuration_key(cls) -> str: """ return f"{cls.__name__.split('Config')[0].lower()}s" - @classmethod - @property + @classproperty def snake_case_name(cls) -> str: """ Returns the snake_case name of the configuration. @@ -1368,8 +1368,7 @@ def __str__(self): """Returns a string representation of the report.""" return f"{self.__class__.__name__}(job:#{self.job_id}, {self.config.name})" - @classmethod - @property + @classproperty def config(cls) -> "AbstractConfig": """ Returns the configuration associated with the report. @@ -1508,8 +1507,7 @@ def parameters(self) -> ParameterQuerySet: """ return Parameter.objects.filter(python_module=self.python_module) - @classmethod - @property + @classproperty def report_class(cls) -> Type[AbstractReport]: """ Returns the report class associated with the plugin configuration. @@ -1534,8 +1532,7 @@ def get_subclasses(cls) -> typing.List["PythonConfig"]: if (model is not None and issubclass(model, cls) and model is not cls) ] - @classmethod - @property + @classproperty def plugin_type(cls) -> str: """ Returns the type of the plugin. @@ -1615,8 +1612,7 @@ def refresh_cache_keys(self, user: User = None): child=self.serializer_class() ).to_representation_single_plugin(self, generic_user) - @classmethod - @property + @classproperty def serializer_class(cls) -> Type["PythonConfigSerializer"]: """ Returns the serializer class associated with the plugin configuration. @@ -1626,8 +1622,7 @@ def serializer_class(cls) -> Type["PythonConfigSerializer"]: """ raise NotImplementedError() - @classmethod - @property + @classproperty def plugin_name(cls) -> str: """ Returns the name of the plugin. @@ -1742,8 +1737,7 @@ def _is_configured(self, user: User = None) -> bool: pc = self.__class__.objects.filter(pk=self.pk).annotate_configured(user).first() return pc.configured - @classmethod - @property + @classproperty def config_exception(cls): """ Returns the exception class for configuration errors. diff --git a/api_app/pivots_manager/classes.py b/api_app/pivots_manager/classes.py index 8bfce31090..d0a86c8045 100644 --- a/api_app/pivots_manager/classes.py +++ b/api_app/pivots_manager/classes.py @@ -6,6 +6,7 @@ from api_app.choices import PythonModuleBasePaths from api_app.classes import Plugin +from api_app.decorators import classproperty from api_app.models import AbstractReport from api_app.pivots_manager.exceptions import ( PivotConfigurationException, @@ -18,8 +19,7 @@ class Pivot(Plugin, metaclass=abc.ABCMeta): - @classmethod - @property + @classproperty def python_base_path(cls): return PythonModuleBasePaths.Pivot.value @@ -35,13 +35,11 @@ def related_reports(self) -> QuerySet: config__in=self.related_configs, job=self._job ) - @classmethod - @property + @classproperty def report_model(cls) -> Type[PivotReport]: return PivotReport - @classmethod - @property + @classproperty def config_model(cls) -> Type[PivotConfig]: return PivotConfig diff --git a/api_app/pivots_manager/models.py b/api_app/pivots_manager/models.py index 5d32f992dc..c125fa9277 100644 --- a/api_app/pivots_manager/models.py +++ b/api_app/pivots_manager/models.py @@ -17,6 +17,7 @@ from django.utils.functional import cached_property from api_app.choices import PythonModuleBasePaths +from api_app.decorators import classproperty from api_app.interfaces import CreateJobsFromPlaybookInterface # skipcq: PYL-R0401 from api_app.models import AbstractReport, Job, PythonConfig, PythonModule @@ -117,20 +118,17 @@ def related_configs(self) -> PythonConfigQuerySet: self.related_analyzer_configs.all() or self.related_connector_configs.all() ) - @classmethod - @property + @classproperty def plugin_type(cls) -> str: return "5" - @classmethod - @property + @classproperty def serializer_class(cls) -> Type["PythonConfigSerializer"]: from api_app.pivots_manager.serializers import PivotConfigSerializer return PivotConfigSerializer - @classmethod - @property + @classproperty def config_exception(cls): return PivotConfigurationException diff --git a/api_app/pivots_manager/views.py b/api_app/pivots_manager/views.py index 31a49093b2..4d4a309a03 100644 --- a/api_app/pivots_manager/views.py +++ b/api_app/pivots_manager/views.py @@ -2,6 +2,7 @@ from rest_framework.exceptions import NotFound from rest_framework.permissions import IsAuthenticated +from api_app.decorators import classproperty from api_app.models import PluginConfig from api_app.pivots_manager.models import PivotConfig, PivotMap, PivotReport from api_app.pivots_manager.permissions import ( @@ -50,8 +51,7 @@ def perform_destroy(self, instance: PivotConfig): class PivotActionViewSet(PythonReportActionViewSet): - @classmethod - @property + @classproperty def report_model(cls): return PivotReport diff --git a/api_app/views.py b/api_app/views.py index 1e0f019851..63fe362358 100644 --- a/api_app/views.py +++ b/api_app/views.py @@ -4,7 +4,7 @@ import datetime import logging import uuid -from abc import ABCMeta, abstractmethod +from abc import ABCMeta from django.conf import settings from django.core.exceptions import ObjectDoesNotExist @@ -23,6 +23,7 @@ from rest_framework.viewsets import ModelViewSet from api_app.choices import Classification, ScanMode +from api_app.decorators import abstractclassproperty from api_app.exceptions import NotImplementedException from api_app.websocket import JobConsumer from certego_saas.apps.organization.permissions import ( @@ -1027,9 +1028,7 @@ class PythonReportActionViewSet(viewsets.GenericViewSet, metaclass=ABCMeta): IsObjectUserOrSameOrgPermission, ] - @classmethod - @property - @abstractmethod + @abstractclassproperty def report_model(cls): """ Abstract property that should return the model class for the report. diff --git a/api_app/visualizers_manager/classes.py b/api_app/visualizers_manager/classes.py index f595e920ae..b13920f13c 100644 --- a/api_app/visualizers_manager/classes.py +++ b/api_app/visualizers_manager/classes.py @@ -10,6 +10,7 @@ from api_app.analyzers_manager.models import MimeTypes from api_app.choices import PythonModuleBasePaths from api_app.classes import Plugin +from api_app.decorators import classproperty from api_app.models import AbstractReport from api_app.visualizers_manager.enums import ( VisualizableAlignment, @@ -538,18 +539,15 @@ class Visualizer(Plugin, metaclass=abc.ABCMeta): Page = VisualizablePage Level = VisualizableLevel - @classmethod - @property + @classproperty def python_base_path(cls): return PythonModuleBasePaths.Visualizer.value - @classmethod - @property + @classproperty def report_model(cls): return VisualizerReport - @classmethod - @property + @classproperty def config_model(cls) -> Type[VisualizerConfig]: return VisualizerConfig diff --git a/api_app/visualizers_manager/models.py b/api_app/visualizers_manager/models.py index c6421ada11..6ac9a5effd 100644 --- a/api_app/visualizers_manager/models.py +++ b/api_app/visualizers_manager/models.py @@ -4,6 +4,7 @@ from django.db import models from api_app.choices import PythonModuleBasePaths +from api_app.decorators import classproperty from api_app.models import AbstractReport, PythonConfig, PythonModule from api_app.playbooks_manager.models import PlaybookConfig from api_app.visualizers_manager.exceptions import VisualizerConfigurationException @@ -43,18 +44,15 @@ class VisualizerConfig(PythonConfig): "api_app.OrganizationPluginConfiguration", related_name="%(class)s" ) - @classmethod - @property + @classproperty def plugin_type(cls) -> str: return "3" - @classmethod - @property + @classproperty def config_exception(cls): return VisualizerConfigurationException - @classmethod - @property + @classproperty def serializer_class(cls): from api_app.visualizers_manager.serializers import VisualizerConfigSerializer diff --git a/api_app/visualizers_manager/views.py b/api_app/visualizers_manager/views.py index 589b91bc68..9f4e25dd30 100644 --- a/api_app/visualizers_manager/views.py +++ b/api_app/visualizers_manager/views.py @@ -3,6 +3,7 @@ import logging +from api_app.decorators import classproperty from api_app.views import ( PluginConfigViewSet, PythonConfigViewSet, @@ -24,8 +25,7 @@ class VisualizerConfigViewSet(PythonConfigViewSet): class VisualizerActionViewSet(PythonReportActionViewSet): - @classmethod - @property + @classproperty def report_model(cls): return VisualizerReport diff --git a/api_app/visualizers_manager/visualizers/dns.py b/api_app/visualizers_manager/visualizers/dns.py index d8efad10e2..3559a97828 100644 --- a/api_app/visualizers_manager/visualizers/dns.py +++ b/api_app/visualizers_manager/visualizers/dns.py @@ -27,6 +27,7 @@ from api_app.analyzers_manager.observable_analyzers.dns.dns_resolvers.quad9_dns_resolver import ( # noqa: E501 Quad9DNSResolver, ) +from api_app.decorators import classproperty from api_app.models import Job from api_app.visualizers_manager.classes import VisualizableObject, Visualizer from api_app.visualizers_manager.decorators import ( @@ -37,8 +38,7 @@ class DNS(Visualizer): - @classmethod - @property + @classproperty def first_level_analyzers(cls) -> List[str]: return [ # noqa ClassicDNSResolver.python_module, @@ -48,8 +48,7 @@ def first_level_analyzers(cls) -> List[str]: Quad9DNSResolver.python_module, ] - @classmethod - @property + @classproperty def second_level_analyzers(cls) -> List[str]: return [ # noqa CloudFlareMaliciousDetector.python_module, diff --git a/authentication/oauth.py b/authentication/oauth.py index 32b462f0c5..9b93447f3d 100644 --- a/authentication/oauth.py +++ b/authentication/oauth.py @@ -2,7 +2,7 @@ # See the file 'LICENSE' for copying permission. """This module configures OAuth authentication for the IntelOwl project using the Authlib library. - It sets up OAuth for Google if it is specified in the Django settings. +It sets up OAuth for Google if it is specified in the Django settings. """ from authlib.integrations.django_client import OAuth diff --git a/authentication/serializers.py b/authentication/serializers.py index 83701672c5..b36adb6bfe 100644 --- a/authentication/serializers.py +++ b/authentication/serializers.py @@ -2,8 +2,8 @@ # See the file 'LICENSE' for copying permission. """This module contains various serializers used in the authentication process - for the IntelOwl project. These serializers handle user access, user profile, - registration, email verification, login, and token generation. +for the IntelOwl project. These serializers handle user access, user profile, +registration, email verification, login, and token generation. """ import logging diff --git a/tests/__init__.py b/tests/__init__.py index dd5b7127d4..a1ea4499e9 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -13,6 +13,7 @@ from api_app.analyzables_manager.models import Analyzable from api_app.analyzers_manager.models import AnalyzerConfig from api_app.choices import Classification +from api_app.decorators import abstractclassproperty from api_app.models import AbstractReport, Job User = get_user_model() @@ -242,9 +243,7 @@ def test_retry_404(self): class ViewSetTestCaseMixin: - @classmethod - @property - @abstractmethod + @abstractclassproperty def model_class(cls) -> Type[Model]: raise NotImplementedError() diff --git a/tests/api_app/analyzers_manager/test_views.py b/tests/api_app/analyzers_manager/test_views.py index 01362a2fd4..3cbb990738 100644 --- a/tests/api_app/analyzers_manager/test_views.py +++ b/tests/api_app/analyzers_manager/test_views.py @@ -6,6 +6,7 @@ from api_app.analyzables_manager.models import Analyzable from api_app.analyzers_manager.models import AnalyzerConfig, AnalyzerReport from api_app.choices import Classification, PythonModuleBasePaths +from api_app.decorators import classproperty from api_app.models import Job, PythonModule from certego_saas.apps.organization.membership import Membership from certego_saas.apps.organization.organization import Organization @@ -22,8 +23,7 @@ class AnalyzerConfigViewSetTestCase( URL = "/api/analyzer" - @classmethod - @property + @classproperty def model_class(cls) -> Type[AnalyzerConfig]: return AnalyzerConfig diff --git a/tests/api_app/connectors_manager/test_views.py b/tests/api_app/connectors_manager/test_views.py index 575c83e497..e0113d1cf1 100644 --- a/tests/api_app/connectors_manager/test_views.py +++ b/tests/api_app/connectors_manager/test_views.py @@ -5,6 +5,7 @@ from api_app.analyzables_manager.models import Analyzable from api_app.choices import Classification from api_app.connectors_manager.models import ConnectorConfig, ConnectorReport +from api_app.decorators import classproperty from api_app.models import Job, PluginConfig from tests import CustomViewSetTestCase, PluginActionViewsetTestCase from tests.api_app.test_views import AbstractConfigViewSetTestCaseMixin @@ -15,8 +16,7 @@ class ConnectorConfigViewSetTestCase( ): URL = "/api/connector" - @classmethod - @property + @classproperty def model_class(cls) -> Type[ConnectorConfig]: return ConnectorConfig diff --git a/tests/api_app/data_model_manager/test_views.py b/tests/api_app/data_model_manager/test_views.py index 46dd4ba44f..5fe422488d 100644 --- a/tests/api_app/data_model_manager/test_views.py +++ b/tests/api_app/data_model_manager/test_views.py @@ -11,6 +11,7 @@ FileDataModel, IPDataModel, ) +from api_app.decorators import classproperty from api_app.models import Job from tests import CustomViewSetTestCase, ViewSetTestCaseMixin @@ -59,8 +60,7 @@ def tearDownClass(cls): super().tearDownClass() Analyzable.objects.all().delete() - @classmethod - @property + @classproperty def model_class(cls) -> Type[Model]: return DomainDataModel @@ -78,8 +78,7 @@ def test_get_superuser(self): class IPDataModelViewSetTestCase(ViewSetTestCaseMixin, CustomViewSetTestCase): URL = "/api/data_model/ip" - @classmethod - @property + @classproperty def model_class(cls) -> Type[Model]: return IPDataModel @@ -108,8 +107,7 @@ def test_get_superuser(self): class FileDataModelViewSetTestCase(ViewSetTestCaseMixin, CustomViewSetTestCase): URL = "/api/data_model/file" - @classmethod - @property + @classproperty def model_class(cls) -> Type[Model]: return FileDataModel diff --git a/tests/api_app/ingestors_manager/test_views.py b/tests/api_app/ingestors_manager/test_views.py index 6eeacfffd9..c33aefa996 100644 --- a/tests/api_app/ingestors_manager/test_views.py +++ b/tests/api_app/ingestors_manager/test_views.py @@ -1,6 +1,7 @@ # This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl # See the file 'LICENSE' for copying permission. +from api_app.decorators import classproperty from api_app.ingestors_manager.models import IngestorConfig from certego_saas.apps.organization.organization import Membership, Organization from tests import CustomViewSetTestCase @@ -12,8 +13,7 @@ class IngestorConfigViewSetTestCase( ): URL = "/api/ingestor" - @classmethod - @property + @classproperty def model_class(cls) -> IngestorConfig: return IngestorConfig diff --git a/tests/api_app/pivots_manager/test_views.py b/tests/api_app/pivots_manager/test_views.py index ac9f08f855..fd0acc2393 100644 --- a/tests/api_app/pivots_manager/test_views.py +++ b/tests/api_app/pivots_manager/test_views.py @@ -3,6 +3,7 @@ from api_app.analyzables_manager.models import Analyzable from api_app.analyzers_manager.models import AnalyzerConfig from api_app.choices import Classification +from api_app.decorators import classproperty from api_app.models import Job, PythonModule from api_app.pivots_manager.models import PivotConfig, PivotMap from api_app.playbooks_manager.models import PlaybookConfig @@ -15,8 +16,7 @@ class PivotMapViewSetTestCase(ViewSetTestCaseMixin, CustomViewSetTestCase): URL = "/api/pivot_map" - @classmethod - @property + @classproperty def model_class(cls) -> Type[PivotMap]: return PivotMap @@ -110,8 +110,7 @@ def tearDown(self) -> None: super().tearDown() self.pc.delete() - @classmethod - @property + @classproperty def model_class(cls) -> Type[PivotConfig]: return PivotConfig diff --git a/tests/api_app/playbooks_manager/test_views.py b/tests/api_app/playbooks_manager/test_views.py index 14f2fceb4c..a7fe1aa067 100644 --- a/tests/api_app/playbooks_manager/test_views.py +++ b/tests/api_app/playbooks_manager/test_views.py @@ -4,6 +4,7 @@ from api_app.analyzers_manager.models import AnalyzerConfig from api_app.choices import PythonModuleBasePaths, ScanMode +from api_app.decorators import classproperty from api_app.models import PythonModule, Tag from api_app.playbooks_manager.models import PlaybookConfig from certego_saas.apps.organization.membership import Membership @@ -17,8 +18,7 @@ class PlaybookConfigViewSetTestCase( ): URL = "/api/playbook" - @classmethod - @property + @classproperty def model_class(cls) -> Type[PlaybookConfig]: return PlaybookConfig diff --git a/tests/api_app/test_mixins.py b/tests/api_app/test_mixins.py index ac35338f18..84e2e148cd 100644 --- a/tests/api_app/test_mixins.py +++ b/tests/api_app/test_mixins.py @@ -5,6 +5,7 @@ from api_app.analyzers_manager.models import AnalyzerConfig from api_app.choices import Classification +from api_app.decorators import classproperty from api_app.mixins import VirusTotalv3AnalyzerMixin, VirusTotalv3BaseMixin from tests import CustomTestCase from tests.mock_utils import MockUpResponse @@ -62,8 +63,7 @@ class VirusTotalv3Base(VirusTotalv3BaseMixin): - @classmethod - @property + @classproperty def python_base_path(cls) -> PosixPath: return pathlib.PosixPath(r"/") @@ -76,8 +76,7 @@ def run(self) -> dict: class VirusTotalv3Analyzer(VirusTotalv3AnalyzerMixin): - @classmethod - @property + @classproperty def python_base_path(cls) -> PosixPath: return pathlib.PosixPath(r"/") diff --git a/tests/api_app/visualizers_manager/test_views.py b/tests/api_app/visualizers_manager/test_views.py index 0d5d523916..da03b65c7e 100644 --- a/tests/api_app/visualizers_manager/test_views.py +++ b/tests/api_app/visualizers_manager/test_views.py @@ -1,20 +1,26 @@ # This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl # See the file 'LICENSE' for copying permission. -from typing import Type +from __future__ import annotations -from api_app.visualizers_manager.models import VisualizerConfig +from typing import TYPE_CHECKING, Type + +from api_app.decorators import classproperty from tests import CustomViewSetTestCase from tests.api_app.test_views import AbstractConfigViewSetTestCaseMixin +if TYPE_CHECKING: + from api_app.visualizers_manager.models import VisualizerConfig + class VisualizerConfigViewSetTestCase( AbstractConfigViewSetTestCaseMixin, CustomViewSetTestCase ): URL = "/api/visualizer" - @classmethod - @property - def model_class(cls) -> Type[VisualizerConfig]: + @classproperty + def model_class(cls) -> "Type['VisualizerConfig']": + from api_app.visualizers_manager.models import VisualizerConfig + return VisualizerConfig def test_get(self):