diff --git a/assets/js/components/deposit/overrides/CreatibutorsRemoteSelectItem.js b/assets/js/components/deposit/overrides/CreatibutorsRemoteSelectItem.js new file mode 100644 index 0000000..87067cf --- /dev/null +++ b/assets/js/components/deposit/overrides/CreatibutorsRemoteSelectItem.js @@ -0,0 +1,50 @@ +// This file is part of CDS RDM +// Copyright (C) 2024 CERN. +// +// CDS 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 _get from "lodash/get"; +import _truncate from "lodash/truncate"; +import _upperCase from "lodash/upperCase"; +import React from "react"; +import PropTypes from "prop-types"; +import { Header, Image } from "semantic-ui-react"; + +export const CDSCreatibutorsRemoteSelectItem = ({ creatibutor, isOrganization, idString, affNames }) => { + + if (creatibutor.props?.is_cern) { + const cmp = ( + + + {creatibutor.props.email} + + ) + idString.push(cmp) + } + + return ( +
+ {creatibutor.name} {idString.length ? <>({idString}) : null} + + {isOrganization ? creatibutor.acronym : affNames} + +
+ ); +}; + +CDSCreatibutorsRemoteSelectItem.propTypes = { + creatibutor: PropTypes.object.isRequired, + isOrganization: PropTypes.bool.isRequired, + idString: PropTypes.array, + affNames: PropTypes.string, +}; + +CDSCreatibutorsRemoteSelectItem.defaultProps = { + idString: [], + affNames: "", +}; \ No newline at end of file diff --git a/assets/js/invenio_app_rdm/overridableRegistry/mapping.js b/assets/js/invenio_app_rdm/overridableRegistry/mapping.js index 16eeb49..cd12b5a 100644 --- a/assets/js/invenio_app_rdm/overridableRegistry/mapping.js +++ b/assets/js/invenio_app_rdm/overridableRegistry/mapping.js @@ -2,10 +2,12 @@ import { CDSCarouselItem } from "../../components/communities_carousel/overrides import { CDSCommunitiesCarousel } from "../../components/communities_carousel/overrides/CommunitiesCarousel"; import { CDSRecordsList } from "../../components/frontpage/overrides/RecordsList"; import { CDSRecordsResultsListItem } from "../../components/frontpage/overrides/RecordsResultsListItem"; +import { CDSCreatibutorsRemoteSelectItem } from "../../components/deposit/overrides/CreatibutorsRemoteSelectItem"; export const overriddenComponents = { "InvenioAppRdm.RecordsList.layout": CDSRecordsList, "InvenioAppRdm.RecordsResultsListItem.layout": CDSRecordsResultsListItem, "InvenioCommunities.CommunitiesCarousel.layout": CDSCommunitiesCarousel, "InvenioCommunities.CarouselItem.layout": CDSCarouselItem, + "CreatibutorsModal.RemoteSelectItem.content": CDSCreatibutorsRemoteSelectItem, }; diff --git a/site/cds_rdm/ldap/api.py b/site/cds_rdm/ldap/api.py index becabf1..4b95651 100644 --- a/site/cds_rdm/ldap/api.py +++ b/site/cds_rdm/ldap/api.py @@ -18,7 +18,7 @@ from invenio_users_resources.services.users.tasks import reindex_users from cds_rdm.ldap.client import LdapClient -from cds_rdm.ldap.user_importer import LdapUserImporter +from cds_rdm.ldap.user_importer import LdapUserImporter, update_or_create_names_vocabularies from cds_rdm.ldap.utils import InvenioUser, serialize_ldap_user, user_exists @@ -102,6 +102,17 @@ def update_invenio_users_from_ldap(remote_accounts, ldap_users_map, log_func): if has_changed: invenio_user.update(ldap_user) + try: + update_or_create_names_vocabularies(ldap_user) + except Exception as e: + log_func( + "update_names_vocabularies_error", + dict( + user_id=invenio_user.user_id, + person_id=ldap_user["remote_account_person_id"], + ), + is_error=True, + ) user_ids.append(invenio_user.user_id) db.session.commit() log_func( diff --git a/site/cds_rdm/ldap/client.py b/site/cds_rdm/ldap/client.py index 8f40bb2..5b87bd8 100644 --- a/site/cds_rdm/ldap/client.py +++ b/site/cds_rdm/ldap/client.py @@ -41,6 +41,8 @@ class LdapClient(object): "uidNumber", "cn", "name", + "sn", + "givenName", ] def __init__(self, ldap_url=None): diff --git a/site/cds_rdm/ldap/user_importer.py b/site/cds_rdm/ldap/user_importer.py index 485b58a..ba3d60c 100644 --- a/site/cds_rdm/ldap/user_importer.py +++ b/site/cds_rdm/ldap/user_importer.py @@ -13,8 +13,46 @@ from invenio_db import db from invenio_oauthclient.models import RemoteAccount, UserIdentity from invenio_userprofiles.models import UserProfile +from invenio_records_resources.proxies import current_service_registry +from invenio_access.permissions import system_identity +from sqlalchemy.orm.exc import NoResultFound +def update_or_create_names_vocabularies(ldap_user): + """Update names vocabularies.""" + names_service = current_service_registry.get("names") + name_data = { + "id": ldap_user["remote_account_person_id"], + "name": ldap_user["user_profile_full_name"], + "given_name": ldap_user["given_name"], + "family_name": ldap_user["family_name"], + "props": { + "email": ldap_user["user_email"], + "username": ldap_user["user_username"], + "department": ldap_user["remote_account_department"], + "is_cern": True, + }, + "affiliations": [{"name": "CERN"}], + } + + try: + fetched_name = names_service.read(system_identity, ldap_user["remote_account_person_id"]) + # Determine if any updates are necessary + fetched_name_dict = fetched_name.to_dict() + update_needed = False + for key, value in name_data.items(): + if key not in fetched_name_dict or fetched_name_dict[key] != value: + update_needed = True + break + + # Perform update only if necessary + if update_needed: + name = names_service.update(system_identity, fetched_name.id, name_data) + except NoResultFound: + name = names_service.create(system_identity, name_data) + + return name + class LdapUserImporter: """Import ldap users to Invenio RDM records. @@ -70,7 +108,7 @@ def create_invenio_remote_account(self, user_id, ldap_user): keycloak_id=keycloak_id, person_id=employee_id, department=department ), ) - + def import_user(self, ldap_user): """Create Invenio users from LDAP export.""" user = self.create_invenio_user(ldap_user) @@ -85,6 +123,8 @@ def import_user(self, ldap_user): remote_account = self.create_invenio_remote_account(user_id, ldap_user) db.session.add(remote_account) + update_or_create_names_vocabularies(ldap_user) + # Automatically confirm the user confirm_user(user) return user_id diff --git a/site/cds_rdm/ldap/utils.py b/site/cds_rdm/ldap/utils.py index c8e6e86..80e0364 100644 --- a/site/cds_rdm/ldap/utils.py +++ b/site/cds_rdm/ldap/utils.py @@ -14,6 +14,7 @@ from invenio_userprofiles import UserProfile from cds_rdm.ldap.errors import InvalidLdapUser +import hashlib def serialize_ldap_user(ldap_user_data, log_func=None): @@ -33,6 +34,8 @@ def serialize(ldap_user_data): cern_account_type=decoded_data["cernAccountType"], remote_account_person_id=str(decoded_data["employeeID"]), remote_account_department=decoded_data["department"], + family_name=decoded_data["sn"], + given_name=decoded_data["givenName"], ) return serialized_data @@ -125,3 +128,14 @@ def update(self, ldap_user): self.user.email = ldap_user["user_email"] self.user.username = ldap_user["user_username"] self.user_profile.full_name = ldap_user["user_profile_full_name"] + + +def hash_value(value, length=16): + """Return a hashed version of the value.""" + # TODO: we should use a secret to encrypt the value (the repo is public) + value_bytes = value.encode('utf-8') + hash_object = hashlib.sha256() + hash_object.update(value_bytes) + hashed_id = hash_object.hexdigest()[:length] + + return hashed_id \ No newline at end of file