diff --git a/invenio_rdm_records/services/communities/service.py b/invenio_rdm_records/services/communities/service.py index 5d84b2998..d25282924 100644 --- a/invenio_rdm_records/services/communities/service.py +++ b/invenio_rdm_records/services/communities/service.py @@ -203,12 +203,19 @@ def _remove(self, identity, community_id, record): if community_id not in record.parent.communities.ids: raise RecordCommunityMissing(record.id, community_id) - # If config is true and there is only 1 communities left to remove + # Check for permission to remove a community from a record + self.require_permission( + identity, "remove_community", record=record, community_id=community_id + ) is_community_required = current_app.config["RDM_RECORD_ALWAYS_IN_COMMUNITY"] is_last_community = len(record.parent.communities.ids) == 1 - # Then, check for permissions to remove last community + # If community is required for a record and if it is the last community to remove + # Then, only users with special permissions can remove can_remove_last_community = self.check_permission( - identity, "remove_community", record=record, community_id=community_id + identity, + "remove_community_elevated", + record=record, + community_id=community_id, ) if ( is_community_required @@ -216,9 +223,6 @@ def _remove(self, identity, community_id, record): and not can_remove_last_community ): raise CannotRemoveCommunityError() - # check permission here, per community: curator cannot remove another community - elif not can_remove_last_community: - raise PermissionDeniedError("remove_community") # Default community is deleted when the exact same community is removed from the record record.parent.communities.remove(community_id) diff --git a/invenio_rdm_records/services/errors.py b/invenio_rdm_records/services/errors.py index 011460fcc..33c6e5d27 100644 --- a/invenio_rdm_records/services/errors.py +++ b/invenio_rdm_records/services/errors.py @@ -205,16 +205,18 @@ def description(self): class RecordSubmissionClosedCommunityError(PermissionDenied): """Record submission policy forbids non-members from submitting records to community.""" - description = "Submission to this community is only allowed to community members." + description = _( + "Submission to this community is only allowed to community members." + ) class CommunityNotSelectedError(Exception): """Error thrown when a record is being created/updated with less than 1 community.""" - description = "Cannot publish without selecting a community." + description = _("Cannot publish without selecting a community.") class CannotRemoveCommunityError(Exception): """Error thrown when the last community is being removed from the record.""" - description = "Cannot remove. A record should be part of atleast 1 community." + description = _("Cannot remove. A record should be part of at least 1 community.") diff --git a/invenio_rdm_records/services/generators.py b/invenio_rdm_records/services/generators.py index 3754254a1..270476b27 100644 --- a/invenio_rdm_records/services/generators.py +++ b/invenio_rdm_records/services/generators.py @@ -414,25 +414,3 @@ def needs(self, request=None, **kwargs): return [AccessRequestTokenNeed(request["payload"]["token"])] return [] - - -class IfOneCommunity(ConditionalGenerator): - """Conditional generator for records always in communities case.""" - - def _condition(self, record=None, **kwargs): - """Check if the record is associated with zero or one community.""" - if record is None: - return True - rec_communities = record.parent.communities.ids - return len(rec_communities) == 1 - - -class IfAtleastOneCommunity(ConditionalGenerator): - """Conditional generator for records always in communities case.""" - - def _condition(self, record=None, **kwargs): - """Check if the record is associated with zero or one community.""" - if record is None: - return True - rec_communities = record.parent.communities.ids - return len(rec_communities) > 0 diff --git a/invenio_rdm_records/services/permissions.py b/invenio_rdm_records/services/permissions.py index 7abc37db3..de9681569 100644 --- a/invenio_rdm_records/services/permissions.py +++ b/invenio_rdm_records/services/permissions.py @@ -30,13 +30,11 @@ AccessGrant, CommunityInclusionReviewers, GuestAccessRequestToken, - IfAtleastOneCommunity, IfCreate, IfDeleted, IfExternalDOIRecord, IfFileIsLocal, IfNewRecord, - IfOneCommunity, IfRecordDeleted, IfRequestType, IfRestricted, @@ -68,6 +66,7 @@ class RDMRecordPermissionPolicy(RecordPermissionPolicy): RecordOwners(), RecordCommunitiesAction("curate"), AccessGrant("manage"), + Administration(), SystemProcess(), ] can_curate = can_manage + [AccessGrant("edit"), SecretLinks("edit")] @@ -201,17 +200,9 @@ class RDMRecordPermissionPolicy(RecordPermissionPolicy): ), ] # Allow publishing a new record or changes to an existing record. - can_publish = [ - IfConfig( - "RDM_RECORD_ALWAYS_IN_COMMUNITY", - then_=[ - IfAtleastOneCommunity( - then_=can_review, else_=[Administration(), SystemProcess()] - ) - ], - else_=can_review, - ) - ] + can_publish = can_review + # Permission to allow special users to publish a record in special cases + can_publish_elevated = [Administration(), SystemProcess()] # Allow lifting a record or draft. can_lift_embargo = can_manage @@ -221,25 +212,16 @@ class RDMRecordPermissionPolicy(RecordPermissionPolicy): # Who can add record to a community can_add_community = can_manage # Who can remove a community from a record - can_remove_community_ = [ + can_remove_community = [ RecordOwners(), CommunityCurators(), + Administration(), SystemProcess(), ] - can_remove_community = [ - IfConfig( - "RDM_RECORD_ALWAYS_IN_COMMUNITY", - then_=[ - IfOneCommunity( - then_=[Administration(), SystemProcess()], - else_=can_remove_community_, - ) - ], - else_=can_remove_community_, - ) - ] + # Permission to allow special users to remove community in special cases + can_remove_community_elevated = [Administration(), SystemProcess()] # Who can remove records from a community - can_remove_record = [CommunityCurators()] + can_remove_record = [CommunityCurators(), Administration()] # Who can add records to a community in bulk can_bulk_add = [SystemProcess()] diff --git a/invenio_rdm_records/services/services.py b/invenio_rdm_records/services/services.py index 616cb9493..eac5b4814 100644 --- a/invenio_rdm_records/services/services.py +++ b/invenio_rdm_records/services/services.py @@ -415,14 +415,17 @@ def publish(self, identity, id_, uow=None, expand=False): # Get the draft draft = self.draft_cls.pid.resolve(id_, registered_only=False) - # If config is true and there are no communities selected is_community_required = current_app.config["RDM_RECORD_ALWAYS_IN_COMMUNITY"] is_community_missing = len(draft.parent.communities.ids) == 0 - # Then, check for permissions to upload without community + # If community is required for a record and there are no communities selected + # Then, check for permissions to publish without community + can_publish_without_community = self.check_permission( + identity, "publish_elevated", record=draft + ) if ( is_community_required and is_community_missing - and not self.check_permission(identity, "publish", record=draft) + and not can_publish_without_community ): raise CommunityNotSelectedError()