From ffb10bccd9e833030a210b4b2c2516deb4bc2028 Mon Sep 17 00:00:00 2001 From: Laura Date: Wed, 7 Jan 2026 14:07:43 +0100 Subject: [PATCH 1/4] feat(mug): enable curation workflow --- .../overridableRegistry/mapping.js | 8 +- themes/MUG/invenio.cfg | 80 ++++++++++++++++++- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/assets/js/invenio_app_rdm/overridableRegistry/mapping.js b/assets/js/invenio_app_rdm/overridableRegistry/mapping.js index 0d15027..4c94090 100644 --- a/assets/js/invenio_app_rdm/overridableRegistry/mapping.js +++ b/assets/js/invenio_app_rdm/overridableRegistry/mapping.js @@ -8,4 +8,10 @@ * Add here all the overridden components of your app. */ -export const overriddenComponents = {} \ No newline at end of file +import { DepositBox } from "@js/invenio_curations/deposit/DepositBox"; +import { curationComponentOverrides } from "@js/invenio_curations/requests"; + +export const overriddenComponents = { + ...curationComponentOverrides, + "InvenioAppRdm.Deposit.CardDepositStatusBox.container": DepositBox, +}; \ No newline at end of file diff --git a/themes/MUG/invenio.cfg b/themes/MUG/invenio.cfg index 610e83b..39345ab 100644 --- a/themes/MUG/invenio.cfg +++ b/themes/MUG/invenio.cfg @@ -11,6 +11,21 @@ from datetime import datetime from invenio_i18n import lazy_gettext as _ from invenio_oauthclient.contrib.keycloak import KeycloakSettingsHelper +from invenio_app_rdm.config import NOTIFICATIONS_BUILDERS as RDM_NOTIFICATIONS_BUILDERS +from invenio_curations.config import CURATIONS_NOTIFICATIONS_BUILDERS +from invenio_curations.requests.curation import CurationRequest +from invenio_curations.services import facets as curations_facets +from invenio_curations.services.components import CurationComponent +from invenio_curations.services.generators import ( + IfCurationRequestAccepted, + IfRequestTypes, + TopicPermission, +) +from invenio_rdm_records.requests import CommunitySubmission +from invenio_rdm_records.services.components import DefaultRecordsComponents +from invenio_rdm_records.services.permissions import RDMRequestsPermissionPolicy +from invenio_requests.services.generators import Creator, Receiver + def _(x): # needed to avoid start time failure with lazy strings return x @@ -99,9 +114,9 @@ APP_DEFAULT_SECURE_HEADERS = { # See https://github.com/inveniosoftware/invenio-app-rdm/blob/master/invenio_app_rdm/config.py # ============================================================================ # Name used in header and UI -THEME_SITENAME = "instance" +THEME_SITENAME = "MUG Repository" # Frontpage title -THEME_FRONTPAGE_TITLE = "instance" +THEME_FRONTPAGE_TITLE = "Medical University of Graz Repository" # Header logo # THEME_LOGO = 'images/invenio-rdm.svg' @@ -221,6 +236,63 @@ BABEL_DEFAULT_TIMEZONE = "Europe/Vienna" # Other supported languages (do not include BABEL_DEFAULT_LOCALE in list). I18N_LANGUAGES = [] +# ============================================================================ +# Invenio-Curations +# ============================================================================ +NOTIFICATIONS_BUILDERS = { + **RDM_NOTIFICATIONS_BUILDERS, + **CURATIONS_NOTIFICATIONS_BUILDERS, +} + +RDM_RECORDS_SERVICE_COMPONENTS = DefaultRecordsComponents + [CurationComponent] + +REQUESTS_FACETS = { + "type": {"facet": curations_facets.type, "ui": {"field": "type"}}, + "status": {"facet": curations_facets.status, "ui": {"field": "status"}}, +} + + +class CurationRDMRequestsPermissionPolicy(RDMRequestsPermissionPolicy): + """Customized permission policy for curation workflow.""" + + curation_request_record_review = IfRequestTypes( + [CurationRequest], + then_=[TopicPermission(permission_name="can_review")], + else_=[], + ) + + can_action_accept = [ + IfRequestTypes( + request_types=[CommunitySubmission], + then_=[ + IfCurationRequestAccepted( + then_=RDMRequestsPermissionPolicy.can_action_accept, else_=[] + ) + ], + else_=RDMRequestsPermissionPolicy.can_action_accept, + ) + ] + + can_read = [ + IfRequestTypes( + [CurationRequest], + then_=[Creator(), Receiver(), TopicPermission(permission_name="can_review")], + else_=RDMRequestsPermissionPolicy.can_read, + ) + ] + + can_create_comment = can_read + + can_action_submit = RDMRequestsPermissionPolicy.can_action_submit + [ + curation_request_record_review + ] + can_action_review = RDMRequestsPermissionPolicy.can_action_accept + can_action_critique = RDMRequestsPermissionPolicy.can_action_accept + can_action_resubmit = can_action_submit + + +REQUESTS_PERMISSION_POLICY = CurationRDMRequestsPermissionPolicy + # ============================================================================ # Extras # ============================================================================ @@ -284,7 +356,7 @@ OVERRIDE_SHIBBOLETH = False """Set True if SAML is configured""" #INVENIO_OVERRIDE_FRONTPAGE_RIGHT=False -OVERRIDE_FRONTPAGE_RIGHT = False +OVERRIDE_FRONTPAGE_RIGHT = True """Frontpage right section""" # Right Section Configuration @@ -300,7 +372,7 @@ OVERRIDE_RIGHT_SECTION_CONTACT_EMAIL = "rdmsupport@medunigraz.at" # Theme and Templates # -------------- -OVERRIDE_RESOURCE_OVERVIEW = True +OVERRIDE_RESOURCE_OVERVIEW = False """Resource overview section""" # ============================================================================ From 2c2a0352dc070067ea1718b22f2551d53034786f Mon Sep 17 00:00:00 2001 From: Laura Date: Wed, 7 Jan 2026 14:07:52 +0100 Subject: [PATCH 2/4] chore(deps): add invenio-curations and global-search --- pyproject.toml | 5 ++++- uv.lock | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c810fdf..b7ab230 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,8 @@ dependencies = [ "uwsgi >=2.0", "uwsgitop >=0.11", "uwsgi-tools >=1.1.1", + "invenio-curations==0.4.0", + "invenio-global-search>=0.3.0", "invenio-override ~=0.0.6", ] @@ -21,4 +23,5 @@ dependencies = [ py-modules = [] [tool.uv.sources] -invenio-override = { git = "https://github.com/sharedRDM/invenio-override", branch = "main" } \ No newline at end of file +invenio-override = { path = "../invenio-override", editable = true } +invenio-curations = { git = "https://github.com/tu-graz-library/invenio-curations", branch = "main"} diff --git a/uv.lock b/uv.lock index 38514a6..66a2fc7 100644 --- a/uv.lock +++ b/uv.lock @@ -1187,6 +1187,8 @@ name = "instance" source = { virtual = "." } dependencies = [ { name = "invenio-app-rdm", extra = ["opensearch2"] }, + { name = "invenio-curations" }, + { name = "invenio-global-search" }, { name = "invenio-logging" }, { name = "invenio-override" }, { name = "uwsgi" }, @@ -1197,8 +1199,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "invenio-app-rdm", extras = ["opensearch2"], specifier = "==13.0.0" }, + { name = "invenio-curations", git = "https://github.com/tu-graz-library/invenio-curations?branch=main" }, + { name = "invenio-global-search", specifier = ">=0.3.0" }, { name = "invenio-logging", extras = ["sentry-sdk"], specifier = ">=4.0.0,<5.0.0" }, - { name = "invenio-override", git = "https://github.com/sharedRDM/invenio-override?branch=main" }, + { name = "invenio-override", editable = "../invenio-override" }, { name = "uwsgi", specifier = ">=2.0" }, { name = "uwsgi-tools", specifier = ">=1.1.1" }, { name = "uwsgitop", specifier = ">=0.11" }, @@ -1498,6 +1502,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/6a/7f56b8ed37be54853693985e2195bc45d7ea8cc23254752848938d124387/invenio_config-1.0.4-py2.py3-none-any.whl", hash = "sha256:e14fb7840afb71a913603391c48da3d6604cbcf6c458391c97eda167f06e1dcc", size = 10917 }, ] +[[package]] +name = "invenio-curations" +version = "0.4.0" +source = { git = "https://github.com/tu-graz-library/invenio-curations?branch=main#cd91640ac9c36ff7d73306ef4507de45d97ee66f" } +dependencies = [ + { name = "invenio-drafts-resources" }, + { name = "invenio-rdm-records" }, + { name = "invenio-requests" }, + { name = "nh3" }, +] + [[package]] name = "invenio-db" version = "2.0.0" @@ -1785,7 +1800,7 @@ wheels = [ [[package]] name = "invenio-override" version = "0.0.6" -source = { git = "https://github.com/sharedRDM/invenio-override?branch=main#d5a52a6ac35697a99b060f0fced48caf5847d854" } +source = { editable = "../invenio-override" } dependencies = [ { name = "invenio-app-rdm", extra = ["opensearch2"] }, { name = "invenio-global-search" }, @@ -1794,6 +1809,25 @@ dependencies = [ { name = "opensearch-py" }, ] +[package.metadata] +requires-dist = [ + { name = "invenio-app", marker = "extra == 'tests'", specifier = ">=2.1.0,<3.0.0" }, + { name = "invenio-app-rdm", extras = ["opensearch2"], specifier = ">=13.0.0b3.dev2,<13.1.dev0" }, + { name = "invenio-global-search", specifier = ">=0.3.0" }, + { name = "invenio-global-search", extras = ["lom"], marker = "extra == 'lom'", specifier = ">=0.3.0" }, + { name = "invenio-global-search", extras = ["lom", "marc21"], marker = "extra == 'tests'", specifier = ">=0.3.0" }, + { name = "invenio-global-search", extras = ["marc21"], marker = "extra == 'marc21'", specifier = ">=0.3.0" }, + { name = "invenio-previewer", marker = "extra == 'tests'", specifier = ">=2.2.0" }, + { name = "invenio-rdm-records", specifier = ">=18.0.0" }, + { name = "invenio-search", extras = ["opensearch2"], marker = "extra == 'opensearch2'", specifier = ">=3.0.0,<4.0.0" }, + { name = "opensearch-dsl", specifier = ">=2.0.0,<3.0.0" }, + { name = "opensearch-py", specifier = ">=2.0.0,<3.0.0" }, + { name = "pytest-black-ng", marker = "extra == 'tests'", specifier = ">=0.4.0" }, + { name = "pytest-invenio", marker = "extra == 'tests'", specifier = ">=3.3.0,<4.0.0" }, + { name = "sphinx", marker = "extra == 'tests'", specifier = ">=4.5.0" }, +] +provides-extras = ["lom", "marc21", "tests", "opensearch2"] + [[package]] name = "invenio-pages" version = "7.2.0" @@ -1936,16 +1970,17 @@ wheels = [ [[package]] name = "invenio-records-global-search" -version = "0.3.4" +version = "0.3.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "invenio-indexer" }, + { name = "invenio-rdm-records" }, { name = "invenio-records-resources" }, { name = "invenio-search-ui" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/ba/cf5e382db02b2918f6afcff481c85d4638b8b1970ead4f2f0ff83af477b6/invenio_records_global_search-0.3.4.tar.gz", hash = "sha256:f869778ed1550828dd6049158b338dbaa7ded02b9e9d35a4ab0d8b3eadf73831", size = 43706 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/5c/80dffbb8891f5c8acc43bca6a160a47474acff55987a9c000e4002d825da/invenio_records_global_search-0.3.5.tar.gz", hash = "sha256:8fd89785d8768dceac0dfaa7d22f245f11c5f05872138d0da4257f27c89c54a5", size = 45433 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/fc/3ae8972152b7a37426adfdc27d6d6dfcf5dd98dd12c9c6562c1464f87dfb/invenio_records_global_search-0.3.4-py2.py3-none-any.whl", hash = "sha256:73a7eeee65624891f03a038303ac4031cd64c07ae96584e7102f455983cd4914", size = 63720 }, + { url = "https://files.pythonhosted.org/packages/86/c1/c0d4c20b69599777bb7a4cb4a145e63b1a97dc199443c2bd770d3bca1494/invenio_records_global_search-0.3.5-py2.py3-none-any.whl", hash = "sha256:95eb69fe46caba7defb4336076ba5d5239599972264d35a961a0559ba8fda657", size = 66240 }, ] [[package]] From 953b76407d39c5cad146abdf74eae2e6e98e9831 Mon Sep 17 00:00:00 2001 From: Laura Date: Wed, 7 Jan 2026 14:23:14 +0100 Subject: [PATCH 3/4] chore(curations): add optional diff-comment template --- templates/comment-template.html | 70 +++++++++++++++++++++++++++++++++ themes/MUG/invenio.cfg | 5 +++ 2 files changed, 75 insertions(+) create mode 100644 templates/comment-template.html diff --git a/templates/comment-template.html b/templates/comment-template.html new file mode 100644 index 0000000..cc5b7e3 --- /dev/null +++ b/templates/comment-template.html @@ -0,0 +1,70 @@ + + + +

