From 712a43840ea20b0a0f56f3427c7df04ac154d5af Mon Sep 17 00:00:00 2001 From: Javier Romero Castro Date: Tue, 6 Feb 2024 11:02:26 +0100 Subject: [PATCH] systemfields: add parent community * closes https://github.com/zenodo/zenodo-rdm/issues/696 --- .../communities/records/api.py | 2 + .../communities/communities-v1.0.0.json | 4 ++ .../os-v1/communities/communities-v1.0.0.json | 3 + .../os-v2/communities/communities-v1.0.0.json | 3 + .../v7/communities/communities-v1.0.0.json | 3 + .../records/systemfields/parent_community.py | 71 +++++++++++++++++++ .../communities/services/service.py | 25 ++++++- 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 invenio_communities/communities/records/systemfields/parent_community.py diff --git a/invenio_communities/communities/records/api.py b/invenio_communities/communities/records/api.py index 3a38dedb9..7ea72372a 100644 --- a/invenio_communities/communities/records/api.py +++ b/invenio_communities/communities/records/api.py @@ -29,6 +29,7 @@ from invenio_communities.communities.records.systemfields.is_verified import ( IsVerifiedField, ) +from .systemfields.parent_community import ParentCommunityField from ..dumpers.community_theme import CommunityThemeDumperExt from ..dumpers.featured import FeaturedDumperExt @@ -52,6 +53,7 @@ class Community(Record): id = ModelField() slug = ModelField() pid = PIDSlugField("id", "slug") + parent = ParentCommunityField() schema = ConstantField("$schema", "local://communities/communities-v1.0.0.json") diff --git a/invenio_communities/communities/records/jsonschemas/communities/communities-v1.0.0.json b/invenio_communities/communities/records/jsonschemas/communities/communities-v1.0.0.json index 402f69084..31c6b513c 100644 --- a/invenio_communities/communities/records/jsonschemas/communities/communities-v1.0.0.json +++ b/invenio_communities/communities/records/jsonschemas/communities/communities-v1.0.0.json @@ -145,6 +145,10 @@ } } }, + "parent": { + "type": "string", + "description": "Identifier of the parent community." + }, "theme": { "type": "object", "description": "Community theme settings.", diff --git a/invenio_communities/communities/records/mappings/os-v1/communities/communities-v1.0.0.json b/invenio_communities/communities/records/mappings/os-v1/communities/communities-v1.0.0.json index a41abb796..c518772c7 100644 --- a/invenio_communities/communities/records/mappings/os-v1/communities/communities-v1.0.0.json +++ b/invenio_communities/communities/records/mappings/os-v1/communities/communities-v1.0.0.json @@ -50,6 +50,9 @@ "is_deleted": { "type": "boolean" }, + "parent": { + "type": "keyword" + }, "tombstone": { "properties": { "removal_reason": { diff --git a/invenio_communities/communities/records/mappings/os-v2/communities/communities-v1.0.0.json b/invenio_communities/communities/records/mappings/os-v2/communities/communities-v1.0.0.json index a41abb796..c518772c7 100644 --- a/invenio_communities/communities/records/mappings/os-v2/communities/communities-v1.0.0.json +++ b/invenio_communities/communities/records/mappings/os-v2/communities/communities-v1.0.0.json @@ -50,6 +50,9 @@ "is_deleted": { "type": "boolean" }, + "parent": { + "type": "keyword" + }, "tombstone": { "properties": { "removal_reason": { diff --git a/invenio_communities/communities/records/mappings/v7/communities/communities-v1.0.0.json b/invenio_communities/communities/records/mappings/v7/communities/communities-v1.0.0.json index a41abb796..c518772c7 100644 --- a/invenio_communities/communities/records/mappings/v7/communities/communities-v1.0.0.json +++ b/invenio_communities/communities/records/mappings/v7/communities/communities-v1.0.0.json @@ -50,6 +50,9 @@ "is_deleted": { "type": "boolean" }, + "parent": { + "type": "keyword" + }, "tombstone": { "properties": { "removal_reason": { diff --git a/invenio_communities/communities/records/systemfields/parent_community.py b/invenio_communities/communities/records/systemfields/parent_community.py new file mode 100644 index 000000000..d9bbf36eb --- /dev/null +++ b/invenio_communities/communities/records/systemfields/parent_community.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# 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. + +"""Community PID slug field.""" +from uuid import UUID + +from invenio_records.systemfields import SystemField + +from invenio_communities.proxies import current_communities + + +def is_valid_uuid(value): + """Check if the provided value is a valid UUID.""" + try: + UUID(str(value)) + return True + except (ValueError, AttributeError, TypeError): + return False + + +class ParentCommunityField(SystemField): + """System field for parent community.""" + + def __init__(self, key="parent"): + """Create a new ParentCommunityField instance.""" + super().__init__(key=key) + + def obj(self, instance): + """Get the access object.""" + obj = self._get_cache(instance) + if obj is not None: + return obj + + value = self.get_dictkey(instance) + if value: + obj = value + else: + obj = None + + self._set_cache(instance, obj) + return obj + + def set_obj(self, record, obj): + """Set the access object.""" + if is_valid_uuid(obj) or obj is None: + pass + elif isinstance(obj, current_communities.service.record_cls): + obj = str(obj.id) + else: + raise ValueError("Invalid parent community.") + record["parent"] = obj + + def __get__(self, record, owner=None): + """Get the record's access object.""" + if record is None: + # access by class + return self + + # access by object + return self.obj(record) + + def __set__(self, record, obj): + """Set the records access object.""" + self.set_obj(record, obj) + + diff --git a/invenio_communities/communities/services/service.py b/invenio_communities/communities/services/service.py index 20a9f6222..ec7fb50a2 100644 --- a/invenio_communities/communities/services/service.py +++ b/invenio_communities/communities/services/service.py @@ -22,7 +22,7 @@ from invenio_records_resources.services.uow import ( RecordCommitOp, RecordIndexOp, - unit_of_work, + unit_of_work, RecordBulkIndexOp, ) from invenio_requests import current_requests_service from invenio_requests.services.results import EntityResolverExpandableField @@ -474,6 +474,29 @@ def delete_community( if len(requests) > 0: raise OpenRequestsForCommunityDeletionError(len(requests)) + # We want to fetch all the child communities and update them. + # task.apply_async(update_child_comm(parent_slug)) + # import pdb + # pdb.set_trace() + child_communities = self._search( + "search", + identity, + {}, + None, + extra_filter=dsl.query.Bool( + "must", + must=[ + dsl.Q("match", **{"parent": record.slug}), + ], + ), + ).execute() + child_communities = child_communities # Create a list with the slug/id + for child_community in child_communities: + child_record = self.record_cls.pid.resolve(child_community["slug"]) + child_record.parent_community = None + + uow.register(RecordBulkIndexOp(child_communities, indexer=self.indexer)) + # Load tombstone data with the schema data, errors = self.schema_tombstone.load( data or {},