Skip to content

Commit fe0f8de

Browse files
committed
deposit: passed checks errors to form on draft edit
1 parent 67704b3 commit fe0f8de

File tree

6 files changed

+107
-72
lines changed

6 files changed

+107
-72
lines changed

invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/deposit.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
value='{{ files_locked | tojson }}'>
3232
{%- endif %}
3333

34+
{%- if errors %}
35+
<input id="deposits-errors" type="hidden" name="deposits-errors"
36+
value='{{ errors | tojson }}'>
37+
{%- endif %}
38+
3439
{%- if preselectedCommunity %}
3540
<input id="deposits-draft-community" type="hidden" name="deposits-draft-community"
3641
value='{{ preselectedCommunity | tojson }}'>
@@ -54,6 +59,7 @@
5459
<input type="hidden" name="deposits-config"
5560
value='{{ forms_config | tojson }}'>
5661
{%- endif %}
62+
5763

5864
{%- if permissions %}
5965
<input id="deposits-record-permissions" type="hidden"

invenio_app_rdm/records_ui/views/deposits.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from invenio_communities.views.communities import render_community_theme_template
2121
from invenio_i18n import lazy_gettext as _
2222
from invenio_i18n.ext import current_i18n
23-
from invenio_rdm_records.proxies import current_rdm_records
23+
from invenio_rdm_records.proxies import current_rdm_records, current_rdm_records_service
2424
from invenio_rdm_records.records.api import get_files_quota
2525
from invenio_rdm_records.resources.serializers import UIJSONSerializer
2626
from invenio_rdm_records.services.schemas import RDMRecordSchema
@@ -32,6 +32,7 @@
3232
from marshmallow_utils.fields.babel import gettext_from_dict
3333
from sqlalchemy.orm import load_only
3434

