diff --git a/invenio_app_rdm/administration/domains/__init__.py b/invenio_app_rdm/administration/domains/__init__.py new file mode 100644 index 000000000..14557df40 --- /dev/null +++ b/invenio_app_rdm/administration/domains/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2024 CERN. +# +# 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 user resources.""" +from .domains import ( + DomainsCreateView, + DomainsDetailView, + DomainsEditView, + DomainsListView, +) + +__all__ = ( + "DomainsCreateView", + "DomainsDetailView", + "DomainsEditView", + "DomainsListView", +) diff --git a/invenio_app_rdm/administration/domains/domains.py b/invenio_app_rdm/administration/domains/domains.py new file mode 100644 index 000000000..314d95e78 --- /dev/null +++ b/invenio_app_rdm/administration/domains/domains.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2024 CERN. +# +# 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 domains view module.""" + +from invenio_administration.views.base import ( + AdminResourceCreateView, + AdminResourceDetailView, + AdminResourceEditView, + AdminResourceListView, +) +from invenio_i18n import lazy_gettext as _ + + +class DomainAdminMixin: + """Common admin properties,""" + + resource_config = "domains_resource" + extension_name = "invenio-users-resources" + + api_endpoint = "/domains" + pid_path = "domain" + + create_view_name = "domains_create" + list_view_name = "domains" + + display_search = True + display_delete = True + display_create = True + display_edit = True + + +class DomainsListView(DomainAdminMixin, AdminResourceListView): + """Search admin view.""" + + name = "domains" + title = _("Domains") + menu_label = _("Domains") + category = _("Site management") + icon = "world" + + item_field_list = { + "domain": {"text": _("Domain"), "order": 1, "width": 3}, + "tld": {"text": _("TLD"), "order": 2, "width": 1}, + "status_name": {"text": _("Status"), "order": 3, "width": 1}, + "num_users": {"text": _("Users"), "order": 6, "width": 1}, + "num_active": {"text": _("Active"), "order": 7, "width": 1}, + "num_inactive": {"text": _("Inactive"), "order": 8, "width": 1}, + "num_confirmed": {"text": _("Confirmed"), "order": 9, "width": 1}, + "num_verified": {"text": _("Verified"), "order": 10, "width": 1}, + "num_blocked": {"text": _("Blocked"), "order": 11, "width": 1}, + "links": {"text": "", "order": 13, "width": 1}, + } + + search_config_name = "USERS_RESOURCES_DOMAINS_SEARCH" + search_sort_config_name = "USERS_RESOURCES_DOMAINS_SORT_OPTIONS" + search_facets_config_name = "USERS_RESOURCES_DOMAINS_SEARCH_FACETS" + + template = "invenio_app_rdm/administration/domains_search.html" + + search_request_headers = {"Accept": "application/vnd.inveniordm.v1+json"} + + +class FormMixin: + form_fields = { + "domain": { + "order": 1, + "text": _("Domain"), + "description": _("Domain name (all lowercase)"), + }, + "status_name": { + "order": 2, + "required": True, + "text": _("Status"), + "description": _( + "Status of the domain. One of new (domain needs review), moderated (users in domain require moderation), verified (users in domain does not require moderation) or blocked (users cannot register using this domain)." + ), + "options": [ + {"title_l10n": "New", "id": "new"}, + {"title_l10n": "Moderated", "id": "moderated"}, + {"title_l10n": "Verified", "id": "verified"}, + {"title_l10n": "Blocked", "id": "blocked"}, + ], + "placeholder": "Select a status", + }, + "category_name": { + "order": 3, + "text": _("Category"), + "description": _("A label to categorise the domain."), + "options": [ + # TODO: Needs to be dynmaically loaded from domain category table. + {"title_l10n": "Organization", "id": "organization"}, + {"title_l10n": "Company", "id": "company"}, + {"title_l10n": "Mail provider", "id": "mailprovider"}, + {"title_l10n": "Spammer", "id": "spammer"}, + ], + "placeholder": "Select a category", + }, + "flagged": { + "order": 4, + "text": _("Flagged"), + "description": _( + "Used by automatic processes to flag the domain as requiring review." + ), + }, + "flagged_source": { + "order": 5, + "text": _("Source of flag"), + "description": _("Which source flagged the domain."), + }, + } + + +class DomainsCreateView(DomainAdminMixin, FormMixin, AdminResourceCreateView): + """Configuration for Banner create view.""" + + name = "domains_create" + url = "/domains/create" + title = _("Create domain") + + +class DomainsEditView(DomainAdminMixin, FormMixin, AdminResourceEditView): + name = "domains_edit" + url = "/domains//edit" + title = _("Edit domain") + + +class DomainsDetailView(DomainAdminMixin, AdminResourceDetailView): + url = "/domains/" + name = "domains_details" + title = _("Domain details") + + item_field_list = { + "domain": {"text": _("Domain"), "order": 1}, + "tld": {"text": _("Top-level domain"), "order": 2}, + "status_name": {"text": _("Status"), "order": 3}, + "category_name": {"text": _("Category"), "order": 4}, + "flagged": {"text": _("Flagged"), "order": 5}, + "flagged_source": {"text": _("Source of flag"), "order": 6}, + "created": {"text": _("Created"), "order": 7}, + "updated": {"text": _("Updated"), "order": 8}, + "org": {"text": _("Organisation"), "order": 9}, + "num_users": {"text": _("Users"), "order": 10}, + "num_active": {"text": _("Active"), "order": 11}, + "num_inactive": {"text": _("Inactive"), "order": 12}, + "num_confirmed": {"text": _("Confirmed"), "order": 13}, + "num_verified": {"text": _("Verified"), "order": 14}, + "num_blocked": {"text": _("Blocked"), "order": 15}, + } diff --git a/invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/domains_search.html b/invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/domains_search.html new file mode 100644 index 000000000..07b497d1a --- /dev/null +++ b/invenio_app_rdm/administration/templates/semantic-ui/invenio_app_rdm/administration/domains_search.html @@ -0,0 +1,13 @@ +{# +Copyright (C) 2024 CERN. + +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. +#} + +{% extends "invenio_administration/search.html" %} + +{% block javascript %} + {{ super() }} + {{ webpack['invenio-domains-administration.js'] }} +{% endblock %} diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/SetQuotaForm.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/SetQuotaForm.js index 5fbfc95da..21b4e86d3 100644 --- a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/SetQuotaForm.js +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/components/SetQuotaForm.js @@ -151,7 +151,12 @@ export class SetQuotaForm extends Component { /> - + diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/index.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/index.js new file mode 100644 index 000000000..30b6d2c5a --- /dev/null +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/index.js @@ -0,0 +1,27 @@ +// This file is part of InvenioCommunities +// Copyright (C) 2024 CERN. +// +// Invenio 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. + +import { initDefaultSearchComponents } from "@js/invenio_administration"; +import { createSearchAppInit } from "@js/invenio_search_ui"; +import { NotificationController } from "@js/invenio_administration"; +import { SearchResultItemLayout } from "./search"; + +const domContainer = document.getElementById("invenio-search-config"); + +const defaultComponents = initDefaultSearchComponents(domContainer); + +const overridenComponents = { + ...defaultComponents, + "InvenioAdministration.SearchResultItem.layout": SearchResultItemLayout, +}; + +createSearchAppInit( + overridenComponents, + true, + "invenio-search-config", + false, + NotificationController +); diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/SearchResultItemLayout.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/SearchResultItemLayout.js new file mode 100644 index 000000000..760693155 --- /dev/null +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/SearchResultItemLayout.js @@ -0,0 +1,187 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2022 CERN. + * + * Invenio is free software; you can redistribute it and/or modify it + * under the terms of the MIT License; see LICENSE file for more details. + */ + +import { BoolFormatter, DateFormatter, Actions } from "@js/invenio_administration"; +import PropTypes from "prop-types"; +import React, { Component } from "react"; +import { Table, Dropdown, Icon, Button } from "semantic-ui-react"; +import { withState } from "react-searchkit"; +import { AdminUIRoutes } from "@js/invenio_administration/src/routes"; +import { i18next } from "@translations/invenio_app_rdm/i18next"; +import isEmpty from "lodash/isEmpty"; + +class SearchResultItemComponent extends Component { + refreshAfterAction = () => { + const { updateQueryState, currentQueryState } = this.props; + updateQueryState(currentQueryState); + }; + + render() { + const { + title, + resourceName, + result, + displayEdit, + displayDelete, + actions, + idKeyPath, + listUIEndpoint, + } = this.props; + + const resourceHasActions = displayEdit || displayDelete || !isEmpty(actions); + + return ( + + {/**/} + {/*We pass user ID to bulk actions - user moderation API takes user IDs*/} + {/**/} + {/**/} + + {result.domain}   + + + + + + + + {result.tld} + + + + + + + + + {result.num_users} + + + {result.num_active} + + + {result.num_inactive} + + + {result.num_confirmed} + + + {result.num_verified} + + + {result.num_blocked} + + + }> + + (window.location = result.links.admin_users_html)} + /> + + + + + + + + + + ); + } +} + +SearchResultItemComponent.propTypes = { + actions: PropTypes.object.isRequired, + currentQueryState: PropTypes.object.isRequired, + displayDelete: PropTypes.bool.isRequired, + displayEdit: PropTypes.bool.isRequired, + idKeyPath: PropTypes.string.isRequired, + listUIEndpoint: PropTypes.string.isRequired, + resourceName: PropTypes.string.isRequired, + result: PropTypes.object.isRequired, + title: PropTypes.string.isRequired, + updateQueryState: PropTypes.func.isRequired, +}; + +SearchResultItemComponent.defaultProps = {}; + +export const SearchResultItemLayout = withState(SearchResultItemComponent); diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/index.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/index.js new file mode 100644 index 000000000..998f2fcbe --- /dev/null +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/domains/search/index.js @@ -0,0 +1,9 @@ +/* + * This file is part of Invenio. + * Copyright (C) 2024 CERN. + * + * Invenio is free software; you can redistribute it and/or modify it + * under the terms of the MIT License; see LICENSE file for more details. + */ + +export { SearchResultItemLayout } from "./SearchResultItemLayout"; diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/UserActions.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/UserActions.js index 5476f5b9c..dee06ed3b 100644 --- a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/UserActions.js +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/UserActions.js @@ -179,41 +179,44 @@ export class UserActions extends Component {
{useDropdown ? (
- { isUserActive && ( + {isUserActive && ( + )} - {!isUserActive && !isUserBlocked && ( + {!isUserActive && !isUserBlocked && ( + )} - {isUserBlocked && ( + {isUserBlocked && ( + )} } diff --git a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/search/SearchResultItemLayout.js b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/search/SearchResultItemLayout.js index 8a4771219..2559cbb9c 100644 --- a/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/search/SearchResultItemLayout.js +++ b/invenio_app_rdm/theme/assets/semantic-ui/js/invenio_app_rdm/administration/users/search/SearchResultItemLayout.js @@ -44,15 +44,18 @@ class SearchResultItemComponent extends Component { @{result.username} - - { result.identities.orcid && ( - ORCID + {result.identities.orcid && ( + ORCID )} {result.email} @@ -93,36 +96,36 @@ class SearchResultItemComponent extends Component { data-label={i18next.t("Status")} className="word-break-all" > - - - - - + + + + + - }> - - (window.location = result.links.admin_records_html)} /> - (window.location = result.links.admin_drafts_html)}/> - (window.location = result.links.admin_moderation_html)} /> + }> + + (window.location = result.links.admin_records_html)} + /> + (window.location = result.links.admin_drafts_html)} + /> + (window.location = result.links.admin_moderation_html)} + /> diff --git a/invenio_app_rdm/theme/webpack.py b/invenio_app_rdm/theme/webpack.py index 978b6fe76..1d3aa97ec 100644 --- a/invenio_app_rdm/theme/webpack.py +++ b/invenio_app_rdm/theme/webpack.py @@ -36,6 +36,7 @@ "invenio-users-administration": "./js/invenio_app_rdm/administration/users/index.js", "invenio-records-administration": "./js/invenio_app_rdm/administration/records/index.js", "invenio-drafts-administration": "./js/invenio_app_rdm/administration/drafts/index.js", + "invenio-domains-administration": "./js/invenio_app_rdm/administration/domains/index.js", }, dependencies={ "@babel/runtime": "^7.9.0", diff --git a/setup.cfg b/setup.cfg index 8a2f2745d..e06a9e36a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -109,11 +109,16 @@ invenio_celery.tasks = invenio_administration.views = invenio_users_resources_users_list = invenio_app_rdm.administration.users:UsersListView invenio_users_resources_users_details = invenio_app_rdm.administration.users:UsersDetailView + invenio_users_resources_domains_list = invenio_app_rdm.administration.domains:DomainsListView + invenio_users_resources_domains_edit = invenio_app_rdm.administration.domains:DomainsEditView + invenio_users_resources_domains_detail = invenio_app_rdm.administration.domains:DomainsDetailView + invenio_users_resources_domains_create = invenio_app_rdm.administration.domains:DomainsCreateView invenio_requests_user_moderation_list = invenio_app_rdm.administration.user_moderation:UserModerationListView invenio_requests_user_moderation_detail = invenio_app_rdm.administration.user_moderation:UserModerationRequestDetailView invenio_app_rdm_records_list = invenio_app_rdm.administration.records:RecordAdminListView invenio_app_rdm_drafts_list = invenio_app_rdm.administration.records:DraftAdminListView + [build_sphinx] source-dir = docs/ build-dir = docs/_build