invenio-app-rdm 13.0.0b3.dev5__py2.py3-none-any.whl → 13.0.0b3.dev7__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- invenio_app_rdm/__init__.py +1 -1
- invenio_app_rdm/administration/audit_logs/__init__.py +12 -0
- invenio_app_rdm/administration/audit_logs/audit_logs.py +77 -0
- invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/audit_logs.html +14 -0
- invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/details.html +2 -2
- invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/detail.html +9 -0
- invenio_app_rdm/records_ui/views/__init__.py +2 -0
- invenio_app_rdm/records_ui/views/decorators.py +10 -7
- invenio_app_rdm/requests_ui/views/requests.py +6 -3
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/ViewAction.js +0 -0
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/index.js +29 -0
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/search/SearchResultItemLayout.js +71 -0
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/search/index.js +9 -0
- invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js +1 -1
- invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/files_integrity_report/email/files_integrity_report.html +10 -11
- invenio_app_rdm/theme/webpack.py +1 -0
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/METADATA +20 -6
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/RECORD +27 -20
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/WHEEL +1 -1
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/entry_points.txt +1 -0
- tests/conftest.py +0 -41
- tests/mock_module/templates/mock_mail.html +3 -4
- tests/test_tasks.py +121 -16
- tests/ui/conftest.py +17 -5
- tests/ui/test_file_download.py +73 -0
- invenio_app_rdm/urls.py +0 -72
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/licenses/LICENSE +0 -0
- {invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/top_level.txt +0 -0
invenio_app_rdm/__init__.py
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2025 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio App RDM 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
|
+
|
|
8
|
+
"""Audit logs administration module."""
|
|
9
|
+
|
|
10
|
+
from .audit_logs import AuditLogListView
|
|
11
|
+
|
|
12
|
+
__all__ = "AuditLogListView"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2025 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio App RDM 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
|
+
|
|
8
|
+
"""Invenio administration view module for audit logs."""
|
|
9
|
+
from flask import current_app
|
|
10
|
+
from invenio_administration.views.base import AdminResourceListView
|
|
11
|
+
from invenio_i18n import lazy_gettext as _
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuditLogListView(AdminResourceListView):
|
|
15
|
+
"""Audit logs admin search view."""
|
|
16
|
+
|
|
17
|
+
api_endpoint = "/audit-logs/"
|
|
18
|
+
extension_name = "invenio-audit-logs"
|
|
19
|
+
name = "audit-logs"
|
|
20
|
+
resource_config = "audit_log_resource"
|
|
21
|
+
|
|
22
|
+
title = "Audit Logs"
|
|
23
|
+
menu_label = "Audit Logs"
|
|
24
|
+
category = "Logs"
|
|
25
|
+
pid_path = "id"
|
|
26
|
+
icon = "file alternate"
|
|
27
|
+
template = "invenio_app_rdm/administration/audit_logs.html"
|
|
28
|
+
order = 1
|
|
29
|
+
search_request_headers = {"Accept": "application/vnd.inveniordm.v1+json"}
|
|
30
|
+
|
|
31
|
+
display_search = True
|
|
32
|
+
display_delete = False
|
|
33
|
+
display_create = False
|
|
34
|
+
display_edit = False
|
|
35
|
+
|
|
36
|
+
item_field_list = {
|
|
37
|
+
"id": {
|
|
38
|
+
"text": _("Log ID"),
|
|
39
|
+
"order": 1,
|
|
40
|
+
"width": 3,
|
|
41
|
+
"width": 3,
|
|
42
|
+
},
|
|
43
|
+
"resource.type": {
|
|
44
|
+
"text": _("Resource"),
|
|
45
|
+
"order": 2,
|
|
46
|
+
"width": 2,
|
|
47
|
+
},
|
|
48
|
+
"resource.id": { # Link to resource in the `resource_type` admin panel
|
|
49
|
+
"text": _("Resource ID"),
|
|
50
|
+
"order": 3,
|
|
51
|
+
"width": 2,
|
|
52
|
+
},
|
|
53
|
+
"action": {
|
|
54
|
+
"text": _("Action"),
|
|
55
|
+
"order": 4,
|
|
56
|
+
"width": 2,
|
|
57
|
+
},
|
|
58
|
+
"user.id": { # Link to user in user admin panel
|
|
59
|
+
"text": _("User"),
|
|
60
|
+
"order": 5,
|
|
61
|
+
"width": 3,
|
|
62
|
+
},
|
|
63
|
+
"created": {
|
|
64
|
+
"text": _("Timestamp"),
|
|
65
|
+
"order": 6,
|
|
66
|
+
"width": 7,
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
search_config_name = "AUDIT_LOGS_SEARCH"
|
|
71
|
+
search_facets_config_name = "AUDIT_LOGS_FACETS"
|
|
72
|
+
search_sort_config_name = "AUDIT_LOGS_SORT_OPTIONS"
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def disabled():
|
|
76
|
+
"""Disable the view on demand."""
|
|
77
|
+
return not current_app.config["AUDIT_LOGS_ENABLED"]
|
invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/audit_logs.html
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{#
|
|
2
|
+
Copyright (C) 2025 CERN.
|
|
3
|
+
|
|
4
|
+
Invenio App RDM is free software; you can redistribute it and/or modify it
|
|
5
|
+
under the terms of the MIT License; see LICENSE file for more details.
|
|
6
|
+
#}
|
|
7
|
+
|
|
8
|
+
{% extends "invenio_administration/search.html" %}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
{% block javascript %}
|
|
12
|
+
{{ super() }}
|
|
13
|
+
{{ webpack['invenio-audit-logs-administration.js'] }}
|
|
14
|
+
{% endblock %}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
#}
|
|
10
10
|
|
|
11
11
|
{%- from "invenio_app_rdm/records/macros/detail.html" import
|
|
12
|
-
list_languages, show_dates, show_detail, show_detail_conference %}
|
|
12
|
+
list_languages, show_dates, show_detail, show_detail_conference, show_detail_thesis %}
|
|
13
13
|
|
|
14
14
|
{%- set id_doi = record.pids.get('doi', {}).get('identifier') %}
|
|
15
15
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{{ show_detail(_('Publisher'), metadata.publisher) if metadata.publisher }}
|
|
27
27
|
{{ show_detail(_('Published in'), record.ui.publishing_information.journal) if record.ui.get('publishing_information', {}).get('journal') }}
|
|
28
28
|
{{ show_detail(_('Imprint'), record.ui.publishing_information.imprint) if record.ui.get('publishing_information', {}).get('imprint') }}
|
|
29
|
-
{{
|
|
29
|
+
{{ show_detail_thesis(_('Thesis'), record.ui.publishing_information.thesis) if record.ui.get('publishing_information', {}).get('thesis', {}) }}
|
|
30
30
|
{{ show_detail(_('Conference'), show_detail_conference(record.ui.conference)) if record.ui.conference }}
|
|
31
31
|
{{ show_detail(_('Languages'), list_languages(record.ui.languages)) if record.ui.languages }}
|
|
32
32
|
{{ show_detail(_('Formats'), ", ".join(metadata.formats)) if metadata.formats }}
|
|
@@ -309,3 +309,12 @@
|
|
|
309
309
|
class="fa fa-external-link"></i> {{ _('Conference website') }}</a></dd>
|
|
310
310
|
{%- endif %}
|
|
311
311
|
{% endmacro %}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
{% macro show_detail_thesis(title, thesis) %}
|
|
315
|
+
<dt class="ui tiny header">
|
|
316
|
+
{{ title }}
|
|
317
|
+
</dt>
|
|
318
|
+
<dd>{{ thesis | safe }}
|
|
319
|
+
</dd>
|
|
320
|
+
{% endmacro %}
|
|
@@ -22,6 +22,7 @@ from invenio_records_resources.services.errors import (
|
|
|
22
22
|
PermissionDeniedError,
|
|
23
23
|
RecordPermissionDeniedError,
|
|
24
24
|
)
|
|
25
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
25
26
|
|
|
26
27
|
from invenio_app_rdm.views import create_url_rule
|
|
27
28
|
|
|
@@ -161,6 +162,7 @@ def create_blueprint(app):
|
|
|
161
162
|
blueprint.register_error_handler(PIDUnregistered, not_found_error)
|
|
162
163
|
blueprint.register_error_handler(KeyError, not_found_error)
|
|
163
164
|
blueprint.register_error_handler(FileKeyNotFoundError, not_found_error)
|
|
165
|
+
blueprint.register_error_handler(NoResultFound, not_found_error)
|
|
164
166
|
blueprint.register_error_handler(DraftNotCreatedError, draft_not_found_error)
|
|
165
167
|
blueprint.register_error_handler(
|
|
166
168
|
PermissionDeniedError, record_permission_denied_error
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
#
|
|
3
3
|
# Copyright (C) 2019-2025 CERN.
|
|
4
|
-
# Copyright (C) 2019-
|
|
4
|
+
# Copyright (C) 2019-2025 Northwestern University.
|
|
5
5
|
# Copyright (C) 2021 TU Wien.
|
|
6
6
|
#
|
|
7
7
|
# Invenio App RDM is free software; you can redistribute it and/or modify it
|
|
@@ -13,6 +13,7 @@ from functools import wraps
|
|
|
13
13
|
|
|
14
14
|
from flask import current_app, g, make_response, redirect, request, session, url_for
|
|
15
15
|
from flask_login import login_required
|
|
16
|
+
from invenio_base import invenio_url_for
|
|
16
17
|
from invenio_communities.communities.resources.serializer import (
|
|
17
18
|
UICommunityJSONSerializer,
|
|
18
19
|
)
|
|
@@ -25,8 +26,6 @@ from invenio_rdm_records.resources.serializers.signposting import (
|
|
|
25
26
|
from invenio_records_resources.services.errors import PermissionDeniedError
|
|
26
27
|
from sqlalchemy.orm.exc import NoResultFound
|
|
27
28
|
|
|
28
|
-
from invenio_app_rdm.urls import record_url_for
|
|
29
|
-
|
|
30
29
|
|
|
31
30
|
def service():
|
|
32
31
|
"""Get the record service."""
|
|
@@ -376,17 +375,21 @@ def _get_header(rel, value, link_type=None):
|
|
|
376
375
|
|
|
377
376
|
|
|
378
377
|
def _get_signposting_collection(pid_value):
|
|
379
|
-
ui_url =
|
|
378
|
+
ui_url = invenio_url_for(
|
|
379
|
+
"invenio_app_rdm_records.record_detail", pid_value=pid_value
|
|
380
|
+
)
|
|
380
381
|
return _get_header("collection", ui_url, "text/html")
|
|
381
382
|
|
|
382
383
|
|
|
383
384
|
def _get_signposting_describes(pid_value):
|
|
384
|
-
ui_url =
|
|
385
|
+
ui_url = invenio_url_for(
|
|
386
|
+
"invenio_app_rdm_records.record_detail", pid_value=pid_value
|
|
387
|
+
)
|
|
385
388
|
return _get_header("describes", ui_url, "text/html")
|
|
386
389
|
|
|
387
390
|
|
|
388
391
|
def _get_signposting_linkset(pid_value):
|
|
389
|
-
api_url =
|
|
392
|
+
api_url = invenio_url_for("records.read", pid_value=pid_value)
|
|
390
393
|
return _get_header("linkset", api_url, "application/linkset+json")
|
|
391
394
|
|
|
392
395
|
|
|
@@ -412,7 +415,7 @@ def add_signposting_landing_page(f):
|
|
|
412
415
|
response.headers["Link"] = signposting_headers
|
|
413
416
|
else:
|
|
414
417
|
pid_value = kwargs["pid_value"]
|
|
415
|
-
signposting_link =
|
|
418
|
+
signposting_link = invenio_url_for("records.read", pid_value=pid_value)
|
|
416
419
|
|
|
417
420
|
response.headers["Link"] = (
|
|
418
421
|
f'<{signposting_link}> ; rel="linkset" ; type="application/linkset+json"' # fmt: skip
|
|
@@ -352,7 +352,8 @@ def community_dashboard_request_view(request, community, community_ui, **kwargs)
|
|
|
352
352
|
base_template="invenio_communities/details/base.html",
|
|
353
353
|
invenio_request=request.to_dict(),
|
|
354
354
|
record=record_ui,
|
|
355
|
-
community=
|
|
355
|
+
community=community,
|
|
356
|
+
community_ui=community_ui,
|
|
356
357
|
checks=checks,
|
|
357
358
|
permissions=permissions,
|
|
358
359
|
is_preview=is_draft, # preview only when draft
|
|
@@ -376,7 +377,8 @@ def community_dashboard_request_view(request, community, community_ui, **kwargs)
|
|
|
376
377
|
theme=community.to_dict().get("theme", {}),
|
|
377
378
|
base_template="invenio_communities/details/members/base.html",
|
|
378
379
|
invenio_request=request.to_dict(),
|
|
379
|
-
community=community
|
|
380
|
+
community=community,
|
|
381
|
+
community_ui=community_ui,
|
|
380
382
|
permissions=permissions,
|
|
381
383
|
request_is_accepted=request_is_accepted,
|
|
382
384
|
user_avatar=avatar,
|
|
@@ -389,7 +391,8 @@ def community_dashboard_request_view(request, community, community_ui, **kwargs)
|
|
|
389
391
|
theme=community.to_dict().get("theme", {}),
|
|
390
392
|
base_template="invenio_communities/details/base.html",
|
|
391
393
|
invenio_request=request.to_dict(),
|
|
392
|
-
community=
|
|
394
|
+
community=community,
|
|
395
|
+
community_ui=community_ui,
|
|
393
396
|
permissions=permissions,
|
|
394
397
|
request_is_accepted=request_is_accepted,
|
|
395
398
|
user_avatar=avatar,
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/ViewAction.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// This file is part of InvenioCommunities
|
|
2
|
+
// Copyright (C) 2025 CERN.
|
|
3
|
+
//
|
|
4
|
+
// Invenio RDM is free software; you can redistribute it and/or modify it
|
|
5
|
+
// under the terms of the MIT License; see LICENSE file for more details.
|
|
6
|
+
|
|
7
|
+
import { initDefaultSearchComponents } from "@js/invenio_administration";
|
|
8
|
+
import { createSearchAppInit } from "@js/invenio_search_ui";
|
|
9
|
+
import { NotificationController } from "@js/invenio_administration";
|
|
10
|
+
import { SearchResultItemLayout } from "./search";
|
|
11
|
+
import { SearchFacets } from "@js/invenio_administration";
|
|
12
|
+
|
|
13
|
+
const domContainer = document.getElementById("invenio-search-config");
|
|
14
|
+
|
|
15
|
+
const defaultComponents = initDefaultSearchComponents(domContainer);
|
|
16
|
+
|
|
17
|
+
const overridenComponents = {
|
|
18
|
+
...defaultComponents,
|
|
19
|
+
"InvenioAdministration.SearchResultItem.layout": SearchResultItemLayout,
|
|
20
|
+
"SearchApp.facets": SearchFacets,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
createSearchAppInit(
|
|
24
|
+
overridenComponents,
|
|
25
|
+
true,
|
|
26
|
+
"invenio-search-config",
|
|
27
|
+
false,
|
|
28
|
+
NotificationController
|
|
29
|
+
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Invenio.
|
|
3
|
+
* Copyright (C) 2025 CERN.
|
|
4
|
+
*
|
|
5
|
+
* Invenio 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
|
+
*/
|
|
8
|
+
|
|
9
|
+
import PropTypes from "prop-types";
|
|
10
|
+
import React, { Component } from "react";
|
|
11
|
+
import { Item, Table } from "semantic-ui-react";
|
|
12
|
+
import { Image } from "react-invenio-forms";
|
|
13
|
+
import { withState } from "react-searchkit";
|
|
14
|
+
import { i18next } from "@translations/invenio_app_rdm/i18next";
|
|
15
|
+
|
|
16
|
+
class SearchResultItemComponent extends Component {
|
|
17
|
+
componentDidMount() {
|
|
18
|
+
console.error("result", this.props.result);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
refreshAfterAction = () => {
|
|
22
|
+
const { updateQueryState, currentQueryState } = this.props;
|
|
23
|
+
updateQueryState(currentQueryState);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
const { result } = this.props;
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
id,
|
|
31
|
+
created,
|
|
32
|
+
action,
|
|
33
|
+
resource: { id: resourceId, type: resourceType },
|
|
34
|
+
user: { id: userId, email: userEmail },
|
|
35
|
+
} = result;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Table.Row>
|
|
39
|
+
<Table.Cell data-label={i18next.t("Log ID")}>
|
|
40
|
+
<a target="_blank" rel="noreferrer noopener" href={result.links.self}>
|
|
41
|
+
{id}
|
|
42
|
+
</a>
|
|
43
|
+
</Table.Cell>
|
|
44
|
+
<Table.Cell data-label={i18next.t("Resource")}>{resourceType}</Table.Cell>
|
|
45
|
+
<Table.Cell data-label={i18next.t("Resource ID")}>
|
|
46
|
+
<a href={`/administration/${resourceType}s?q=id:${resourceId}`}>
|
|
47
|
+
{resourceId}
|
|
48
|
+
</a>
|
|
49
|
+
</Table.Cell>
|
|
50
|
+
<Table.Cell data-label={i18next.t("Action")}>{action}</Table.Cell>
|
|
51
|
+
<Table.Cell data-label={i18next.t("User")}>
|
|
52
|
+
<Item className="flex" key={userId}>
|
|
53
|
+
<Image src={`/api/users/${userId}/avatar.svg`} avatar loadFallbackFirst />
|
|
54
|
+
<a href={`/administration/users?q=id:${userId}`}>
|
|
55
|
+
{userEmail} ({userId})
|
|
56
|
+
</a>
|
|
57
|
+
</Item>
|
|
58
|
+
</Table.Cell>
|
|
59
|
+
<Table.Cell data-label={i18next.t("Date")}>{created}</Table.Cell>
|
|
60
|
+
</Table.Row>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
SearchResultItemComponent.propTypes = {
|
|
66
|
+
result: PropTypes.object.isRequired,
|
|
67
|
+
updateQueryState: PropTypes.func.isRequired,
|
|
68
|
+
currentQueryState: PropTypes.object.isRequired,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const SearchResultItemLayout = withState(SearchResultItemComponent);
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/search/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Invenio.
|
|
3
|
+
* Copyright (C) 2025 CERN.
|
|
4
|
+
*
|
|
5
|
+
* Invenio 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
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { SearchResultItemLayout } from "./SearchResultItemLayout";
|
|
@@ -481,7 +481,7 @@ export class RDMDepositForm extends Component {
|
|
|
481
481
|
includesPaths={this.sectionsConfig["funding-section"]}
|
|
482
482
|
severityChecks={this.severityChecks}
|
|
483
483
|
active
|
|
484
|
-
label="Funding"
|
|
484
|
+
label={i18next.t("Funding")}
|
|
485
485
|
ui={this.accordionStyle}
|
|
486
486
|
id="funding-section"
|
|
487
487
|
>
|
|
@@ -3,30 +3,29 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Copyright (C) 2022 CERN.
|
|
5
5
|
# Copyright (C) 2024 KTH Royal Institute of Technology.
|
|
6
|
+
# Copyright (C) 2025 Northwestern University.
|
|
6
7
|
#
|
|
7
8
|
# Invenio App RDM is free software; you can redistribute it and/or modify it
|
|
8
9
|
# under the terms of the MIT License; see LICENSE file for more details.
|
|
9
10
|
-#}
|
|
10
11
|
|
|
11
|
-
{% set BASE_URL = config.SITE_UI_URL %}
|
|
12
|
-
|
|
13
12
|
{{ _("The following files were flagged as 'unhealthy'. This means that the checksum check failed or timed out. Please take any action if needed.") }}
|
|
14
13
|
|
|
15
14
|
{% for entry in entries -%}
|
|
16
|
-
{{ _("ID:
|
|
17
|
-
{{ _("URI:
|
|
15
|
+
{{ _("ID: {}").format(entry.file.id) }}
|
|
16
|
+
{{ _("URI: {}").format(entry.file.uri) }}
|
|
18
17
|
{%- if 'filename' in entry %}
|
|
19
|
-
{{ _("Name:
|
|
18
|
+
{{ _("Name: {}").format(entry.filename) }}
|
|
20
19
|
{%- endif %}
|
|
21
|
-
{{ _("Created:
|
|
22
|
-
{{ _("Checksum:
|
|
23
|
-
{{ _("Last check date:
|
|
24
|
-
{{ _("Last check FAILED with result:
|
|
20
|
+
{{ _("Created: {}").format(entry.file.created) }}
|
|
21
|
+
{{ _("Checksum: {}").format(entry.file.checksum) }}
|
|
22
|
+
{{ _("Last check date: {}").format(entry.file.last_check_at) }}
|
|
23
|
+
{{ _("Last check FAILED with result: {}").format(entry.file.last_check) }}
|
|
25
24
|
{%- if 'record' in entry %}
|
|
26
|
-
{{ _("Record:
|
|
25
|
+
{{ _("Record: {}").format(invenio_url_for("invenio_app_rdm_records.record_detail", pid_value=entry.record.id)) }}
|
|
27
26
|
{%- endif %}
|
|
28
27
|
{%- if 'draft' in entry %}
|
|
29
|
-
{{ _("Draft:
|
|
28
|
+
{{ _("Draft: {}").format(invenio_url_for("invenio_app_rdm_records.deposit_edit", pid_value=entry.draft.id)) }}
|
|
30
29
|
{%- endif %}
|
|
31
30
|
{{ "-" * 80 }}
|
|
32
31
|
{% endfor %}
|
invenio_app_rdm/theme/webpack.py
CHANGED
|
@@ -38,6 +38,7 @@ theme = WebpackThemeBundle(
|
|
|
38
38
|
"invenio-records-administration": "./js/invenio_app_rdm/administration/records/index.js",
|
|
39
39
|
"invenio-drafts-administration": "./js/invenio_app_rdm/administration/drafts/index.js",
|
|
40
40
|
"invenio-domains-administration": "./js/invenio_app_rdm/administration/domains/index.js",
|
|
41
|
+
"invenio-audit-logs-administration": "./js/invenio_app_rdm/administration/auditLogs/index.js",
|
|
41
42
|
"invenio-communities-browse": "./js/invenio_app_rdm/subcommunity/browse.js",
|
|
42
43
|
},
|
|
43
44
|
dependencies={
|
{invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: invenio-app-rdm
|
|
3
|
-
Version: 13.0.0b3.
|
|
3
|
+
Version: 13.0.0b3.dev7
|
|
4
4
|
Summary: Invenio Research Data Management.
|
|
5
5
|
Home-page: https://github.com/inveniosoftware/invenio-app-rdm
|
|
6
6
|
Author: CERN
|
|
@@ -11,8 +11,8 @@ Platform: any
|
|
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Requires-Python: >=3.7
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: invenio-app<3.0.0,>=2.
|
|
15
|
-
Requires-Dist: invenio-base<3.0.0,>=2.
|
|
14
|
+
Requires-Dist: invenio-app<3.0.0,>=2.1.0
|
|
15
|
+
Requires-Dist: invenio-base<3.0.0,>=2.1.0
|
|
16
16
|
Requires-Dist: invenio-cache<3.0.0,>=2.0.0
|
|
17
17
|
Requires-Dist: invenio-celery<3.0.0,>=2.0.0
|
|
18
18
|
Requires-Dist: invenio-config<2.0.0,>=1.0.3
|
|
@@ -40,14 +40,15 @@ Requires-Dist: invenio-search-ui<5.0.0,>=4.0.0
|
|
|
40
40
|
Requires-Dist: invenio-files-rest<4.0.0,>=3.0.0
|
|
41
41
|
Requires-Dist: invenio-previewer<4.0.0,>=3.0.0
|
|
42
42
|
Requires-Dist: invenio-records-files<2.0.0,>=1.2.1
|
|
43
|
-
Requires-Dist: invenio-communities<19.0.0,>=18.
|
|
44
|
-
Requires-Dist: invenio-rdm-records<19.0.0,>=18.
|
|
43
|
+
Requires-Dist: invenio-communities<19.0.0,>=18.2.0
|
|
44
|
+
Requires-Dist: invenio-rdm-records<19.0.0,>=18.4.0
|
|
45
45
|
Requires-Dist: CairoSVG<3.0.0,>=2.5.2
|
|
46
46
|
Requires-Dist: invenio-banners<5.0.0,>=4.0.0
|
|
47
47
|
Requires-Dist: invenio-pages<6.0.0,>=5.0.0
|
|
48
|
+
Requires-Dist: invenio-audit-logs<1.0.0,>=0.1.0
|
|
48
49
|
Provides-Extra: tests
|
|
49
50
|
Requires-Dist: pytest-black-ng>=0.4.0; extra == "tests"
|
|
50
|
-
Requires-Dist: pytest-invenio<4.0.0,>=3.
|
|
51
|
+
Requires-Dist: pytest-invenio<4.0.0,>=3.3.0; extra == "tests"
|
|
51
52
|
Requires-Dist: Sphinx>=4.5.0; extra == "tests"
|
|
52
53
|
Provides-Extra: elasticsearch7
|
|
53
54
|
Requires-Dist: invenio-search[elasticsearch7]<4.0.0,>=3.0.0; extra == "elasticsearch7"
|
|
@@ -97,6 +98,19 @@ https://inveniordm.docs.cern.ch
|
|
|
97
98
|
Changes
|
|
98
99
|
=======
|
|
99
100
|
|
|
101
|
+
Version v13.0.0b3.dev7 (released 2025-05-08)
|
|
102
|
+
|
|
103
|
+
- fix: community request page missing context variable
|
|
104
|
+
|
|
105
|
+
Version v13.0.0b3.dev6 (released 2025-05-07)
|
|
106
|
+
|
|
107
|
+
- records-ui: add error handler for NoResultFound exceptions
|
|
108
|
+
- tests: add tests for draft file download with and without preview flag
|
|
109
|
+
- i18n: mark string for translation
|
|
110
|
+
- urls: integrate link generation (invenio_url_for)
|
|
111
|
+
- templates: add thesis details display
|
|
112
|
+
- administration: Add Audit Logs Admin Panel UI (experimental feature, behind a flag)
|
|
113
|
+
|
|
100
114
|
Version v13.0.0b3.dev5 (released 2025-04-25)
|
|
101
115
|
|
|
102
116
|
- deposit: add copyright field
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
invenio_app_rdm/__init__.py,sha256=
|
|
1
|
+
invenio_app_rdm/__init__.py,sha256=XOVVBuu5KIjDGC4Z4qFjNx_OmuljD_F20pcco0NFczQ,699
|
|
2
2
|
invenio_app_rdm/cli.py,sha256=G6QqNU2W6n6ICtTMnpeKFXIsdorncDmVXwwwsGH5F2k,2746
|
|
3
3
|
invenio_app_rdm/config.py,sha256=Sv6Q8VEP-KYNuvC6kASLOYC-gYRByYN-hwPmbCxQWKc,50624
|
|
4
4
|
invenio_app_rdm/ext.py,sha256=PkZhATGJDgYqBJQh41NdvBZWR83mgI3Eej6rj10UVJE,5278
|
|
5
5
|
invenio_app_rdm/tasks.py,sha256=FyrIQXVuPjms-dNEnLrVmmdwrX_IykJ87gcSNgOR6O0,1373
|
|
6
|
-
invenio_app_rdm/urls.py,sha256=8S95QSs4yS0rtORsd4veo--rF3LSLwZenoowJ5ubbmM,2496
|
|
7
6
|
invenio_app_rdm/views.py,sha256=SDr9NwZEWQcgT_3GFRYdDf6eUaK9DfnoafIkhUf9nSI,785
|
|
8
7
|
invenio_app_rdm/administration/__init__.py,sha256=8r9LeoE9fNHZSVS5QsCfVhRU7MAiEOWJk9MA3Y--4F8,251
|
|
8
|
+
invenio_app_rdm/administration/audit_logs/__init__.py,sha256=jsBXeKSY5YNn1juF9sFyHPYo_XYpwdP3Dye-de7cMK0,318
|
|
9
|
+
invenio_app_rdm/administration/audit_logs/audit_logs.py,sha256=vgrGQ1lLE5uSuoJCx9kIMQPshjxJzZlCZ4v5cZEcKus,2156
|
|
9
10
|
invenio_app_rdm/administration/domains/__init__.py,sha256=Qob5kqjRPxpuSE5yDV2tesN6tmaKp5JcxCxGA8Mrcak,487
|
|
10
11
|
invenio_app_rdm/administration/domains/domains.py,sha256=vafLa-mqkg_tQLjx328E64P_4mksB5kjBlsfunvdatg,5599
|
|
11
12
|
invenio_app_rdm/administration/records/__init__.py,sha256=WpNHBm_Mk9FF8GzvrXWjL79URMSgBhpqgxvrLXNooqg,434
|
|
12
13
|
invenio_app_rdm/administration/records/records.py,sha256=BFxxnB4acN8Fd3A6CWuyRUjo3bvdWmNSkcxuVZYzTaA,5357
|
|
14
|
+
invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/audit_logs.html,sha256=kLP3lfZiwLB8N-78_xINymnD8TIjGMzeJIO1a1zO130,346
|
|
13
15
|
invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/domains_search.html,sha256=NP8HPfOQPIR9psNDMFRXJH8fjok2AbXCentD_3Q1wWw,338
|
|
14
16
|
invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/user_moderation.html,sha256=koXd8lV_KBgAl1Wll7aM3xR0NgYcOl2PiFqD2Xkcp2w,348
|
|
15
17
|
invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/user_moderation_details.html,sha256=g6YZh9yWqDfzd5kMgIrO4c5k4iKa61y04RsuT_ZbMJI,350
|
|
@@ -63,7 +65,7 @@ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details
|
|
|
63
65
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/subjects.html,sha256=Wu7MCXzGj41K38-VXi-kStvc8fm3Ck68uJ1egfFK0dw,1509
|
|
64
66
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/citations.html,sha256=5Sdg_gwGOgm0qLRv4-CUmDNx7PYlOsa5XPGjDdx7k20,258
|
|
65
67
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/communities.html,sha256=GxxKbXxVg5lKcSEzVeYJXyz7qUL7yhsZnhXY3lE-vNU,1561
|
|
66
|
-
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/details.html,sha256=
|
|
68
|
+
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/details.html,sha256=Ip3wBnfpS8U9fBH2q9nZbt7znAzUKvVrbz3QkeBUMUM,1988
|
|
67
69
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/export.html,sha256=DoDrQFd_OJcJzqBEQ2FRbcfJpD3TLRjESU68mBLWVyU,1392
|
|
68
70
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/external_resources.html,sha256=Ia92YMRlxuGRTMsWU4hQTLJDeRy8BX8bnSSaLXKst4Y,1934
|
|
69
71
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/keywords_subjects.html,sha256=LvsA6JiosfwSSwUUg6--3xx1OZepvN7mxQdIWyl9caE,708
|
|
@@ -74,14 +76,14 @@ invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details
|
|
|
74
76
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/technical_metadata.html,sha256=N5VUwCygKG-zXvyu0YeFJb7A0eHIcKWuMAVm9Kbrb_M,658
|
|
75
77
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/details/side_bar/versions.html,sha256=sPYG81XFcU1ND6roeYmN4SY419iyvQj9ozCv9Pctw5E,932
|
|
76
78
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/creatibutors.html,sha256=N53nwtlEZjxweCx70qFJa1s6uL1pPSzWZgk8p1vodE4,4277
|
|
77
|
-
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/detail.html,sha256=
|
|
79
|
+
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/detail.html,sha256=YEF5tR22t2QUO-tKpjsS4gKhYMZpfyjbO6wWf8LKhJw,10598
|
|
78
80
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/doi.html,sha256=NZUtJSCwQScJsmz7vxglslEVqPwG7Ldul_wl7yce0fg,1489
|
|
79
81
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/files.html,sha256=Xsq_HiM_cTGKgmoE1HAXje8iYe3d0wIJoesk22Xn7vU,8761
|
|
80
82
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/locations.html,sha256=27-KyPqb05pu-yRXHvxCgZWRSi5bFP6xf7XBn91sbeA,1741
|
|
81
83
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/stats_popup.html,sha256=5SVzfIS15Aro2Itd2BiaLbMXm0cvvwk6ZCdYjuSwhBw,625
|
|
82
84
|
invenio_app_rdm/records_ui/templates/semantic-ui/invenio_app_rdm/records/macros/version.html,sha256=eA8-n81XUezkwPXvcG5v2sgLPQNTgr7hB36-_Gr-tVI,758
|
|
83
|
-
invenio_app_rdm/records_ui/views/__init__.py,sha256=
|
|
84
|
-
invenio_app_rdm/records_ui/views/decorators.py,sha256=
|
|
85
|
+
invenio_app_rdm/records_ui/views/__init__.py,sha256=9DaDls04IQv7fYttDjLofIWGsRRjk-FwUYnIfxV3OWk,5840
|
|
86
|
+
invenio_app_rdm/records_ui/views/decorators.py,sha256=MUUmgGuigmFMigcpyJbNvM0yPKUyeAw5LE6MJ69BoFA,15883
|
|
85
87
|
invenio_app_rdm/records_ui/views/deposits.py,sha256=KRR_fpl98EhNZie0Q-_uZtgG2QKsQAW2fhb-kvnQ4s4,21561
|
|
86
88
|
invenio_app_rdm/records_ui/views/filters.py,sha256=Rm55fXJv97cqq8B_6KCe-3PxxHUH4VRu-jd9fTea6r4,6994
|
|
87
89
|
invenio_app_rdm/records_ui/views/records.py,sha256=GdxG3JnXrV1QT0KxOqeYWoDGIiZRZ9w5poihPPd-wTo,16428
|
|
@@ -99,13 +101,17 @@ invenio_app_rdm/requests_ui/templates/semantic-ui/invenio_requests/subcommunity/
|
|
|
99
101
|
invenio_app_rdm/requests_ui/templates/semantic-ui/invenio_requests/subcommunity-invitation/index.html,sha256=347Saf8Fv78uevCbK2nFiOtNFUT0QyZSZS7lgoNzHdQ,1448
|
|
100
102
|
invenio_app_rdm/requests_ui/templates/semantic-ui/invenio_requests/user-access-request/index.html,sha256=ltSP9sYPnpmCKMDYpZYU25Wxr3Dfqe2RNDxm6bVjX_I,1779
|
|
101
103
|
invenio_app_rdm/requests_ui/views/__init__.py,sha256=7QiAyRq8Eu84IXwjzxK63vNeTZnowZ5P85xtw7XgRjs,397
|
|
102
|
-
invenio_app_rdm/requests_ui/views/requests.py,sha256=
|
|
104
|
+
invenio_app_rdm/requests_ui/views/requests.py,sha256=Ww3ewDciAvcrheOwtirS6Qewj21FQ8R1b42Og0_r_3w,16149
|
|
103
105
|
invenio_app_rdm/requests_ui/views/ui.py,sha256=DBysYQa__gOCg-pikO6HmoVLmRmMAVWeTBiYhPa7PmA,2359
|
|
104
106
|
invenio_app_rdm/theme/__init__.py,sha256=QbkxNjjOmGKRlie96HfTXgnFeVQjOX0GdiZnHP7pIhs,277
|
|
105
107
|
invenio_app_rdm/theme/views.py,sha256=Ucn6o7mF8qR7gtOeliKC73gIBhy5LgY65rvteC1Uiog,4312
|
|
106
|
-
invenio_app_rdm/theme/webpack.py,sha256=
|
|
108
|
+
invenio_app_rdm/theme/webpack.py,sha256=5oi0YBD84y8246JYGtSNmNbRUH-bz_G8WrSRRDEyplw,5201
|
|
107
109
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/theme.js,sha256=LSswk1IkVgUxTT3Arw_QF-mNQ16vVYDf2B90h6FZfFw,4431
|
|
108
110
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/utils.js,sha256=oTCQkmr7j6FwVsOfM6hsKrPHfadW7m9IurrqYVDgxDw,3628
|
|
111
|
+
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/ViewAction.js,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
112
|
+
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/index.js,sha256=7glSWacd986Zu6l_Ob7IXp4uNWA0f51FBfRv4HZxjYU,965
|
|
113
|
+
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/search/SearchResultItemLayout.js,sha256=wXwMfu8u02A3KT_xZbalntDGvLwVFc9AlorUTuiSqdQ,2268
|
|
114
|
+
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/auditLogs/search/index.js,sha256=q1WaQ-kNNMvNdnsONMw2c4GWobizoPWsmIdWL2fRCPc,283
|
|
109
115
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/CompareRevisionsDropdown.js,sha256=BNdMxfFYPhlrGKPg47oc4X8ILllfCngN61L1b7Yt_8Q,2483
|
|
110
116
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/ImpersonateUser.js,sha256=1tnHc9PaCQvVS1PVsDWtfpWzVxJJ5_eltn9WJEYygiY,2366
|
|
111
117
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/ImpersonateUserForm.js,sha256=Z21KrMyAJ1rKF5IEzM088-pTvTga21LBnG4GPYvh5g4,6890
|
|
@@ -160,7 +166,7 @@ invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/CopyButto
|
|
|
160
166
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/DisplayPartOfCommunities.js,sha256=bSmhuwSWk4CW80mqa4ZZbjfa-_NsiJ1IxQ9veDy6sAM,2751
|
|
161
167
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/DisplayVerifiedCommunity.js,sha256=m3rT8jJ3440ZX22zZog8bHatWltYXwvmw_tu6tJUM9k,1506
|
|
162
168
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/components/RecordsResultsListItem.js,sha256=RTSQBlGQY7ww7fVGHDvDfWQNyJ07mnEoyboTGIcCgD4,6694
|
|
163
|
-
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js,sha256=
|
|
169
|
+
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/RDMDepositForm.js,sha256=92Mg5PAjOHZ8pMNHJjyqdHMXLXuaAF6FT12UTJzy9XQ,32295
|
|
164
170
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/ShareDraftButton.js,sha256=ICMV4Ixe-nTe6q7COZ0oyAQf2nVp2cez_-iUZobwUD0,1998
|
|
165
171
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/config.js,sha256=a9Im0S72ne6LGDzM8C-pP9fIhcMihIbOJ5Ez5SwSn9A,1456
|
|
166
172
|
invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/deposit/index.js,sha256=gA0BaUFpaJr9nkmHSWoxuwKDfSD3JUTPcadj2TKHN24,1587
|
|
@@ -374,7 +380,7 @@ invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/page.html,sha256=zwI
|
|
|
374
380
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/page_cover.html,sha256=D-NNfCX38wRjHOq1kzPPncKKUd0b9U1al-NMy48dKvU,357
|
|
375
381
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/searchbar.html,sha256=tvzez_2CE86wl_lipD44MD1swZcZw5uYqXEvvPMkBIo,2222
|
|
376
382
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/site_footer.html,sha256=C0xluZe7KCkvRKeeMIt6P8v_EfWyuMCQ_JQvlI0M9Xw,1037
|
|
377
|
-
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/files_integrity_report/email/files_integrity_report.html,sha256=
|
|
383
|
+
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/files_integrity_report/email/files_integrity_report.html,sha256=mwbLrf2xabxq0dLQzUNWGHeYVoySo9GaaydT-FKC9g8,1237
|
|
378
384
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/help/search.de.html,sha256=gefXaGv-ylkBUbvXXJe5EcTS66qoY0-v0XesXICX5_E,9310
|
|
379
385
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/help/search.en.html,sha256=-EZdjhc4JslSq37_QN3KRL01LBwLJENkRtwBJ-PLSzc,8792
|
|
380
386
|
invenio_app_rdm/theme/templates/semantic-ui/invenio_app_rdm/help/search.sv.html,sha256=PHSLAuYtRTtsDgArshe5SIDs_M-dw8MUrSIrnNky2gw,9123
|
|
@@ -469,10 +475,10 @@ invenio_app_rdm/users_ui/views/__init__.py,sha256=SMdY2NJj9GICfr3Xuok7qdNYVtA2bJ
|
|
|
469
475
|
invenio_app_rdm/users_ui/views/dashboard.py,sha256=iUn2PrODAwb8ugmMosJKAjPhUzjCiWiAWoXQr9RUFuc,1793
|
|
470
476
|
invenio_app_rdm/users_ui/views/ui.py,sha256=W_eXM8dLVIrNHQB2UEh37C9BYoHauft6RyvcDNFHovA,1742
|
|
471
477
|
invenio_app_rdm/utils/files.py,sha256=CruDyO2gDVadSlWEJD-WHpWHeOQ0juh-Ei9jz3D9yjc,3923
|
|
472
|
-
invenio_app_rdm-13.0.0b3.
|
|
478
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/licenses/LICENSE,sha256=AZXFHRrZa5s4m9DV7zZr4bPGTMUvcEPCodeV_AmFI8k,1204
|
|
473
479
|
tests/__init__.py,sha256=yKVf0yYRuxmXvyAtLjmfpHGVCsEkZOhs_FojAAM_w-8,244
|
|
474
|
-
tests/conftest.py,sha256=
|
|
475
|
-
tests/test_tasks.py,sha256=
|
|
480
|
+
tests/conftest.py,sha256=FQ_aSBxGo0gNfV64RJ117GcmgjVbZKwpxF9_3VNdNJY,7931
|
|
481
|
+
tests/test_tasks.py,sha256=YAf2mryFK6Vfzk2053XLBA2e92vbNCTWqJ6ThWhGOuQ,6645
|
|
476
482
|
tests/test_utils.py,sha256=nvj59DibjRZgLzwnch83tyCw9R1DEuDSQhU7v7mEOT0,1897
|
|
477
483
|
tests/test_version.py,sha256=c_ayM-WLlD0Q6z939sBnFpMTY160TmFg-9-hGsPa7FE,410
|
|
478
484
|
tests/test_views.py,sha256=Q0mSOqd6xVrAxQMdc0MAdZRUnxv7gFAkKcBQY-gQtUI,1420
|
|
@@ -490,20 +496,21 @@ tests/fixtures/app_data/pages.yaml,sha256=t4pyjwMBVI6MxEkwCtg9urMXo5fh0mzWy-Zr8N
|
|
|
490
496
|
tests/fixtures/app_data/pages/about.html,sha256=obB_g3uL1ligwguh0a0-tRLRBB-eGXN1NE-3odp2j-E,11
|
|
491
497
|
tests/mock_module/__init__.py,sha256=gu6vRcXqYTKCXZjvAIHZRv2w1IvpGiDs7atQJbij5M0,236
|
|
492
498
|
tests/mock_module/views.py,sha256=TWJQfcql5XaBNtdR9phVl4tHB0YG6g5IG5n08VZTzXE,770
|
|
493
|
-
tests/mock_module/templates/mock_mail.html,sha256=
|
|
499
|
+
tests/mock_module/templates/mock_mail.html,sha256=w7eiZbbs1gErCXelGN7NeiTavcDM9yUM702Mygz0oAc,943
|
|
494
500
|
tests/redirector/__init__.py,sha256=yKVf0yYRuxmXvyAtLjmfpHGVCsEkZOhs_FojAAM_w-8,244
|
|
495
501
|
tests/redirector/conftest.py,sha256=KAbp0R8tgGoNvMr8mJ1G2AZX6PzLw-PChtbucrLn5_o,1676
|
|
496
502
|
tests/redirector/test_redirector.py,sha256=iATYglIw3QSoUKpspQCAM4SaG_WmzjL7r1Nmew_KlGY,1002
|
|
497
503
|
tests/ui/__init__.py,sha256=yKVf0yYRuxmXvyAtLjmfpHGVCsEkZOhs_FojAAM_w-8,244
|
|
498
|
-
tests/ui/conftest.py,sha256=
|
|
504
|
+
tests/ui/conftest.py,sha256=3Msw0lfBoboQ7X-oZv_wGN7UF6StUpHPRVzRvbjhpoI,3472
|
|
499
505
|
tests/ui/test_deposits.py,sha256=BehQzo1r3_f4Uc9jcXRddd9bS5GfQ3jRRYOM0AMbi3w,3792
|
|
500
506
|
tests/ui/test_export_formats.py,sha256=pCXJCTp9ykEWb2oB-ynGjQDhFaVsOs31ym0stwfWCaQ,909
|
|
507
|
+
tests/ui/test_file_download.py,sha256=o4JHkFyJxZDaQ5NHRZR_PV98jS9UtklbOZPpduzwWKw,2436
|
|
501
508
|
tests/ui/test_filters.py,sha256=Q90wsJffjMVir7wNX8taGf2KZleLtPbXZXHLTkBpzLA,284
|
|
502
509
|
tests/ui/test_signposting_ui.py,sha256=KCSjQlMD2VKlwQCyZYDwYjtVNL35x3u-ZC4ceD5y21w,3847
|
|
503
510
|
tests/ui/test_static.py,sha256=vO3OQAOhrQESJifnQfM1pw7JYz3J874O8BAb7Cc_PPA,868
|
|
504
511
|
tests/ui/test_stats_ui.py,sha256=LHa_0hjvpYvliSk_jknWy-90CO82jVElUfK5Ua_ZmfA,3554
|
|
505
|
-
invenio_app_rdm-13.0.0b3.
|
|
506
|
-
invenio_app_rdm-13.0.0b3.
|
|
507
|
-
invenio_app_rdm-13.0.0b3.
|
|
508
|
-
invenio_app_rdm-13.0.0b3.
|
|
509
|
-
invenio_app_rdm-13.0.0b3.
|
|
512
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/METADATA,sha256=eGia2PPptzucD3ImEyEI9TMwfsODbAZnXk87kHBtlv4,13241
|
|
513
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/WHEEL,sha256=oSJJyWjO7Z2XSScFQUpXG1HL-N0sFMqqeKVVbZTPkWc,109
|
|
514
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/entry_points.txt,sha256=rfzEeOEdtGy99NlpWzeW-32CoO5XrEpBvlZwLD2Th88,2158
|
|
515
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/top_level.txt,sha256=NqTqrntInEAci7EXcNBvouXFMqwyjVQhEI0b7izYRBY,22
|
|
516
|
+
invenio_app_rdm-13.0.0b3.dev7.dist-info/RECORD,,
|
{invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/entry_points.txt
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
rdm = invenio_app_rdm.cli:rdm
|
|
3
3
|
|
|
4
4
|
[invenio_administration.views]
|
|
5
|
+
invenio_app_rdm_audit_logs = invenio_app_rdm.administration.audit_logs:AuditLogListView
|
|
5
6
|
invenio_app_rdm_drafts_list = invenio_app_rdm.administration.records:DraftAdminListView
|
|
6
7
|
invenio_app_rdm_records_list = invenio_app_rdm.administration.records:RecordAdminListView
|
|
7
8
|
invenio_requests_user_moderation_detail = invenio_app_rdm.administration.user_moderation:UserModerationRequestDetailView
|
tests/conftest.py
CHANGED
|
@@ -27,8 +27,6 @@ except AttributeError:
|
|
|
27
27
|
|
|
28
28
|
security.safe_str_cmp = hmac.compare_digest
|
|
29
29
|
|
|
30
|
-
import shutil
|
|
31
|
-
import tempfile
|
|
32
30
|
from collections import namedtuple
|
|
33
31
|
|
|
34
32
|
import pytest
|
|
@@ -41,7 +39,6 @@ from invenio_accounts.proxies import current_datastore
|
|
|
41
39
|
from invenio_accounts.testutils import login_user_via_session
|
|
42
40
|
from invenio_app.factory import create_app as _create_app
|
|
43
41
|
from invenio_db import db
|
|
44
|
-
from invenio_files_rest.models import Bucket, FileInstance, Location, ObjectVersion
|
|
45
42
|
from invenio_records_resources.proxies import current_service_registry
|
|
46
43
|
from invenio_vocabularies.contrib.subjects.api import Subject
|
|
47
44
|
from invenio_vocabularies.proxies import current_service as vocabulary_service
|
|
@@ -273,41 +270,3 @@ RunningApp = namedtuple(
|
|
|
273
270
|
def running_app(app, location, resource_type_item, language_item, subject_item):
|
|
274
271
|
"""Fixture mimicking a running app."""
|
|
275
272
|
return RunningApp(app, location, resource_type_item, language_item, subject_item)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
@pytest.yield_fixture()
|
|
279
|
-
def dummy_location(db):
|
|
280
|
-
"""File system location."""
|
|
281
|
-
tmppath = tempfile.mkdtemp()
|
|
282
|
-
|
|
283
|
-
loc = Location(name="testloc", uri=tmppath, default=True)
|
|
284
|
-
db.session.add(loc)
|
|
285
|
-
db.session.commit()
|
|
286
|
-
|
|
287
|
-
yield loc
|
|
288
|
-
|
|
289
|
-
shutil.rmtree(tmppath)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
@pytest.fixture
|
|
293
|
-
def invalid_file_instance(db, dummy_location):
|
|
294
|
-
"""Creates a file instance."""
|
|
295
|
-
# Create a Bucket and ObjectVersion
|
|
296
|
-
b1 = Bucket.create(location=dummy_location)
|
|
297
|
-
with open("README.rst", "rb") as fp:
|
|
298
|
-
obj = ObjectVersion.create(b1, "README.rst", stream=fp)
|
|
299
|
-
db.session.commit()
|
|
300
|
-
file_id = obj.file_id
|
|
301
|
-
|
|
302
|
-
# Get FileInstance from file ID
|
|
303
|
-
f = FileInstance.query.get(file_id)
|
|
304
|
-
|
|
305
|
-
# Force an invalid checksum
|
|
306
|
-
f.checksum = "invalid"
|
|
307
|
-
f.verify_checksum()
|
|
308
|
-
db.session.commit()
|
|
309
|
-
|
|
310
|
-
# Retrieve the file instance (with updated last_check)
|
|
311
|
-
f = FileInstance.query.get(file_id)
|
|
312
|
-
|
|
313
|
-
return f
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
#
|
|
4
4
|
# Copyright (C) 2022 CERN.
|
|
5
|
+
# Copyright (C) 2025 Northwestern University.
|
|
5
6
|
#
|
|
6
7
|
# Invenio App RDM is free software; you can redistribute it and/or modify it
|
|
7
8
|
# under the terms of the MIT License; see LICENSE file for more details.
|
|
8
9
|
-#}
|
|
9
10
|
|
|
10
|
-
{% set BASE_URL = config.SITE_UI_URL %}
|
|
11
|
-
|
|
12
11
|
{%- for entry in entries -%}
|
|
13
12
|
{{ "ID: %s" | format(entry.file.id) }}
|
|
14
13
|
{{ "URI: %s" | format(entry.file.uri) }}
|
|
@@ -19,10 +18,10 @@
|
|
|
19
18
|
{{ "Checksum: %s" | format(entry.file.checksum) }}
|
|
20
19
|
{{ "Last check: %s" | format(entry.file.last_check_at) }}
|
|
21
20
|
{%- if 'record' in entry %}
|
|
22
|
-
{{ "Record: %s
|
|
21
|
+
{{ "Record: %s" | format(invenio_url_for("invenio_app_rdm_records.record_detail", pid_value=entry.record.id)) }}
|
|
23
22
|
{%- endif %}
|
|
24
23
|
{%- if 'draft' in entry %}
|
|
25
|
-
{{ "Draft: %s
|
|
24
|
+
{{ "Draft: %s" | format(invenio_url_for("invenio_app_rdm_records.deposit_edit", pid_value=entry.draft.id)) }}
|
|
26
25
|
{%- endif %}
|
|
27
26
|
{{ "-" * 80 }}
|
|
28
27
|
{% endfor %}
|
tests/test_tasks.py
CHANGED
|
@@ -1,16 +1,102 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
#
|
|
3
3
|
# Copyright (C) 2022-2024 CERN.
|
|
4
|
+
# Copyright (C) 2025 Northwestern University.
|
|
4
5
|
#
|
|
5
6
|
# Invenio App RDM is free software; you can redistribute it and/or modify it
|
|
6
7
|
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
8
|
"""Test invenio-app-rdm celery tasks."""
|
|
8
9
|
|
|
9
|
-
from
|
|
10
|
+
from io import BytesIO
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from invenio_access.permissions import system_identity
|
|
14
|
+
from invenio_db import db
|
|
15
|
+
from invenio_files_rest.models import Bucket, FileInstance, Location, ObjectVersion
|
|
16
|
+
from invenio_rdm_records.proxies import current_rdm_records
|
|
10
17
|
|
|
18
|
+
from invenio_app_rdm.tasks import file_integrity_report
|
|
11
19
|
|
|
12
|
-
|
|
20
|
+
# Fixtures
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def draft_with_file_instance(running_app, minimal_record):
|
|
25
|
+
"""Create draft with file and return (Draft, FileInstance)."""
|
|
26
|
+
minimal_record["files"] = {"enabled": True}
|
|
27
|
+
|
|
28
|
+
record_service = current_rdm_records.records_service
|
|
29
|
+
file_service = record_service.draft_files
|
|
30
|
+
|
|
31
|
+
draft = record_service.create(system_identity, minimal_record)
|
|
32
|
+
file_to_initialise = [
|
|
33
|
+
{
|
|
34
|
+
"key": "article.txt",
|
|
35
|
+
"checksum": "md5:c785060c866796cc2a1708c997154c8e",
|
|
36
|
+
"size": 17, # 2kB
|
|
37
|
+
"metadata": {
|
|
38
|
+
"description": "Published article PDF.",
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
file_service.init_files(system_identity, draft.id, file_to_initialise)
|
|
43
|
+
content = BytesIO(b"test file content")
|
|
44
|
+
file_service.set_file_content(
|
|
45
|
+
system_identity,
|
|
46
|
+
draft.id,
|
|
47
|
+
file_to_initialise[0]["key"],
|
|
48
|
+
content,
|
|
49
|
+
content.getbuffer().nbytes,
|
|
50
|
+
)
|
|
51
|
+
file_item = file_service.commit_file(system_identity, draft.id, "article.txt")
|
|
52
|
+
# fmt: off
|
|
53
|
+
id_of_file_instance = (
|
|
54
|
+
file_item
|
|
55
|
+
._record
|
|
56
|
+
.files
|
|
57
|
+
.entries["article.txt"]
|
|
58
|
+
.object_version.file_id
|
|
59
|
+
)
|
|
60
|
+
# fmt: on
|
|
61
|
+
f = FileInstance.query.get(id_of_file_instance)
|
|
62
|
+
return draft, f
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.fixture
|
|
66
|
+
def draft_with_invalid_file_instance(draft_with_file_instance):
|
|
67
|
+
# Force an invalid checksum
|
|
68
|
+
draft, f = draft_with_file_instance
|
|
69
|
+
f.checksum = "invalid"
|
|
70
|
+
f.verify_checksum()
|
|
71
|
+
db.session.commit()
|
|
72
|
+
|
|
73
|
+
# Retrieve the file instance (with updated last_check)
|
|
74
|
+
f = FileInstance.query.get(f.id)
|
|
75
|
+
|
|
76
|
+
return draft, f
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.fixture
|
|
80
|
+
def record_with_invalid_file_instance(draft_with_invalid_file_instance):
|
|
81
|
+
draft, f = draft_with_invalid_file_instance
|
|
82
|
+
record_service = current_rdm_records.records_service
|
|
83
|
+
return record_service.publish(system_identity, draft.id), f
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.fixture
|
|
87
|
+
def invalid_file_instance(record_with_invalid_file_instance):
|
|
88
|
+
draft, f = record_with_invalid_file_instance
|
|
89
|
+
return f
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# Tests
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_task_file_integrity_report(
|
|
96
|
+
app, record_with_invalid_file_instance, set_app_config_fn_scoped
|
|
97
|
+
):
|
|
13
98
|
"""Test celery task for file integrity reports."""
|
|
99
|
+
record, invalid_file_instance = record_with_invalid_file_instance
|
|
14
100
|
assert invalid_file_instance.last_check is False
|
|
15
101
|
|
|
16
102
|
# A report must be generated for the file
|
|
@@ -20,7 +106,6 @@ def test_task_file_integrity_report(app, invalid_file_instance):
|
|
|
20
106
|
recipients = "test@invenio.org"
|
|
21
107
|
sender = "test@invenio.org"
|
|
22
108
|
|
|
23
|
-
file_name = invalid_file_instance.objects[0].key
|
|
24
109
|
uri = invalid_file_instance.uri
|
|
25
110
|
file_id = invalid_file_instance.id
|
|
26
111
|
file_name = invalid_file_instance.objects[0].key
|
|
@@ -28,9 +113,13 @@ def test_task_file_integrity_report(app, invalid_file_instance):
|
|
|
28
113
|
|
|
29
114
|
with mail.record_messages() as outbox:
|
|
30
115
|
# Configure email and validate that email was sent
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
116
|
+
set_app_config_fn_scoped(
|
|
117
|
+
{
|
|
118
|
+
"APP_RDM_FILES_INTEGRITY_REPORT_TEMPLATE": "mock_mail.html",
|
|
119
|
+
"APP_RDM_ADMIN_EMAIL_RECIPIENT": recipients,
|
|
120
|
+
"MAIL_DEFAULT_SENDER": sender,
|
|
121
|
+
}
|
|
122
|
+
)
|
|
34
123
|
|
|
35
124
|
file_integrity_report()
|
|
36
125
|
assert len(outbox) == 1
|
|
@@ -41,9 +130,12 @@ def test_task_file_integrity_report(app, invalid_file_instance):
|
|
|
41
130
|
assert "URI: {}".format(uri) in mail_sent.body
|
|
42
131
|
assert "ID: {}".format(str(file_id)) in mail_sent.body
|
|
43
132
|
assert "Name: {}".format(file_name) in mail_sent.body
|
|
133
|
+
assert f"Record: https://127.0.0.1:5000/records/{record.id}" in mail_sent.body
|
|
44
134
|
|
|
45
135
|
|
|
46
|
-
def test_integrity_report_invalid_template(
|
|
136
|
+
def test_integrity_report_invalid_template(
|
|
137
|
+
app, invalid_file_instance, set_app_config_fn_scoped
|
|
138
|
+
):
|
|
47
139
|
"""Test non-existant e-mail template."""
|
|
48
140
|
assert invalid_file_instance.last_check is False
|
|
49
141
|
|
|
@@ -52,12 +144,15 @@ def test_integrity_report_invalid_template(app, invalid_file_instance):
|
|
|
52
144
|
|
|
53
145
|
with mail.record_messages() as outbox:
|
|
54
146
|
# Remove the template, no e-mail is sent
|
|
55
|
-
|
|
147
|
+
set_app_config_fn_scoped({"APP_RDM_FILES_INTEGRITY_REPORT_TEMPLATE": None})
|
|
148
|
+
|
|
56
149
|
file_integrity_report()
|
|
57
150
|
assert len(outbox) == 0
|
|
58
151
|
|
|
59
152
|
|
|
60
|
-
def test_integrity_report_invalid_addresses(
|
|
153
|
+
def test_integrity_report_invalid_addresses(
|
|
154
|
+
app, invalid_file_instance, set_app_config_fn_scoped
|
|
155
|
+
):
|
|
61
156
|
"""Test invalid recipient address."""
|
|
62
157
|
assert invalid_file_instance.last_check is False
|
|
63
158
|
|
|
@@ -65,17 +160,24 @@ def test_integrity_report_invalid_addresses(app, invalid_file_instance):
|
|
|
65
160
|
assert mail
|
|
66
161
|
|
|
67
162
|
with mail.record_messages() as outbox:
|
|
68
|
-
|
|
69
|
-
|
|
163
|
+
set_app_config_fn_scoped(
|
|
164
|
+
{
|
|
165
|
+
# Use mock template
|
|
166
|
+
"APP_RDM_FILES_INTEGRITY_REPORT_TEMPLATE": "mock_mail.html",
|
|
167
|
+
# Recipient is not set, mail is not sent.
|
|
168
|
+
"APP_RDM_ADMIN_EMAIL_RECIPIENT": None,
|
|
169
|
+
}
|
|
170
|
+
)
|
|
70
171
|
|
|
71
|
-
# Recipient is not set, mail is not sent.
|
|
72
|
-
app.config["APP_RDM_ADMIN_EMAIL_RECIPIENT"] = None
|
|
73
172
|
file_integrity_report()
|
|
74
173
|
assert len(outbox) == 0
|
|
75
174
|
|
|
76
175
|
|
|
77
|
-
def test_integrity_report_default_template(
|
|
176
|
+
def test_integrity_report_default_template(
|
|
177
|
+
app, draft_with_invalid_file_instance, set_app_config_fn_scoped
|
|
178
|
+
):
|
|
78
179
|
"""Test invalid recipient address."""
|
|
180
|
+
draft, invalid_file_instance = draft_with_invalid_file_instance
|
|
79
181
|
assert invalid_file_instance.last_check is False
|
|
80
182
|
|
|
81
183
|
mail = app.extensions.get("mail")
|
|
@@ -91,8 +193,10 @@ def test_integrity_report_default_template(app, invalid_file_instance):
|
|
|
91
193
|
|
|
92
194
|
with mail.record_messages() as outbox:
|
|
93
195
|
# Use default template
|
|
94
|
-
|
|
95
|
-
|
|
196
|
+
set_app_config_fn_scoped(
|
|
197
|
+
{"APP_RDM_ADMIN_EMAIL_RECIPIENT": recipients, "MAIL_DEFAULT_SENDER": sender}
|
|
198
|
+
)
|
|
199
|
+
|
|
96
200
|
file_integrity_report()
|
|
97
201
|
assert len(outbox) == 1
|
|
98
202
|
mail_sent = outbox[0]
|
|
@@ -102,3 +206,4 @@ def test_integrity_report_default_template(app, invalid_file_instance):
|
|
|
102
206
|
assert "URI: {}".format(uri) in mail_sent.body
|
|
103
207
|
assert "ID: {}".format(str(file_id)) in mail_sent.body
|
|
104
208
|
assert "Name: {}".format(file_name) in mail_sent.body
|
|
209
|
+
assert f"Draft: https://127.0.0.1:5000/uploads/{draft.id}" in mail_sent.body
|
tests/ui/conftest.py
CHANGED
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
from io import BytesIO
|
|
13
13
|
|
|
14
14
|
import pytest
|
|
15
|
+
from flask_principal import Identity
|
|
15
16
|
from flask_webpackext.manifest import (
|
|
16
17
|
JinjaManifest,
|
|
17
18
|
JinjaManifestEntry,
|
|
18
19
|
JinjaManifestLoader,
|
|
19
20
|
)
|
|
20
|
-
from invenio_access.permissions import system_identity
|
|
21
|
+
from invenio_access.permissions import any_user, authenticated_user, system_identity
|
|
21
22
|
from invenio_app.factory import create_ui
|
|
22
23
|
from invenio_rdm_records.proxies import current_rdm_records
|
|
23
24
|
from invenio_search import current_search
|
|
@@ -74,14 +75,18 @@ def record(running_app, minimal_record):
|
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
@pytest.fixture()
|
|
77
|
-
def
|
|
78
|
-
"""Create
|
|
78
|
+
def draft_with_file(running_app, minimal_record, users):
|
|
79
|
+
"""Create a draft with a file."""
|
|
79
80
|
minimal_record["files"] = {"enabled": True}
|
|
80
81
|
|
|
82
|
+
# Use a user's identity to make sure the record has an owner
|
|
83
|
+
user_identity = Identity(users["user1"].id)
|
|
84
|
+
user_identity.provides.add(any_user)
|
|
85
|
+
user_identity.provides.add(authenticated_user)
|
|
81
86
|
record_service = current_rdm_records.records_service
|
|
82
87
|
file_service = record_service.draft_files
|
|
83
88
|
|
|
84
|
-
draft = record_service.create(
|
|
89
|
+
draft = record_service.create(user_identity, minimal_record)
|
|
85
90
|
file_to_initialise = [
|
|
86
91
|
{
|
|
87
92
|
"key": "article.txt",
|
|
@@ -102,4 +107,11 @@ def record_with_file(running_app, minimal_record):
|
|
|
102
107
|
content.getbuffer().nbytes,
|
|
103
108
|
)
|
|
104
109
|
file_service.commit_file(system_identity, draft.id, "article.txt")
|
|
105
|
-
return
|
|
110
|
+
return draft
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@pytest.fixture()
|
|
114
|
+
def record_with_file(draft_with_file):
|
|
115
|
+
"""Create and publish a record with file."""
|
|
116
|
+
record_service = current_rdm_records.records_service
|
|
117
|
+
return record_service.publish(system_identity, draft_with_file.id)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2025 CERN.
|
|
4
|
+
# Copyright (C) 2025 KTH Royal Institute of Technology.
|
|
5
|
+
#
|
|
6
|
+
# Invenio-App-RDM is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the MIT License; see LICENSE file for more details.
|
|
8
|
+
|
|
9
|
+
from flask import url_for
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_file_download_with_and_without_preview_flag(
|
|
13
|
+
client_with_login, draft_with_file
|
|
14
|
+
):
|
|
15
|
+
"""Test file download both with and without preview flag."""
|
|
16
|
+
client = client_with_login
|
|
17
|
+
draft_id = draft_with_file["id"]
|
|
18
|
+
file_name = "article.txt"
|
|
19
|
+
|
|
20
|
+
# The draft's owner should be able to download its file from the preview page
|
|
21
|
+
url_with_preview = url_for(
|
|
22
|
+
"invenio_app_rdm_records.record_file_download",
|
|
23
|
+
pid_value=draft_id,
|
|
24
|
+
filename=file_name,
|
|
25
|
+
download=1,
|
|
26
|
+
preview=1,
|
|
27
|
+
)
|
|
28
|
+
response = client.get(url_with_preview)
|
|
29
|
+
assert (
|
|
30
|
+
response.status_code == 200
|
|
31
|
+
), "File download with preview flag should return 200"
|
|
32
|
+
|
|
33
|
+
# But since the draft isn't published yet, it can't be found without preview=1
|
|
34
|
+
url_without_preview = url_for(
|
|
35
|
+
"invenio_app_rdm_records.record_file_download",
|
|
36
|
+
pid_value=draft_id,
|
|
37
|
+
filename=file_name,
|
|
38
|
+
download=1,
|
|
39
|
+
)
|
|
40
|
+
response = client.get(url_without_preview)
|
|
41
|
+
assert (
|
|
42
|
+
response.status_code == 404
|
|
43
|
+
), "File download without preview flag should return 404"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_nonexistent_file_returns_404(client_with_login, draft_with_file):
|
|
47
|
+
"""Test that requesting a non-existent file returns 404 via the NoResultFound handler."""
|
|
48
|
+
client = client_with_login
|
|
49
|
+
draft_id = draft_with_file["id"]
|
|
50
|
+
fake_file = "nonexistent-file.pdf"
|
|
51
|
+
|
|
52
|
+
# Downloads for files that don't exist should return a 404, both without...
|
|
53
|
+
url_without_preview = url_for(
|
|
54
|
+
"invenio_app_rdm_records.record_file_download",
|
|
55
|
+
pid_value=draft_id,
|
|
56
|
+
filename=fake_file,
|
|
57
|
+
download=1,
|
|
58
|
+
)
|
|
59
|
+
response = client.get(url_without_preview)
|
|
60
|
+
assert response.status_code == 404, "Non-existent file should return 404"
|
|
61
|
+
|
|
62
|
+
# ... as well as with the preview=1 flag
|
|
63
|
+
url_with_preview = url_for(
|
|
64
|
+
"invenio_app_rdm_records.record_file_download",
|
|
65
|
+
pid_value=draft_id,
|
|
66
|
+
filename=fake_file,
|
|
67
|
+
download=1,
|
|
68
|
+
preview=1,
|
|
69
|
+
)
|
|
70
|
+
response = client.get(url_with_preview)
|
|
71
|
+
assert (
|
|
72
|
+
response.status_code == 404
|
|
73
|
+
), "Non-existent file with preview flag should return 404"
|
invenio_app_rdm/urls.py
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Copyright (C) 2023 Northwestern University.
|
|
4
|
-
#
|
|
5
|
-
# This file is lifted from Invenio-RDM-Records .
|
|
6
|
-
#
|
|
7
|
-
# Invenio-RDM-Records is free software; you can redistribute it and/or modify
|
|
8
|
-
# it under the terms of the MIT License; see LICENSE file for more details.
|
|
9
|
-
|
|
10
|
-
"""Convenient URL generation.
|
|
11
|
-
|
|
12
|
-
InvenioRDM poses challenges to url generation that Flask's url_for cannot handle out
|
|
13
|
-
of the gate.
|
|
14
|
-
|
|
15
|
-
- InvenioRDM is actually 2 applications mounted on different url_prefixes:
|
|
16
|
-
`url_for` in the API application isn't aware of the UI application endpoints
|
|
17
|
-
- The endpoint names are relatively hidden / spread out and APP_RDM_ROUTES is usually
|
|
18
|
-
the interface to name them.
|
|
19
|
-
- Need to be able to generate urls outside of request context without thinking about it,
|
|
20
|
-
|
|
21
|
-
This module contains minimal methods to generate URLs correctly without much
|
|
22
|
-
engineering. Over time, it can be made more abstract, complex and powerful and even
|
|
23
|
-
extracted into its own package to solve url generation across InvenioRDM once and for
|
|
24
|
-
all.
|
|
25
|
-
|
|
26
|
-
Design decisions:
|
|
27
|
-
|
|
28
|
-
- Generated urls are absolute for now
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
import unicodedata
|
|
32
|
-
from urllib.parse import quote
|
|
33
|
-
|
|
34
|
-
from flask import current_app
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def record_url_for(_app="ui", pid_value=""):
|
|
38
|
-
"""Return url for record route."""
|
|
39
|
-
assert _app in ["ui", "api"]
|
|
40
|
-
|
|
41
|
-
site_app = _app.upper()
|
|
42
|
-
url_prefix = current_app.config.get(f"SITE_{site_app}_URL", "")
|
|
43
|
-
|
|
44
|
-
# We use [] so that this fails and brings to attention the configuration
|
|
45
|
-
# problem if APP_RDM_ROUTES.record_detail is missing
|
|
46
|
-
url_path = current_app.config["APP_RDM_ROUTES"]["record_detail"].replace(
|
|
47
|
-
"<pid_value>", pid_value
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
return "/".join(p.strip("/") for p in [url_prefix, url_path])
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def download_url_for(pid_value="", filename=""):
|
|
54
|
-
"""Return url for download route."""
|
|
55
|
-
url_prefix = current_app.config.get("SITE_UI_URL", "")
|
|
56
|
-
|
|
57
|
-
# see https://github.com/pallets/werkzeug/blob/main/src/werkzeug/utils.py#L456-L465
|
|
58
|
-
try:
|
|
59
|
-
filename.encode("ascii")
|
|
60
|
-
except UnicodeEncodeError:
|
|
61
|
-
# safe = RFC 5987 attr-char
|
|
62
|
-
filename = quote(filename, safe="!#$&+-.^_`|~")
|
|
63
|
-
|
|
64
|
-
# We use [] so that this fails and brings to attention the configuration
|
|
65
|
-
# problem if APP_RDM_ROUTES.record_file_download is missing
|
|
66
|
-
url_path = (
|
|
67
|
-
current_app.config["APP_RDM_ROUTES"]["record_file_download"]
|
|
68
|
-
.replace("<pid_value>", pid_value)
|
|
69
|
-
.replace("<path:filename>", filename)
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
return "/".join(p.strip("/") for p in [url_prefix, url_path])
|
{invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{invenio_app_rdm-13.0.0b3.dev5.dist-info → invenio_app_rdm-13.0.0b3.dev7.dist-info}/top_level.txt
RENAMED
|
File without changes
|