Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement service methods for community deletion #1020

Merged
Merged
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
14 changes: 14 additions & 0 deletions invenio_communities/communities/resources/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# This file is part of Invenio.
# Copyright (C) 2016-2021 CERN.
# Copyright (C) 2023 TU Wien.
#
# 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.
Expand All @@ -14,6 +15,7 @@
ResponseHandler,
create_error_handler,
)
from invenio_i18n import lazy_gettext as _
from invenio_records_resources.resources import RecordResourceConfig
from invenio_records_resources.services.base.config import ConfiguratorMixin, FromConfig
from invenio_requests.resources.requests.config import RequestSearchRequestArgsSchema
Expand All @@ -22,6 +24,7 @@
UICommunityJSONSerializer,
)
from invenio_communities.errors import (
CommunityDeletedError,
CommunityFeaturedEntryDoesNotExistError,
LogoSizeLimitError,
OpenRequestsForCommunityDeletionError,
Expand Down Expand Up @@ -54,6 +57,17 @@
description=str(e),
)
),
CommunityDeletedError: create_error_handler(
lambda e: (
HTTPJSONException(code=404, description=_("Community not found"))
if not e.community.tombstone.is_visible
else HTTPJSONException(
code=410,
description=_("Community deleted"),
tombstone=e.community.tombstone.dump(),
)
)
),
}
)

Expand Down
54 changes: 53 additions & 1 deletion invenio_communities/communities/resources/ui_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# This file is part of Invenio.
# Copyright (C) 2022 CERN.
# Copyright (C) 2023 TU Wien.
#
# 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.
Expand All @@ -12,11 +13,14 @@

from flask import g
from flask_resources import BaseObjectSchema
from invenio_i18n import get_locale
from invenio_i18n import lazy_gettext as _
from invenio_records_resources.services.custom_fields import CustomFieldsSchemaUI
from invenio_vocabularies.contrib.awards.serializer import AwardL10NItemSchema
from invenio_vocabularies.contrib.funders.serializer import FunderL10NItemSchema
from invenio_vocabularies.resources import VocabularyL10Schema
from marshmallow import Schema, fields
from marshmallow import Schema, fields, post_dump
from marshmallow_utils.fields import FormatEDTF as FormatEDTF_

from invenio_communities.proxies import current_communities

Expand All @@ -30,6 +34,44 @@ def _community_permission_check(action, community, identity):
).allows(identity)


def mask_removed_by(obj):
"""Mask information about who removed the community."""
return_value = _("Unknown")
removed_by = obj.get("removed_by", None)

if removed_by is not None:
user = removed_by.get("user", None)

if user == "system":
return_value = _("System (automatic)")
elif user is not None:
return_value = _("User")

return return_value


# Partial to make short definitions in below schema.
FormatEDTF = partial(FormatEDTF_, locale=get_locale)


class TombstoneSchema(Schema):
"""Schema for a record tombstone."""

removal_reason = fields.Nested(VocabularyL10Schema, attribute="removal_reason")

note = fields.String(attribute="note")

removed_by = fields.Function(mask_removed_by)

removal_date_l10n_medium = FormatEDTF(attribute="removal_date", format="medium")

removal_date_l10n_long = FormatEDTF(attribute="removal_date", format="long")

citation_text = fields.String(attribute="citation_text")

is_visible = fields.Boolean(attribute="is_visible")


class FundingSchema(Schema):
"""Schema for dumping types in the UI."""

Expand All @@ -47,6 +89,8 @@ class UICommunitySchema(BaseObjectSchema):
attribute="metadata.funding",
)

tombstone = fields.Nested(TombstoneSchema, attribute="tombstone")

# Custom fields
custom_fields = fields.Nested(
partial(CustomFieldsSchemaUI, fields_var="COMMUNITIES_CUSTOM_FIELDS")
Expand All @@ -64,6 +108,14 @@ def get_permissions(self, obj):
)
return {"can_include_directly": can_include_directly, "can_update": can_update}

@post_dump
def hide_tombstone(self, obj, **kwargs):
"""Hide the tombstone information if it's not visible."""
if not obj.get("tombstone", {}).get("is_visible", False):
obj.pop("tombstone", None)

return obj


class TypesSchema(Schema):
"""Schema for dumping types in the UI."""
Expand Down
41 changes: 41 additions & 0 deletions invenio_communities/communities/services/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from invenio_access.permissions import system_identity, system_process
from invenio_db import db
from invenio_i18n import lazy_gettext as _
from invenio_i18n.proxies import current_i18n
from invenio_oaiserver.models import OAISet
from invenio_pidstore.errors import PIDDeletedError, PIDDoesNotExistError
from invenio_records_resources.services.records.components import (
Expand All @@ -26,6 +27,7 @@
from ...proxies import current_roles
from ...utils import on_user_membership_change
from ..records.systemfields.access import VisibilityEnum
from ..records.systemfields.deletion_status import CommunityDeletionStatusEnum


class PIDComponent(ServiceComponent):
Expand Down Expand Up @@ -232,6 +234,44 @@ def update(self, identity, data=None, record=None, **kwargs):
record.custom_fields = data.get("custom_fields", {})


class CommunityDeletionComponent(ServiceComponent):
"""Service component for record deletion."""

def delete_community(self, identity, data=None, record=None, **kwargs):
"""Set the community's deletion status and tombstone information."""
# Set the record's deletion status and tombstone information
record.deletion_status = CommunityDeletionStatusEnum.DELETED
record.tombstone = data

# Set `removed_by` information for the tombstone
record.tombstone.removed_by = identity.id

def update_tombstone(self, identity, data=None, record=None, **kwargs):
"""Update the community's tombstone information."""
record.tombstone = data

def restore_community(self, identity, data=None, record=None, **kwargs):
"""Reset the community's deletion status and tombstone information."""
record.deletion_status = CommunityDeletionStatusEnum.PUBLISHED

# Remove the tombstone information
record.tombstone = None

# Set a record to 'metadata only' if its files got cleaned up
if not record.files.entries:
record.files.enabled = False

def mark_community(self, identity, data=None, record=None, **kwargs):
"""Mark the community for purge."""
record.deletion_status = CommunityDeletionStatusEnum.MARKED
record.tombstone = record.tombstone

def unmark_community(self, identity, data=None, record=None, **kwargs):
"""Unmark the community for purge, resetting it to soft-deleted state."""
record.deletion_status = CommunityDeletionStatusEnum.DELETED
record.tombstone = record.tombstone


DefaultCommunityComponents = [
MetadataComponent,
CustomFieldsComponent,
Expand All @@ -241,4 +281,5 @@ def update(self, identity, data=None, record=None, **kwargs):
OwnershipComponent,
FeaturedCommunityComponent,
OAISetComponent,
CommunityDeletionComponent,
]
3 changes: 2 additions & 1 deletion invenio_communities/communities/services/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
)

from ...permissions import CommunityPermissionPolicy, can_perform_action
from ..schema import CommunityFeaturedSchema, CommunitySchema
from ..schema import CommunityFeaturedSchema, CommunitySchema, TombstoneSchema
from .components import DefaultCommunityComponents
from .links import CommunityLink
from .sort import CommunitiesSortParam
Expand Down Expand Up @@ -95,6 +95,7 @@ class CommunityServiceConfig(RecordServiceConfig, ConfiguratorMixin):
# Service schema
schema = CommunitySchema
schema_featured = CommunityFeaturedSchema
schema_tombstone = TombstoneSchema

result_list_cls_featured = CommunityFeaturedList
result_item_cls_featured = FeaturedCommunityItem
Expand Down
Loading