{{header}}

+ + {% if adds|length > 0 %} +

{{ _("Added") }}

+
    + {% for add in adds %} + {% set result_items = add.diff[2] %} + {% for result in result_items %} + {% set field = result[0] %} + {% set values = result[1:] %} + {% for value in values %} +
  • + {{ field }} +
    + New: {{ value|safe }} +
    +
  • + {% endfor %} + {% endfor %} + {% endfor %} +
+ {% endif %} + + {% if changes|length > 0 %} +

{{_("Changed")}}

+
    + {% for change in changes %} + {% set result = change.diff[2] %} + {% set old = result[0] %} + {% set new = result[1] %} +
  • + {{ change.diff[1] }} +
    + Old: {{ old|safe }}
    + New: {{ new|safe }} +
    +
  • + {% endfor %} +
+ {% endif %} + + {% if removes|length > 0 %} +

{{ _("Removed") }}

+
    + {% for remove in removes %} + {% set result_items = remove.diff[2] %} + {% for result in result_items %} + {% set values = result[1:] %} + {% for value in values %} + {% if remove.diff[1] == "metadata" %} + {% set field = result[0] %} + {% else %} + {% set field = remove.diff[1] %} + {% endif %} +
  • + {{ field }} +
    + {{ value|safe }} +
    +
  • + {% endfor %} + {% endfor %} + {% endfor %} +