35+
from ...utils.checks import resolve_checks
3536
from ..utils import set_default_value
3637
from .decorators import (
3738
no_cache_response,
@@ -548,11 +549,25 @@ def deposit_edit(pid_value, draft=None, draft_files=None, files_locked=True):
548549
if doi_provider_config:
549550
doi_provider_config[0]["default_selected"] = "no"
550551

552+
errors = []
553+
record_uuid = current_rdm_records_service.draft_cls.pid.resolve(
554+
pid_value, registered_only=False
555+
).id
556+
request = draft.data.get("parent", {}).get("review")
557+
if request and record_uuid:
558+
checks = resolve_checks(record_uuid, request) or []
559+
errors = [
560+
err
561+
for check in checks
562+
for err in (check.result.get("errors") if check.result else [])
563+
]
564+
551565
return render_community_theme_template(
552566
current_app.config["APP_RDM_DEPOSIT_FORM_TEMPLATE"],
553567
theme=community_theme,
554568
forms_config=form_config,
555569
record=record,
570+
errors=errors,
556571
community=community,
557572
community_use_jinja_header=community_use_jinja_header,
558573
files=files_dict,

invenio_app_rdm/requests_ui/views/requests.py

Lines changed: 4 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from flask_login import current_user, login_required
1414
from invenio_communities.config import COMMUNITIES_ROLES
1515
from invenio_communities.members.services.request import CommunityInvitation
16-
from invenio_communities.proxies import current_communities, current_identities_cache
16+
from invenio_communities.proxies import current_identities_cache
1717
from invenio_communities.subcommunities.services.request import (
1818
SubCommunityInvitationRequest,
1919
SubCommunityRequest,
@@ -31,7 +31,6 @@
3131
from invenio_requests.resolvers.registry import ResolverRegistry
3232
from invenio_requests.views.decorators import pass_request
3333
from invenio_users_resources.proxies import current_user_resources
34-
from sqlalchemy import case
3534
from sqlalchemy.orm.exc import NoResultFound
3635

3736
from ...records_ui.utils import get_external_resources
@@ -45,6 +44,7 @@
4544
get_user_communities_memberships,
4645
load_custom_fields,
4746
)
47+
from ...utils.checks import resolve_checks
4848

4949

5050
def _resolve_topic_record(request):
@@ -174,72 +174,6 @@ def _resolve_record_or_draft_media_files(record, request):
174174
return None
175175

176176

177-
def _resolve_checks(record_uuid, request, community=None):
178-
"""Resolve the checks for this draft/record related to the community and the request."""
179-
# FIXME: Move this logic to invenio-checks
180-
181-
# Early exit if checks are not enabled.
182-
enabled = current_app.config.get("CHECKS_ENABLED", False)
183-
184-
if not enabled:
185-
return None
186-
187-
# Early exit if not draft submission nor record inclusion
188-
request_type = request["type"]
189-
is_draft_submission = request_type == CommunitySubmission.type_id
190-
is_record_inclusion = request_type == CommunityInclusion.type_id
191-
192-
if not is_draft_submission and not is_record_inclusion:
193-
return None
194-
195-
# Early exit if there is no record UUID (for instance for some closed requests)
196-
if not record_uuid:
197-
return None
198-
199-
# Resolve the target community from the request if the community was not passed as an argument
200-
if not community:
201-
community_uuid = request["receiver"]["community"]
202-
community = current_communities.service.read(
203-
id_=community_uuid, identity=g.identity
204-
)
205-
206-
# Collect the community UUID and the potential parent community UUID
207-
communities = []
208-
community_parent_id = community.to_dict().get("parent", {}).get("id")
209-
if community_parent_id:
210-
# Add the parent community first for later ordering of check configs
211-
communities.append(community_parent_id)
212-
communities.append(community.id)
213-
214-
# Early exit if no check config found for the communities
215-
from invenio_checks.models import CheckConfig, CheckRun
216-
217-
check_configs = (
218-
CheckConfig.query.filter(CheckConfig.community_id.in_(communities))
219-
.order_by(
220-
# Order by the communities (parent first if any) and then by check IDs for deterministic ordering
221-
case((CheckConfig.community_id == communities[0], 0), else_=1),
222-
CheckConfig.check_id,
223-
)
224-
.all()
225-
)
226-
227-
if not check_configs:
228-
return None
229-
230-
# Find check runs for the given check configs
231-
check_config_ids = [check_config.id for check_config in check_configs]
232-
checks = CheckRun.query.filter(
233-
CheckRun.config_id.in_(check_config_ids),
234-
CheckRun.record_id == record_uuid,
235-
).all()
236-
# For a given record, there is one check run corresponding to one check config
237-
# Order the check runs by the same order as the check configs for deterministic ordering
238-
checks = sorted(checks, key=lambda check: check_config_ids.index(check.config_id))
239-
240-
return checks
241-
242-
243177
@login_required
244178
@pass_request(expand=True)
245179
def user_dashboard_request_view(request, **kwargs):
@@ -261,7 +195,7 @@ def user_dashboard_request_view(request, **kwargs):
261195
record = topic["record"]
262196
record_uuid = topic["record_uuid"]
263197
is_draft = record_ui["is_draft"] if record_ui else False
264-
checks = _resolve_checks(record_uuid, request)
198+
checks = resolve_checks(record_uuid, request)
265199

266200
files = _resolve_record_or_draft_files(record_ui, request)
267201
media_files = _resolve_record_or_draft_media_files(record_ui, request)
@@ -341,7 +275,7 @@ def community_dashboard_request_view(request, community, community_ui, **kwargs)
341275
record = topic["record"]
342276
record_uuid = topic["record_uuid"]
343277
is_draft = record_ui["is_draft"] if record_ui else False
344-
checks = _resolve_checks(record_uuid, request, community)
278+
checks = resolve_checks(record_uuid, request, community)
345279

346280
permissions.update(topic["permissions"])
347281
files = _resolve_record_or_draft_files(record_ui, request)

invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export class RDMDepositForm extends Component {
5252
super(props);
5353
this.config = props.config || {};
5454
const { files, record } = this.props;
55-
5655
// TODO: Make ALL vocabulary be generated by backend.
5756
// Currently, some vocabulary is generated by backend and some is
5857
// generated by frontend here. Iteration is faster and abstractions can be
@@ -106,6 +105,7 @@ export class RDMDepositForm extends Component {
106105
const {
107106
config,
108107
record,
108+
errors,
109109
files,
110110
permissions,
111111
preselectedCommunity,
@@ -126,6 +126,7 @@ export class RDMDepositForm extends Component {
126126
<Overridable
127127
id="InvenioAppRdm.Deposit.RDMDepositForm.layout"
128128
record={record}
129+
errors={errors}
129130
files={files}
130131
config={config}
131132
permissions={permissions}
@@ -143,6 +144,7 @@ export class RDMDepositForm extends Component {
143144
preselectedCommunity={preselectedCommunity}
144145
files={files}
145146
permissions={permissions}
147+
errors={errors}
146148
>
147149
<Overridable
148150
id="InvenioAppRdm.Deposit.FormFeedback.container"
@@ -760,6 +762,7 @@ RDMDepositForm.propTypes = {
760762
recordRestrictionGracePeriod: PropTypes.number.isRequired,
761763
allowRecordRestriction: PropTypes.bool.isRequired,
762764
record: PropTypes.object.isRequired,
765+
errors: PropTypes.object,
763766
preselectedCommunity: PropTypes.object,
764767
files: PropTypes.object,
765768
permissions: PropTypes.object,

invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ReactDOM.render(
1818
<OverridableContext.Provider value={overriddenComponents}>
1919
<RDMDepositForm
2020
record={getInputFromDOM("deposits-record")}
21+
errors={getInputFromDOM("deposits-errors")}
2122
preselectedCommunity={getInputFromDOM("deposits-draft-community")}
2223
files={getInputFromDOM("deposits-record-files")}
2324
config={getInputFromDOM("deposits-config")}

invenio_app_rdm/utils/checks.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright (C) 2025 CERN.
4+
#
5+
# Invenio-Checks is free software; you can redistribute it and/or modify it
6+
# under the terms of the MIT License; see LICENSE file for more details.
7+
"""Checks utilities."""
8+
9+
from flask import current_app, g
10+
from invenio_communities.proxies import current_communities
11+
from invenio_rdm_records.requests import CommunityInclusion, CommunitySubmission
12+
from sqlalchemy import case
13+
14+
15+
def resolve_checks(record_uuid, request, community=None):
16+
"""Resolve the checks for this draft/record related to the community and the request."""
17+
# Early exit if checks are not enabled.
18+
enabled = current_app.config.get("CHECKS_ENABLED", False)
19+
20+
if not enabled:
21+
return None
22+
23+
# Early exit if not draft submission nor record inclusion
24+
request_type = request["type"]
25+
is_draft_submission = request_type == CommunitySubmission.type_id
26+
is_record_inclusion = request_type == CommunityInclusion.type_id
27+
28+
if not is_draft_submission and not is_record_inclusion:
29+
return None
30+
31+
# Early exit if there is no record UUID (for instance for some closed requests)
32+
if not record_uuid:
33+
return None
34+
35+
# Resolve the target community from the request if the community was not passed as an argument
36+
if not community:
37+
community_uuid = request["receiver"]["community"]
38+
community = current_communities.service.read(
39+
id_=community_uuid, identity=g.identity
40+
)
41+
42+
# Collect the community UUID and the potential parent community UUID
43+
communities = []
44+
community_parent_id = community.to_dict().get("parent", {}).get("id")
45+
if community_parent_id:
46+
# Add the parent community first for later ordering of check configs
47+
communities.append(community_parent_id)
48+
communities.append(community.id)
49+
50+
# Early exit if no check config found for the communities
51+
from invenio_checks.models import CheckConfig, CheckRun
52+
53+
check_configs = (
54+
CheckConfig.query.filter(CheckConfig.community_id.in_(communities))
55+
.order_by(
56+
# Order by the communities (parent first if any) and then by check IDs for deterministic ordering
57+
case((CheckConfig.community_id == communities[0], 0), else_=1),
58+
CheckConfig.check_id,
59+
)
60+
.all()
61+
)
62+
63+
if not check_configs:
64+
return None
65+
66+
# Find check runs for the given check configs
67+
check_config_ids = [check_config.id for check_config in check_configs]
68+
checks = CheckRun.query.filter(
69+
CheckRun.config_id.in_(check_config_ids),
70+
CheckRun.record_id == record_uuid,
71+
).all()
72+
# For a given record, there is one check run corresponding to one check config
73+
# Order the check runs by the same order as the check configs for deterministic ordering
74+
checks = sorted(checks, key=lambda check: check_config_ids.index(check.config_id))
75+
76+
return checks

0 commit comments

Comments
 (0)