Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions invenio_app_rdm/administration/roles/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 CERN.
# Copyright (C) 2025 KTH Royal Institute of Technology.
#
# Invenio App RDM is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Invenio administration module for groups / roles resources."""

from .roles import RolesCreateView, RolesDetailView, RolesEditView, RolesListView

__all__ = ("RolesListView", "RolesDetailView", "RolesCreateView", "RolesEditView")
115 changes: 115 additions & 0 deletions invenio_app_rdm/administration/roles/roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 CERN.
# Copyright (C) 2025 KTH Royal Institute of Technology.
#
# Invenio App RDM is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Administration views for managing roles."""
from flask import abort
from invenio_administration.views.base import (
AdminResourceCreateView,
AdminResourceDetailView,
AdminResourceEditView,
AdminResourceListView,
)
from invenio_i18n import lazy_gettext as _

from ..users.permissions import can_access_user_administration


class RoleAdminMixin:
"""Shared configuration for role administration views."""

resource_config = "groups_resource"
extension_name = "invenio-users-resources"

api_endpoint = "/groups"
pid_path = "id"

create_view_name = "roles_create"
list_view_name = "roles"

display_search = True
display_delete = True
display_create = True
display_edit = True

search_config_name = "USERS_RESOURCES_GROUPS_ADMIN_SEARCH"
search_sort_config_name = "USERS_RESOURCES_GROUPS_ADMIN_SORT_OPTIONS"
search_facets_config_name = "USERS_RESOURCES_GROUPS_ADMIN_FACETS"

def dispatch_request(self, **kwargs):
"""Deny direct navigation to unauthorized users."""
if not can_access_user_administration():
abort(403)
return super().get(**kwargs)


class RolesListView(RoleAdminMixin, AdminResourceListView):
"""List roles."""

name = "roles"
title = _("Roles")
menu_label = _("Roles")
category = _("User management")
icon = "id badge"
order = 30

item_field_list = {
"name": {"text": _("Name"), "order": 0, "width": 3},
"id": {"text": _("ID"), "order": 1, "width": 3},
"description": {"text": _("Description"), "order": 2, "width": 5},
"is_managed": {"text": _("Managed"), "order": 3, "width": 1},
"created": {"text": _("Created"), "order": 4, "width": 2},
}

search_request_headers = {"Accept": "application/json"}


class RolesDetailView(RoleAdminMixin, AdminResourceDetailView):
"""Role detail view."""

url = "/roles/<pid_value>"
name = "roles_detail"
title = _("Role details")

item_field_list = {
"id": {"text": _("ID"), "order": 0},
"name": {"text": _("Name"), "order": 1},
"description": {"text": _("Description"), "order": 2},
"is_managed": {"text": _("Managed"), "order": 3},
"created": {"text": _("Created"), "order": 4},
"updated": {"text": _("Updated"), "order": 5},
}


class RolesCreateView(RoleAdminMixin, AdminResourceCreateView):
"""Role creation view."""

name = "roles_create"
url = "/roles/create"
title = _("Create role")

form_fields = {
"name": {
"order": 1,
"text": _("Name"),
"required": True,
},
"description": {
"order": 2,
"text": _("Description"),
},
}


class RolesEditView(RoleAdminMixin, AdminResourceEditView):
"""Role edit view."""

name = "roles_edit"
url = "/roles/<pid_value>/edit"
title = _("Edit role")

form_fields = RolesCreateView.form_fields
28 changes: 28 additions & 0 deletions invenio_app_rdm/administration/users/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 CERN.
# Copyright (C) 2025 KTH Royal Institute of Technology.
#
# Invenio App RDM is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Helpers for administration moderation access checks."""

from flask import g
from flask_principal import RoleNeed
from invenio_access.permissions import superuser_access


def can_access_user_administration(identity=None):
"""Return True if the identity may access user/role admin views."""
identity = identity or getattr(g, "identity", None)
if not identity:
return False

provides = identity.provides
admin_need = RoleNeed("administration")
moderator_need = RoleNeed("administration-moderation")