+ {% endif %} + + diff --git a/themes/MUG/invenio.cfg b/themes/MUG/invenio.cfg index 39345ab..27336c2 100644 --- a/themes/MUG/invenio.cfg +++ b/themes/MUG/invenio.cfg @@ -292,6 +292,11 @@ class CurationRDMRequestsPermissionPolicy(RDMRequestsPermissionPolicy): REQUESTS_PERMISSION_POLICY = CurationRDMRequestsPermissionPolicy +# ============================================================================ +# Invenio-Curations - Comment Template +# ============================================================================ +CURATIONS_ENABLE_REQUEST_COMMENTS = True +CURATIONS_COMMENT_TEMPLATE_FILE = "comment-template.html" # ============================================================================ # Extras From 1fe53c9049bde11dbd9f6db57c12834f7d3174b6 Mon Sep 17 00:00:00 2001 From: Laura Date: Wed, 7 Jan 2026 15:22:48 +0100 Subject: [PATCH 4/4] refactor(curations): use package permission policies and add privileged roles --- pyproject.toml | 1 - themes/MUG/invenio.cfg | 56 ++++++++---------------------------------- 2 files changed, 10 insertions(+), 47 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b7ab230..0c5fd80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,5 +23,4 @@ dependencies = [ py-modules = [] [tool.uv.sources] -invenio-override = { path = "../invenio-override", editable = true } invenio-curations = { git = "https://github.com/tu-graz-library/invenio-curations", branch = "main"} diff --git a/themes/MUG/invenio.cfg b/themes/MUG/invenio.cfg index 27336c2..ba13659 100644 --- a/themes/MUG/invenio.cfg +++ b/themes/MUG/invenio.cfg @@ -13,18 +13,13 @@ from invenio_oauthclient.contrib.keycloak import KeycloakSettingsHelper from invenio_app_rdm.config import NOTIFICATIONS_BUILDERS as RDM_NOTIFICATIONS_BUILDERS from invenio_curations.config import CURATIONS_NOTIFICATIONS_BUILDERS -from invenio_curations.requests.curation import CurationRequest from invenio_curations.services import facets as curations_facets from invenio_curations.services.components import CurationComponent -from invenio_curations.services.generators import ( - IfCurationRequestAccepted, - IfRequestTypes, - TopicPermission, +from invenio_curations.services.permissions import ( + CurationRDMRecordPermissionPolicy, + CurationRDMRequestsPermissionPolicy, ) -from invenio_rdm_records.requests import CommunitySubmission from invenio_rdm_records.services.components import DefaultRecordsComponents -from invenio_rdm_records.services.permissions import RDMRequestsPermissionPolicy -from invenio_requests.services.generators import Creator, Receiver def _(x): # needed to avoid start time failure with lazy strings return x @@ -251,45 +246,14 @@ REQUESTS_FACETS = { "status": {"facet": curations_facets.status, "ui": {"field": "status"}}, } +# Roles that are exempted from curation workflow +CURATIONS_PRIVILEGED_ROLES = [ + "administration", + "bypass-curation", + "administration-rdm-records-curation", +] -class CurationRDMRequestsPermissionPolicy(RDMRequestsPermissionPolicy): - """Customized permission policy for curation workflow.""" - - curation_request_record_review = IfRequestTypes( - [CurationRequest], - then_=[TopicPermission(permission_name="can_review")], - else_=[], - ) - - can_action_accept = [ - IfRequestTypes( - request_types=[CommunitySubmission], - then_=[ - IfCurationRequestAccepted( - then_=RDMRequestsPermissionPolicy.can_action_accept, else_=[] - ) - ], - else_=RDMRequestsPermissionPolicy.can_action_accept, - ) - ] - - can_read = [ - IfRequestTypes( - [CurationRequest], - then_=[Creator(), Receiver(), TopicPermission(permission_name="can_review")], - else_=RDMRequestsPermissionPolicy.can_read, - ) - ] - - can_create_comment = can_read - - can_action_submit = RDMRequestsPermissionPolicy.can_action_submit + [ - curation_request_record_review - ] - can_action_review = RDMRequestsPermissionPolicy.can_action_accept - can_action_critique = RDMRequestsPermissionPolicy.can_action_accept - can_action_resubmit = can_action_submit - +RDM_PERMISSION_POLICY = CurationRDMRecordPermissionPolicy REQUESTS_PERMISSION_POLICY = CurationRDMRequestsPermissionPolicy # ============================================================================