Skip to content

Commit

Permalink
services: Require records community
Browse files Browse the repository at this point in the history
  • Loading branch information
Samk13 committed Jun 28, 2023
1 parent 51d26ad commit 4f020fc
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,7 @@ Pipfile.lock

# pip wheel
pip-wheel-metadata/

# node modules
**/*/node_modules
node_modules
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This file is part of Invenio-RDM-Records
// Copyright (C) 2020-2023 CERN.
// Copyright (C) 2020-2022 Northwestern University.
// Copyright (C) 2023 KTH Royal Institute of Technology.
//
// Invenio-RDM-Records 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 Down Expand Up @@ -40,10 +41,13 @@ class PublishButtonComponent extends Component {
this.closeConfirmModal();
};

isDisabled = (values, isSubmitting, numberOfFiles) => {
isDisabled = (values, isSubmitting, numberOfFiles, permissions) => {
const canPublish = permissions?.can_publish ?? false;
const publishWithCommunity = permissions?.can_publish_with_community_only ?? false;
const hasNoPermission = !canPublish && publishWithCommunity;
const filesEnabled = _get(values, "files.enabled", false);
const filesMissing = filesEnabled && !numberOfFiles;
return isSubmitting || filesMissing;
return isSubmitting || filesMissing || hasNoPermission;
};

render() {
Expand All @@ -54,6 +58,7 @@ class PublishButtonComponent extends Component {
publishWithoutCommunity,
formik,
publishModalExtraContent,
permissions,
...ui
} = this.props;
const { isConfirmModalOpen } = this.state;
Expand All @@ -64,7 +69,7 @@ class PublishButtonComponent extends Component {
return (
<>
<Button
disabled={this.isDisabled(values, isSubmitting, numberOfFiles)}
disabled={this.isDisabled(values, isSubmitting, numberOfFiles, permissions)}
name="publish"
onClick={this.openConfirmModal}
positive
Expand Down Expand Up @@ -126,19 +131,22 @@ PublishButtonComponent.propTypes = {
numberOfFiles: PropTypes.number.isRequired,
formik: PropTypes.object.isRequired,
publishModalExtraContent: PropTypes.string,
permissions: PropTypes.object,
};

PublishButtonComponent.defaultProps = {
buttonLabel: i18next.t("Publish"),
publishWithoutCommunity: false,
actionState: undefined,
publishModalExtraContent: undefined,
permissions: {},
};

const mapStateToProps = (state) => ({
actionState: state.deposit.actionState,
numberOfFiles: Object.values(state.files.entries).length,
publishModalExtraContent: state.deposit.config.publish_modal_extra,
permissions: state.deposit.permissions,
});

export const PublishButton = connect(
Expand Down
7 changes: 7 additions & 0 deletions invenio_rdm_records/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Copyright (C) 2019 Northwestern University.
# Copyright (C) 2021-2023 Graz University of Technology.
# Copyright (C) 2023 TU Wien.
# Copyright (C) 2023 KTH Royal Institute of Technology.
#
# Invenio-RDM-Records 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 Down Expand Up @@ -126,6 +127,12 @@ def always_valid(identifier):
RDM_ALLOW_RESTRICTED_RECORDS = True
"""Allow users to set restricted/private records."""

#
# Record communities
#
RDM_ENSURE_RECORD_COMMUNITY_EXISTS = False
"""Enforces at least one community per record on remove community function."""

#
# Search configuration
#
Expand Down
24 changes: 18 additions & 6 deletions invenio_rdm_records/services/communities/service.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2023 CERN.
# Copyright (C) 2023 KTH Royal Institute of Technology.
#
# Invenio-RDM-Records is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""RDM Record Communities Service."""

from flask import current_app
from invenio_communities.proxies import current_communities
from invenio_i18n import lazy_gettext as _
from invenio_notifications.services.uow import NotificationOp
Expand Down Expand Up @@ -38,6 +40,7 @@
InvalidAccessRestrictions,
OpenRequestAlreadyExists,
RecordCommunityMissing,
RecordCommunityRequired,
)


Expand Down Expand Up @@ -177,6 +180,10 @@ def _remove(self, identity, community_id, record):
self.require_permission(
identity, "remove_community", record=record, community_id=community_id
)
if current_app.config.get("RDM_ENSURE_RECORD_COMMUNITY_EXISTS"):
rec_communities = record.parent.communities.ids
if len(rec_communities) <= 1:
raise RecordCommunityRequired()

# Default community is deleted when the exact same community is removed from the record
record.parent.communities.remove(community_id)
Expand All @@ -196,12 +203,17 @@ def remove(self, identity, id_, data, uow):
)
communities = valid_data["communities"]
processed = []

for community in communities:
community_id = community["id"]
try:
self._remove(identity, community_id, record)
processed.append({"community": community_id})
except (RecordCommunityMissing, PermissionDeniedError) as ex:
except (
RecordCommunityMissing,
PermissionDeniedError,
RecordCommunityRequired,
) as ex:
errors.append(
{
"community": community_id,
Expand All @@ -224,7 +236,7 @@ def search(
search_preference=None,
expand=False,
extra_filter=None,
**kwargs
**kwargs,
):
"""Search for record's communities."""
record = self.record_cls.pid.resolve(id_)
Expand All @@ -241,7 +253,7 @@ def search(
search_preference=search_preference,
expand=expand,
extra_filter=communities_filter,
**kwargs
**kwargs,
)

@staticmethod
Expand Down Expand Up @@ -285,7 +297,7 @@ def search_suggested_communities(
expand=False,
by_membership=False,
extra_filter=None,
**kwargs
**kwargs,
):
"""Search for communities that can be added to a record."""
record = self.record_cls.pid.resolve(id_)
Expand All @@ -305,7 +317,7 @@ def search_suggested_communities(
params=params,
search_preference=search_preference,
extra_filter=communities_filter,
**kwargs
**kwargs,
)

return current_communities.service.search(
Expand All @@ -314,5 +326,5 @@ def search_suggested_communities(
search_preference=search_preference,
expand=expand,
extra_filter=communities_filter,
**kwargs
**kwargs,
)
10 changes: 10 additions & 0 deletions invenio_rdm_records/services/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# Copyright (C) 2021 CERN.
# Copyright (C) 2023 Graz University of Technology.
# Copyright (C) 2023 KTH Royal Institute of Technology.
#
# Invenio-RDM-Records 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 Down Expand Up @@ -142,6 +143,15 @@ def description(self):
)


class RecordCommunityRequired(Exception):
"""Record associated community required."""

@property
def description(self):
"""Exception description."""
return _("One community per record is required.")


class InvalidCommunityVisibility(Exception):
"""Community visibility does not match the content."""

Expand Down
17 changes: 16 additions & 1 deletion invenio_rdm_records/services/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
# Copyright (C) 2019 CERN.
# Copyright (C) 2019 Northwestern University.
# Copyright (C) 2023 TU Wien.
# Copyright (C) 2023 KTH Royal Institute of Technology.
#
# Invenio-RDM-Records is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""Permissions for Invenio RDM Records."""

from invenio_communities.generators import CommunityCurators
from invenio_communities.permissions import CommunityMembers
from invenio_records_permissions.generators import (
AnyUser,
AuthenticatedUser,
Expand Down Expand Up @@ -155,8 +157,21 @@ class RDMRecordPermissionPolicy(RecordPermissionPolicy):
can_delete_draft = can_curate
# Allow creating a new version of an existing published record.
can_new_version = can_curate
can_publish_with_community_only = (
[RecordCommunitiesAction("curate")]
+ [SystemProcess()]
+ [CommunityMembers()]
+ [SecretLinks("edit")]
+ [SubmissionReviewer()]
)
# Allow publishing a new record or changes to an existing record.
can_publish = can_review
can_publish = [
IfConfig(
"RDM_ENSURE_RECORD_COMMUNITY_EXISTS",
then_=can_publish_with_community_only,
else_=can_review,
),
]
# Allow lifting a record or draft.
can_lift_embargo = can_manage

Expand Down
Loading

0 comments on commit 4f020fc

Please sign in to comment.