return (superuser_access in provides) or (
admin_need in provides and moderator_need in provides
)
29 changes: 21 additions & 8 deletions invenio_app_rdm/administration/users/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@

from functools import partial

from flask import current_app
from flask import abort, current_app
from invenio_administration.views.base import (
AdminResourceDetailView,
AdminResourceListView,
)
from invenio_i18n import lazy_gettext as _
from invenio_search_ui.searchconfig import search_app_config

from .permissions import can_access_user_administration

USERS_ITEM_LIST = {
"user": {"text": _("User"), "order": 2, "width": 3},
"username": {"text": _("Username"), "order": 3, "width": 2},
Expand All @@ -36,18 +38,29 @@
"status": {"text": _("Status"), "order": 6, "width": 1},
"visibility": {"text": _("Visibility"), "order": 7, "width": 1},
"active": {"text": _("Active"), "order": 8, "width": 1},
"confirmed_at": {"text": _("Confirmed at"), "order": 9, "width": 1},
"verified_at": {"text": _("Verified at"), "order": 10, "width": 1},
"blocked_at": {"text": _("Blocked at"), "order": 11, "width": 1},
"created": {"text": _("Created"), "order": 12, "width": 2},
"updated": {"text": _("Updated"), "order": 13, "width": 2},
"roles": {"text": _("Roles"), "order": 9, "width": 2},
"confirmed_at": {"text": _("Confirmed at"), "order": 10, "width": 1},
"verified_at": {"text": _("Verified at"), "order": 11, "width": 1},
"blocked_at": {"text": _("Blocked at"), "order": 12, "width": 1},
"created": {"text": _("Created"), "order": 13, "width": 2},
"updated": {"text": _("Updated"), "order": 14, "width": 2},
}


# List of the columns displayed on the user list and user details


class UsersListView(AdminResourceListView):
class UserAdminAccessMixin:
"""Mixin asserting only user admins identities access user views."""

def dispatch_request(self, *args, **kwargs):
"""Override Flask view to add permission check."""
if not can_access_user_administration():
abort(403)
return super().dispatch_request(*args, **kwargs)


class UsersListView(UserAdminAccessMixin, AdminResourceListView):
"""Configuration for users sets list view."""

api_endpoint = "/users/all"
Expand Down Expand Up @@ -113,7 +126,7 @@ def init_search_config(self):
)


class UsersDetailView(AdminResourceDetailView):
class UsersDetailView(UserAdminAccessMixin, AdminResourceDetailView):
"""Configuration for users sets detail view."""

url = "/users/<pid_value>"
Expand Down
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Copyright (C) 2019-2022 Northwestern University.
# Copyright (C) 2022-2025 Graz University of Technology.
# Copyright (C) 2025 University of Münster.
# Copyright (C) 2025 KTH Royal Institute of Technology.
#
# Invenio App RDM is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -119,6 +120,10 @@ invenio_administration.views =
invenio_requests_user_moderation_detail = invenio_app_rdm.administration.user_moderation:UserModerationRequestDetailView
invenio_requests_moderation_requests_list = invenio_app_rdm.administration.moderation.requests:ModerationRequestListView
invenio_requests_moderation_requests_details = invenio_app_rdm.administration.moderation.requests:ModerationRequestDetailView
invenio_users_resources_roles_list = invenio_app_rdm.administration.roles:RolesListView
invenio_users_resources_roles_edit = invenio_app_rdm.administration.roles:RolesEditView
invenio_users_resources_roles_detail = invenio_app_rdm.administration.roles:RolesDetailView
invenio_users_resources_roles_create = invenio_app_rdm.administration.roles:RolesCreateView
invenio_app_rdm_records_list = invenio_app_rdm.administration.records:RecordAdminListView
invenio_app_rdm_drafts_list = invenio_app_rdm.administration.records:DraftAdminListView
invenio_app_rdm_audit_logs = invenio_app_rdm.administration.audit_logs:AuditLogListView
Expand Down
Loading