Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

service: add CRUD actions for CheckConfigService #14

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions invenio_checks/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

from . import config
from .base import ChecksRegistry
from .services import (
CheckConfigService,
ChecksConfigServiceConfig,
)


class InvenioChecks(object):
Expand All @@ -25,6 +29,9 @@ def init_app(self, app):
app.extensions["invenio-checks"] = self
self.checks_registry = ChecksRegistry()
self.checks_registry.load_from_entry_points(app, "invenio_checks.check_types")
self.service = CheckConfigService(
config=ChecksConfigServiceConfig.build(app),
)

def init_config(self, app):
"""Initialize configuration."""
Expand Down
5 changes: 5 additions & 0 deletions invenio_checks/proxies.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@
current_checks_registry = LocalProxy(
lambda: current_app.extensions["invenio-checks"].checks_registry
)

current_checks_configs_service = LocalProxy(
lambda: current_app.extensions["invenio-checks"].service
)
"""Proxy to the instantiated checks_configs service."""
40 changes: 30 additions & 10 deletions invenio_checks/services/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
"""Service schemas."""

from datetime import timezone
from uuid import UUID

from marshmallow import EXCLUDE, Schema, fields
from marshmallow import EXCLUDE, Schema, ValidationError, fields, validates
from marshmallow_utils.fields import SanitizedUnicode, TZDateTime
from marshmallow_utils.permissions import FieldPermissionsMixin
from sqlalchemy.orm import validates

from ..models import CheckRunStatus
from ..models import CheckRunStatus, Severity
from ..proxies import current_checks_registry


class CheckConfigSchema(Schema, FieldPermissionsMixin):
Expand All @@ -25,14 +28,31 @@ class Meta:
unknown = EXCLUDE

id = fields.UUID(dump_only=True)

created = TZDateTime(timezone=timezone.utc, format="iso", dump_only=True)
updated = TZDateTime(timezone=timezone.utc, format="iso", dump_only=True)

title = SanitizedUnicode(required=True)
description = SanitizedUnicode()

active = fields.Boolean(load_default=True)
community_id = fields.Str(required=True)
check_id = fields.Str(required=True)
params = fields.Dict(required=False, default={})
severity = fields.Str(required=False, default=Severity.INFO.value)
enabled = fields.Bool(required=False, default=True)

@validates("community_id")
def validate_community_id(self, value):
"""Validate that the community_id is a valid UUID."""
try:
UUID(value)
except ValueError:
raise ValidationError("Invalid UUID format for community_id.")

@validates("check_id")
def validate_check_id(self, value):
"""Validate that the check_id exists in the registry."""
if not current_checks_registry.get(value):
raise ValidationError(f"Check with id '{value}' not found.")

@validates("severity")
def validate_severity(self, value):
"""Validate that the severity is a valid enum value."""
if value not in [s.value for s in Severity]:
raise ValidationError(f"Invalid severity value: {value}.")


class CheckRunSchema(Schema, FieldPermissionsMixin):
Expand Down
103 changes: 95 additions & 8 deletions invenio_checks/services/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@

"""Checks services."""

from uuid import UUID

from invenio_records_resources.services.records import RecordService
from invenio_records_resources.services.uow import (
ModelCommitOp,
ModelDeleteOp,
unit_of_work,
)
from marshmallow import ValidationError
from sqlalchemy.orm.exc import NoResultFound

from ..models import CheckConfig, Severity
from .schema import CheckConfigSchema


class BaseClass(RecordService):
Expand All @@ -23,25 +35,100 @@ def rebuild_index(self, identity, uow=None):
raise NotImplementedError()


def get_check_config(id_):
"""Get a check config by id."""
check_config = CheckConfig.query.get(id_)
if check_config == None:
raise ValueError(f"Check configuration with id '{id_}' not found")
return check_config


class CheckConfigService(RecordService):
"""Service for managing and check configurations."""
"""Service for managing check configurations."""

@unit_of_work()
def create(self, identity, data, uow=None, **kwargs):
"""Create a check configuration."""
self.require_permission(identity, "create")

schema = CheckConfigSchema()
try:
validated_data = schema.load(data)
except ValidationError as e:
raise ValueError(f"Validation error: {e.messages}")

try:
check_config = CheckConfig(
community_id=UUID(validated_data["community_id"]),
check_id=validated_data["check_id"],
params=validated_data.get("params", {}),
severity=validated_data.get("severity", Severity.INFO.value),
enabled=validated_data.get("enabled", True),
)
uow.register(ModelCommitOp(check_config))
return check_config
except Exception as e:
raise ValueError(f"Failed to create check configuration: {str(e)}")

def read(self, identity, id_, **kwargs):
"""Read a check configuration."""
raise NotImplementedError()
self.require_permission(identity, "read")
check_config = get_check_config(id_)
return check_config

def search(self, identity, params=None, **kwargs):
"""Search for check configurations."""
raise NotImplementedError()
self.require_permission(identity, "search")

def create(self, identity, data, uow=None, **kwargs):
"""Create a check configuration."""
raise NotImplementedError()
if params is None:
params = {}
query = CheckConfig.query

if "community_id" in params:
query = query.filter_by(community_id=UUID(params["community_id"]))
if "check_id" in params:
query = query.filter_by(check_id=params["check_id"])
if "enabled" in params:
query = query.filter_by(enabled=params["enabled"])

return query.all()

@unit_of_work()
def update(self, identity, id_, data, revision_id=None, uow=None, **kwargs):
"""Update a check configuration."""
raise NotImplementedError()
self.require_permission(identity, "update")

try:
check_config = get_check_config(id_)
if "community_id" in data:
check_config.community_id = UUID(data["community_id"])
if "check_id" in data:
check_config.check_id = data["check_id"]
if "params" in data:
check_config.params = data["params"]
if "severity" in data:
check_config.severity = data["severity"]
if "enabled" in data:
check_config.enabled = data["enabled"]

uow.register(ModelCommitOp(check_config))
return check_config
except NoResultFound:
raise ValueError(f"Check configuration with id '{id_}' not found")
except Exception as e:
raise ValueError(f"Failed to update check configuration: {str(e)}")

@unit_of_work()
def delete(self, identity, id_, revision_id=None, uow=None, **kwargs):
"""Delete a check configuration."""
raise NotImplementedError()
self.require_permission(identity, "delete")

try:
check_config = get_check_config(id_)
uow.register(ModelDeleteOp(check_config))

return True
except NoResultFound:
raise ValueError(f"Check configuration with id '{id_}' not found")
except Exception as e:
raise ValueError(f"Failed to delete check configuration: {str(e)}")
Loading