Skip to content

Commit 75c3521

Browse files
authored
Merge branch 'inveniosoftware:master' into add_i18n_to_pages
2 parents 0ace652 + 6c85c55 commit 75c3521

File tree

31 files changed

+353
-119
lines changed

31 files changed

+353
-119
lines changed

CHANGES.rst

+27
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,33 @@
1010
Changes
1111
=======
1212

13+
Version v13.0.0b2.dev5 (released 2025-03-11)
14+
15+
- dashboard: use always view button to redirect user to the upload
16+
- If upload is published redirect user to published record
17+
- If upload is draft redirect user to upload or preview depending on their permission
18+
- deposit: use permissions.can_manage for record community management
19+
- dashboard: split mine and shared with me uploads
20+
21+
Version v13.0.0b2.dev4 (released 2025-03-10)
22+
23+
- views: FAIR signposting level 1 support (config flag)
24+
- tasks: skip health checks for files that don't have a uri
25+
- views: signposting: files: fix filename encoding issues for downloads
26+
27+
Version v13.0.0b2.dev3 (released 2025-02-21)
28+
29+
- views: FAIR signposting level 1 support
30+
- meta: FAIR signposting level 1 support (link rel item)
31+
- globals: site.overrides: Increase pdf preview iframe height
32+
- tests: fix mock module paths
33+
- tests: add __init__.py in all directories
34+
* This is necessary for pytest v8.x to be able to detect all unique
35+
tests.
36+
37+
- tests: filter out excessive warnings
38+
- fix: flask changed to TRUSTED_HOSTS
39+
1340
Version v13.0.0b2.dev2 (released 2025-02-13)
1441

1542
- Bump prerelease dependencies to stable.

invenio_app_rdm/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
#
1818
# See PEP 0440 for details - https://www.python.org/dev/peps/pep-0440
1919

20-
__version__ = "13.0.0b2.dev2"
20+
__version__ = "13.0.0b2.dev5"
2121

2222
__all__ = ("__version__",)

invenio_app_rdm/config.py

+2
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,8 @@ def github_link_render(record):
964964

965965
APP_RDM_RECORD_LANDING_PAGE_TEMPLATE = "invenio_app_rdm/records/detail.html"
966966

967+
APP_RDM_RECORD_LANDING_PAGE_FAIR_SIGNPOSTING_LEVEL_1_ENABLED = False
968+
967969
APP_RDM_RECORD_THUMBNAIL_SIZES = [10, 50, 100, 250, 750, 1200]
968970
"""Allowed record thumbnail sizes."""
969971

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
{%- set title = record.metadata.title %}
2626
{%- set metadata = record.metadata %}
2727

28-
{%- set can_manage_record = permissions is defined and (permissions.can_edit or permissions.can_review) %}
28+
{%- set can_curate_record = permissions is defined and (permissions.can_edit or permissions.can_review) %}
2929

3030
<!-- preview_submission_request is set to true when coming from a community submission request -->
3131
{%- set is_preview_submission_request = preview_submission_request or false %}
32-
{%- set show_record_management_menu = can_manage_record and (not is_preview or is_preview_submission_request) %}
32+
{%- set show_record_management_menu = can_curate_record and (not is_preview or is_preview_submission_request) %}
3333

3434
{%- if record.parent.access.settings %}
3535
{%- set allow_user_requests = not current_user.is_anonymous and record.parent.access.settings.allow_user_requests %}
@@ -175,7 +175,7 @@
175175

176176
{%- block record_header_button -%}
177177

178-
{% if is_preview and not is_preview_submission_request and can_manage_record and is_draft %}
178+
{% if is_preview and not is_preview_submission_request and can_curate_record and is_draft %}
179179
<nav class="back-navigation rel-pb-2 pl-0"
180180
aria-label="{{ _('Back-navigation') }}">
181181
{%- set back_page = url_for('invenio_app_rdm_records.deposit_edit', pid_value=record.id) -%}

invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/meta.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{#
2-
Copyright (C) 2020-2024 CERN.
2+
Copyright (C) 2020-2025 CERN.
33
Copyright (C) 2020 Northwestern University.
44
Copyright (C) 2021 New York University.
55
Copyright (C) 2023 Front Matter.
@@ -28,6 +28,8 @@
2828
<meta name="citation_pdf_url" content="{{ file_url }}"/>
2929
{%- endif %}
3030
<link rel="alternate" type="{{ file.mimetype }}" href="{{ file_url }}">
31+
{#- See https://signposting.org/FAIR/ #}
32+
<link rel="item" type="{{ file.mimetype }}" href="{{ file_url }}">
3133
{%- endfor %}
3234
{% endif %}
3335

invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/communities.html

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
data-record-community-endpoint="{{ record.links.communities }}"
55
data-record-community-search-endpoint="{{ record.links['communities-suggestions'] }}"
66
data-record-user-community-search-endpoint="{{ record.links['user-communities-suggestions'] }}"
7-
data-can-manage-record='{{ can_manage_record |tojson }}'
87
data-pending-communities-search-config='{{ search_app_rdm_record_requests_config(app_id="InvenioAppRdm.RecordRequests", endpoint=record.links.requests) | tojson }}'
98
data-record-community-search-config='{{ search_app_rdm_record_communities_config(app_id="InvenioAppRdm.RecordCommunitiesSuggestions", endpoint=record.links["communities-suggestions"]) | tojson }}'
109
data-record-user-community-search-config='{{ search_app_rdm_record_user_communities_config(app_id="InvenioAppRdm.RecordUserCommunitiesSuggestions", endpoint=record.links["communities-suggestions"]) | tojson }}'

invenio_app_rdm/records_ui/views/decorators.py

+91-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2019-2024 CERN.
3+
# Copyright (C) 2019-2025 CERN.
44
# Copyright (C) 2019-2021 Northwestern University.
55
# Copyright (C) 2021 TU Wien.
66
#
@@ -11,14 +11,17 @@
1111

1212
from functools import wraps
1313

14-
from flask import g, make_response, redirect, request, session, url_for
14+
from flask import current_app, g, make_response, redirect, request, session, url_for
1515
from flask_login import login_required
1616
from invenio_communities.communities.resources.serializer import (
1717
UICommunityJSONSerializer,
1818
)
1919
from invenio_communities.proxies import current_communities
2020
from invenio_pidstore.errors import PIDDoesNotExistError
2121
from invenio_rdm_records.proxies import current_rdm_records
22+
from invenio_rdm_records.resources.serializers.signposting import (
23+
FAIRSignpostingProfileLvl1Serializer,
24+
)
2225
from invenio_records_resources.services.errors import PermissionDeniedError
2326
from sqlalchemy.orm.exc import NoResultFound
2427

@@ -365,20 +368,100 @@ def view(**kwargs):
365368
return view
366369

367370

368-
def add_signposting(f):
369-
"""Add signposting link to view's response headers."""
371+
def _get_header(rel, value, link_type=None):
372+
header = f'<{value}> ; rel="{rel}"'
373+
if link_type:
374+
header += f' ; type="{link_type}"'
375+
return header
376+
377+
378+
def _get_signposting_collection(pid_value):
379+
ui_url = record_url_for(pid_value=pid_value)
380+
return _get_header("collection", ui_url, "text/html")
381+
382+
383+
def _get_signposting_describes(pid_value):
384+
ui_url = record_url_for(pid_value=pid_value)
385+
return _get_header("describes", ui_url, "text/html")
386+
387+
388+
def _get_signposting_linkset(pid_value):
389+
api_url = record_url_for(_app="api", pid_value=pid_value)
390+
return _get_header("linkset", api_url, "application/linkset+json")
391+
392+
393+
def add_signposting_landing_page(f):
394+
"""Add signposting links to the landing page view's response headers."""
395+
396+
@wraps(f)
397+
def view(*args, **kwargs):
398+
response = make_response(f(*args, **kwargs))
399+
400+
# Relies on other decorators having operated before it
401+
if current_app.config[
402+
"APP_RDM_RECORD_LANDING_PAGE_FAIR_SIGNPOSTING_LEVEL_1_ENABLED"
403+
]:
404+
record = kwargs["record"]
405+
406+
signposting_headers = (
407+
FAIRSignpostingProfileLvl1Serializer().serialize_object(
408+
record.to_dict()
409+
)
410+
)
411+
412+
response.headers["Link"] = signposting_headers
413+
else:
414+
pid_value = kwargs["pid_value"]
415+
signposting_link = record_url_for(_app="api", pid_value=pid_value)
416+
417+
response.headers["Link"] = (
418+
f'<{signposting_link}> ; rel="linkset" ; type="application/linkset+json"' # fmt: skip
419+
)
420+
421+
return response
422+
423+
return view
424+
425+
426+
def add_signposting_content_resources(f):
427+
"""Add signposting links to the content resources view's response headers."""
370428

371429
@wraps(f)
372430
def view(*args, **kwargs):
373431
response = make_response(f(*args, **kwargs))
374432

375433
# Relies on other decorators having operated before it
376434
pid_value = kwargs["pid_value"]
377-
signposting_link = record_url_for(_app="api", pid_value=pid_value)
378435

379-
response.headers["Link"] = (
380-
f'<{signposting_link}> ; rel="linkset" ; type="application/linkset+json"' # fmt: skip
381-
)
436+
signposting_headers = [
437+
_get_signposting_collection(pid_value),
438+
_get_signposting_linkset(pid_value),
439+
]
440+
441+
response.headers["Link"] = " , ".join(signposting_headers)
442+
443+
return response
444+
445+
return view
446+
447+
448+
def add_signposting_metadata_resources(f):
449+
"""Add signposting links to the metadata resources view's response headers."""
450+
451+
@wraps(f)
452+
def view(*args, **kwargs):
453+
response = make_response(f(*args, **kwargs))
454+
455+
# Relies on other decorators having operated before it
456+
pid_value = kwargs["pid_value"]
457+
458+
signposting_headers = [
459+
_get_signposting_describes(pid_value),
460+
_get_signposting_linkset(pid_value),
461+
]
462+
463+
response.headers["Link"] = " , ".join(signposting_headers)
464+
382465
return response
383466

384467
return view

invenio_app_rdm/records_ui/views/deposits.py

+6
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ def deposit_create(community=None):
444444
.get("doi", {})
445445
.get("required")
446446
)
447+
447448
return render_community_theme_template(
448449
current_app.config["APP_RDM_DEPOSIT_FORM_TEMPLATE"],
449450
theme=community_theme,
@@ -483,7 +484,12 @@ def deposit_edit(pid_value, draft=None, draft_files=None, files_locked=True):
483484
can_edit_draft = service.check_permission(
484485
g.identity, "update_draft", record=draft._record
485486
)
487+
can_preview_draft = service.check_permission(
488+
g.identity, "preview", record=draft._record
489+
)
486490
if not can_edit_draft:
491+
if can_preview_draft:
492+
return redirect(draft["links"]["preview_html"])
487493
raise PermissionDeniedError()
488494

489495
files_dict = None if draft_files is None else draft_files.to_dict()

invenio_app_rdm/records_ui/views/records.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2019-2024 CERN.
3+
# Copyright (C) 2019-2025 CERN.
44
# Copyright (C) 2019-2021 Northwestern University.
55
# Copyright (C) 2021-2023 TU Wien.
66
#
@@ -39,7 +39,9 @@
3939

4040
from ..utils import get_external_resources
4141
from .decorators import (
42-
add_signposting,
42+
add_signposting_content_resources,
43+
add_signposting_landing_page,
44+
add_signposting_metadata_resources,
4345
pass_file_item,
4446
pass_file_metadata,
4547
pass_include_deleted,
@@ -141,7 +143,7 @@ def open(self):
141143
@pass_record_or_draft(expand=True)
142144
@pass_record_files
143145
@pass_record_media_files
144-
@add_signposting
146+
@add_signposting_landing_page
145147
def record_detail(
146148
pid_value, record, files, media_files, is_preview=False, include_deleted=False
147149
):
@@ -263,6 +265,7 @@ def record_detail(
263265

264266
@pass_is_preview
265267
@pass_record_or_draft(expand=False)
268+
@add_signposting_metadata_resources
266269
def record_export(
267270
pid_value, record, export_format=None, permissions=None, is_preview=False
268271
):
@@ -325,7 +328,7 @@ def record_file_preview(
325328

326329
@pass_is_preview
327330
@pass_file_item(is_media=False)
328-
@add_signposting
331+
@add_signposting_content_resources
329332
def record_file_download(pid_value, file_item=None, is_preview=False, **kwargs):
330333
"""Download a file from a record."""
331334
download = bool(request.args.get("download"))

invenio_app_rdm/tasks.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
def file_integrity_report():
1919
"""Send a report of uhealthy/missing files to system admins."""
2020
# First retry verifying files that errored during their last check
21-
files = FileInstance.query.filter(FileInstance.last_check.is_(None))
21+
files = FileInstance.query.filter(
22+
FileInstance.last_check.is_(None),
23+
FileInstance.uri.is_not(None),
24+
)
2225
for f in files:
2326
try:
2427
f.clear_last_check()
@@ -32,7 +35,8 @@ def file_integrity_report():
3235
FileInstance.query.filter(
3336
sa.or_(
3437
FileInstance.last_check.is_(None), FileInstance.last_check.is_(False)
35-
)
38+
),
39+
FileInstance.uri.is_not(None),
3640
)
3741
.order_by(FileInstance.created.desc())
3842
.all()

invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/CompareRevisionsDropdown.js

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* // This file is part of Invenio-App-Rdm
33
* // Copyright (C) 2025 CERN.
4+
* // Copyright (C) 2025 Graz University of Technology.
45
* //
56
* // Invenio-App-Rdm is free software; you can redistribute it and/or modify it
67
* // under the terms of the MIT License; see LICENSE file for more details.
@@ -81,3 +82,8 @@ CompareRevisionsDropdown.propTypes = {
8182
srcRevision: PropTypes.object,
8283
targetRevision: PropTypes.object,
8384
};
85+
86+
CompareRevisionsDropdown.defaultProps = {
87+
srcRevision: 0,
88+
targetRevision: 0,
89+
};

invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/RevisionsDiffViewer.js

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* // This file is part of Invenio-App-Rdm
33
* // Copyright (C) 2025 CERN.
4+
* // Copyright (C) 2025 Graz University of Technology.
45
* //
56
* // Invenio-App-Rdm is free software; you can redistribute it and/or modify it
67
* // under the terms of the MIT License; see LICENSE file for more details.
@@ -75,3 +76,7 @@ RevisionsDiffViewer.propTypes = {
7576
diff: PropTypes.object,
7677
viewerProps: PropTypes.object.isRequired,
7778
};
79+
80+
RevisionsDiffViewer.defaultProps = {
81+
diff: {},
82+
};

invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/records/CompareRevisions.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* // This file is part of Invenio-App-Rdm
33
* // Copyright (C) 2025 CERN.
4+
* // Copyright (C) 2025 Graz University of Technology.
45
* //
56
* // Invenio-App-Rdm is free software; you can redistribute it and/or modify it
67
* // under the terms of the MIT License; see LICENSE file for more details.
@@ -28,6 +29,14 @@ export class CompareRevisions extends Component {
2829
};
2930
}
3031

32+
componentDidMount() {
33+
this.fetchRevisions();
34+
}
35+
36+
componentWillUnmount() {
37+
this.cancellableAction && this.cancellableAction.cancel();
38+
}
39+
3140
async fetchRevisions() {
3241
const { resource } = this.props;
3342
this.setState({ loading: true });
@@ -50,14 +59,6 @@ export class CompareRevisions extends Component {
5059
}
5160
}
5261

53-
componentDidMount() {
54-
this.fetchRevisions();
55-
}
56-
57-
componentWillUnmount() {
58-
this.cancellableAction && this.cancellableAction.cancel();
59-
}
60-
6162
handleModalClose = () => {
6263
const { actionCancelCallback } = this.props;
6364
actionCancelCallback();
@@ -100,7 +101,7 @@ export class CompareRevisions extends Component {
100101
</Modal.Content>
101102
)}
102103
<Modal.Content scrolling>
103-
<RevisionsDiffViewer diff={this.state.diff} />
104+
<RevisionsDiffViewer diff={diff} />
104105
</Modal.Content>
105106
</Modal.Content>
106107
<Modal.Actions>

0 commit comments

Comments
 (0)