Skip to content
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
34 changes: 34 additions & 0 deletions invenio_checks/alembic/9d47b33c7b74_add_target_type_column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# This file is part of Invenio.
# Copyright (C) 2016-2026 CERN.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""add target_type record."""

import sqlalchemy as sa
from alembic import op
from sqlalchemy.sql import text

# revision identifiers, used by Alembic.
revision = "9d47b33c7b74"
down_revision = "e8bd906e5da8"
branch_labels = ()
depends_on = None


def upgrade():
"""Upgrade database."""
op.add_column(
"checks_config",
sa.Column("target_type", sa.String(15), nullable=False, server_default=""),
)
op.execute(text("""UPDATE checks_config SET target_type = 'record' WHERE
check_id = 'metadata' or check_id = 'file_formats';"""))


def downgrade():
"""Downgrade database."""
op.drop_column("checks_config", "target_type")
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# This file is part of Invenio.
# Copyright (C) 2016-2026 CERN.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""make checkrun fields nullable."""

import sqlalchemy as sa
import sqlalchemy_utils
from alembic import op
from sqlalchemy.dialects import postgresql
from sqlalchemy_utils import JSONType

from invenio_checks.models import CheckRunStatus, Severity

# revision identifiers, used by Alembic.
revision = "e8bd906e5da8"
down_revision = "c39b06b59667"
branch_labels = ()
depends_on = None


def upgrade():
"""Upgrade database."""
op.alter_column("checks_run", "is_draft", nullable=True)
op.alter_column("checks_run", "revision_id", nullable=True)


def downgrade():
"""Downgrade database."""
op.execute("UPDATE checks_run SET is_draft = FALSE WHERE is_draft IS NULL")
op.execute("UPDATE checks_run SET revision_id = 0 WHERE revision_id IS NULL")
op.alter_column("checks_run", "is_draft", nullable=False)
op.alter_column("checks_run", "revision_id", nullable=False)
# ### end Alembic commands ###
68 changes: 50 additions & 18 deletions invenio_checks/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from flask import current_app
from invenio_db.uow import ModelCommitOp
from sqlalchemy import or_

from .models import CheckConfig, CheckRun, CheckRunStatus
from .proxies import current_checks_registry
Expand All @@ -23,20 +24,25 @@ class ChecksAPI:
@classmethod
def get_runs(cls, record, is_draft=None):
"""Get all check runs for a record or draft."""
if is_draft is None:
if is_draft is None and getattr(record, "is_draft", False):
is_draft = record.is_draft
return CheckRun.query.filter_by(record_id=record.id, is_draft=is_draft).all()

@classmethod
def get_configs(cls, community_ids):
def get_configs(cls, community_ids, target_type=None):
"""Get all check configurations for a list of community IDs."""
if not community_ids:
return []

return CheckConfig.query.filter(
query = CheckConfig.query.filter(
CheckConfig.community_id.in_(community_ids),
CheckConfig.enabled.is_(True),
).all()
)

if target_type is not None:
query = query.filter(CheckConfig.target_type == target_type)

return query.all()

@classmethod
def run_check(cls, config, record, uow, is_draft=None):
Expand All @@ -46,7 +52,7 @@ def run_check(cls, config, record, uow, is_draft=None):
updates the run with the new results. If no run exists, it will create it.
If the operation fails, an error is logged and `None` is returned.
"""
if is_draft is None:
if is_draft is None and config.target_type == "record":
is_draft = record.is_draft

result_run = None
Expand All @@ -64,25 +70,33 @@ def run_check(cls, config, record, uow, is_draft=None):
).one_or_none()

if not previous_run:
result_run = CheckRun(
config=config,
record_id=record.id,
is_draft=is_draft,
revision_id=record.revision_id,
start_time=start_time,
end_time=end_time,
status=CheckRunStatus.COMPLETED,
state="",
result=res.to_dict(),
)
check_run = {
"config": config,
"record_id": record.id,
"start_time": start_time,
"end_time": end_time,
"status": CheckRunStatus.COMPLETED,
"state": "",
"result": res.to_dict(),
}
if config.target_type == "record":
check_run.update(
{
"is_draft": is_draft,
"revision_id": record.revision_id,
}
)
result_run = CheckRun(**check_run)
else:
result_run = previous_run
result_run.is_draft = is_draft
result_run.revision_id = record.revision_id
result_run.start_time = start_time
result_run.end_time = end_time
result_run.result = res.to_dict()

if config.target_type == "record":
result_run.is_draft = is_draft
result_run.revision_id = record.revision_id

uow.register(ModelCommitOp(result_run))
except Exception:
current_app.logger.exception(
Expand All @@ -94,3 +108,21 @@ def run_check(cls, config, record, uow, is_draft=None):
)

return result_run

@classmethod
def extract_run_errors(cls, runs):
"""Build errors list from a list of check runs."""
errors = []
for run in runs:
if not run.result or not run.result.get("errors"):
continue

for error in run.result.get("errors", []):
errors.append(
{
**error,
"context": {"community": str(run.config.community_id)},
}
)

return errors
4 changes: 4 additions & 0 deletions invenio_checks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class Check:
description: str
"""Description of the check's purpose."""

sync: bool

target_type: str

def validate_config(self, config):
"""Validate the configuration for this check."""
raise NotImplementedError()
Expand Down
Loading
Loading