Skip to content

Commit

Permalink
service: prevent creating a request if invalid restrictions
Browse files Browse the repository at this point in the history
* Community selection modal checks if the community is
  restricted and disables it if the record is public
* closes inveniosoftware/invenio-app-rdm#2384
  • Loading branch information
jrcastro2 committed Sep 11, 2023
1 parent 2e363f3 commit 06800d4
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CommunityHeaderComponent extends Component {
showCommunitySelectionButton,
disableCommunitySelectionButton,
showCommunityHeader,
record,
} = this.props;
const { modalOpen } = this.state;

Expand Down Expand Up @@ -73,6 +74,7 @@ class CommunityHeaderComponent extends Component {
modalOpen={modalOpen}
chosenCommunity={community}
displaySelected
record={record}
trigger={
<Button
className="community-header-button"
Expand Down Expand Up @@ -119,6 +121,7 @@ CommunityHeaderComponent.propTypes = {
showCommunitySelectionButton: PropTypes.bool.isRequired,
showCommunityHeader: PropTypes.bool.isRequired,
changeSelectedCommunity: PropTypes.func.isRequired,
record: PropTypes.object.isRequired,
};

CommunityHeaderComponent.defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import React, { useContext } from "react";
import { Button, Icon, Label } from "semantic-ui-react";
import { CommunityCompactItem } from "@js/invenio_communities/community";
import { CommunityContext } from "./CommunityContext";
import { InvenioPopup } from "react-invenio-forms";

export const CommunityListItem = ({ result }) => {
export const CommunityListItem = ({ result, record }) => {
const {
setLocalCommunity,
getChosenCommunity,
Expand All @@ -23,17 +24,35 @@ export const CommunityListItem = ({ result }) => {
const { metadata } = result;
const itemSelected = getChosenCommunity()?.id === result.id;
const userMembership = userCommunitiesMemberships[result["id"]];
const invalidPermissionLevel =
record.access.record == "public" && result.access.visibility == "restricted";

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.8, pypi, postgresql14, opensearch2, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.8, pypi, postgresql14, opensearch2, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.8, pypi, postgresql14, elasticsearch7, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.8, pypi, postgresql14, elasticsearch7, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.9, pypi, postgresql14, opensearch2, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.9, pypi, postgresql14, opensearch2, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.9, pypi, postgresql14, elasticsearch7, 16.x)

Expected '===' and instead saw '=='

Check warning on line 28 in invenio_rdm_records/assets/semantic-ui/js/invenio_rdm_records/src/deposit/components/CommunitySelectionModal/CommunityListItem.js

View workflow job for this annotation

GitHub Actions / Tests (3.9, pypi, postgresql14, elasticsearch7, 16.x)

Expected '===' and instead saw '=='

const actions = (
<Button
content={
displaySelected && itemSelected ? i18next.t("Selected") : i18next.t("Select")
}
size="tiny"
positive={displaySelected && itemSelected}
onClick={() => setLocalCommunity(result)}
aria-label={i18next.t("Select {{title}}", { title: metadata.title })}
/>
<>
{invalidPermissionLevel && (
<InvenioPopup
popupId="community-inclusion-info-popup"
size="small"
trigger={
<Icon className="mb-5" color="grey" name="question circle outline" />
}
ariaLabel={i18next.t("Community inclusion information")}
content={i18next.t(
"Submission to this community is only allowed if the record is restricted."
)}
/>
)}
<Button
content={
displaySelected && itemSelected ? i18next.t("Selected") : i18next.t("Select")
}
size="tiny"
positive={displaySelected && itemSelected}
onClick={() => setLocalCommunity(result)}
disabled={invalidPermissionLevel}
aria-label={i18next.t("Select {{title}}", { title: metadata.title })}
/>
</>
);

const extraLabels = userMembership && (
Expand All @@ -55,4 +74,5 @@ export const CommunityListItem = ({ result }) => {

CommunityListItem.propTypes = {
result: PropTypes.object.isRequired,
record: PropTypes.object.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class CommunitySelectionModalComponent extends Component {
modalOpen,
apiConfigs,
handleClose,
record,
} = this.props;

return (
Expand Down Expand Up @@ -93,7 +94,7 @@ export class CommunitySelectionModalComponent extends Component {
</Header>
</Modal.Header>

<CommunitySelectionSearch apiConfigs={apiConfigs} />
<CommunitySelectionSearch apiConfigs={apiConfigs} record={record} />

{extraContentComponents && (
<Modal.Content>{extraContentComponents}</Modal.Content>
Expand All @@ -120,6 +121,7 @@ CommunitySelectionModalComponent.propTypes = {
modalOpen: PropTypes.bool,
apiConfigs: PropTypes.object,
handleClose: PropTypes.func.isRequired,
record: PropTypes.object.isRequired,
};

CommunitySelectionModalComponent.defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { i18next } from "@translations/invenio_rdm_records/i18next";
import React, { Component } from "react";
import { OverridableContext } from "react-overridable";
import { OverridableContext, parametrize } from "react-overridable";
import {
EmptyResults,
Error,
Expand Down Expand Up @@ -47,10 +47,13 @@ export class CommunitySelectionSearch extends Component {
} = this.state;
const {
apiConfigs: { allCommunities, myCommunities },
record,
} = this.props;
const searchApi = new InvenioSearchApi(selectedsearchApi);
const overriddenComponents = {
[`${selectedAppId}.ResultsList.item`]: CommunityListItem,
[`${selectedAppId}.ResultsList.item`]: parametrize(CommunityListItem, {
record: record,
}),
};
return (
<OverridableContext.Provider value={overriddenComponents}>
Expand Down Expand Up @@ -163,6 +166,7 @@ CommunitySelectionSearch.propTypes = {
searchApi: PropTypes.object.isRequired,
}),
}),
record: PropTypes.object.isRequired,
};

CommunitySelectionSearch.defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class SubmitReviewOrPublishComponent extends Component {
showChangeCommunityButton,
showDirectPublishButton,
showSubmitForReviewButton,
record,
...ui
} = this.props;
const { modalOpen } = this.state;
Expand All @@ -52,6 +53,7 @@ class SubmitReviewOrPublishComponent extends Component {
onModalChange={(value) => this.setState({ modalOpen: value })}
modalOpen={modalOpen}
displaySelected
record={record}
chosenCommunity={community}
trigger={
<Button content={i18next.t("Change community")} fluid className="mb-10" />
Expand All @@ -77,6 +79,7 @@ SubmitReviewOrPublishComponent.propTypes = {
showChangeCommunityButton: PropTypes.bool.isRequired,
showDirectPublishButton: PropTypes.bool.isRequired,
showSubmitForReviewButton: PropTypes.bool.isRequired,
record: PropTypes.object.isRequired,
};

SubmitReviewOrPublishComponent.defaultProps = {
Expand Down
4 changes: 1 addition & 3 deletions invenio_rdm_records/requests/community_inclusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from invenio_i18n import lazy_gettext as _
from invenio_records_resources.services.uow import RecordIndexOp
from invenio_requests.customizations import RequestType, actions
from invenio_requests.errors import CannotExecuteActionError

from invenio_rdm_records.services.errors import InvalidAccessRestrictions

Expand Down Expand Up @@ -54,8 +53,7 @@ def execute(self, identity, uow):
assert not record.parent.review

if not is_access_restriction_valid(record, community):
description = InvalidAccessRestrictions.description
raise CannotExecuteActionError(description)
raise InvalidAccessRestrictions()

# set the community to `default` if it is the first
default = not record.parent.communities
Expand Down
6 changes: 6 additions & 0 deletions invenio_rdm_records/requests/community_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
from invenio_i18n import lazy_gettext as _
from invenio_requests.customizations import actions

from .community_inclusion import is_access_restriction_valid
from ..proxies import current_rdm_records_service as service
from .base import ReviewRequest
from ..services.errors import InvalidAccessRestrictions


#
Expand Down Expand Up @@ -42,6 +44,10 @@ def execute(self, identity, uow):
community = self.request.receiver.resolve()
service._validate_draft(identity, draft)

# validate record and community access
if not is_access_restriction_valid(draft, community):
raise InvalidAccessRestrictions()

# Unset review from record (still accessible from request)
# The curator (receiver) should still have access, via the community
# The creator (uploader) should also still have access, because
Expand Down
1 change: 1 addition & 0 deletions invenio_rdm_records/services/communities/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
)
from invenio_rdm_records.proxies import current_rdm_records, current_rdm_records_service
from invenio_rdm_records.requests import CommunityInclusion
from invenio_rdm_records.requests.community_inclusion import is_access_restriction_valid
from invenio_rdm_records.services.errors import (
CommunityAlreadyExists,
InvalidAccessRestrictions,
Expand Down
5 changes: 0 additions & 5 deletions invenio_rdm_records/services/community_inclusion/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from invenio_rdm_records.requests.community_inclusion import (
CommunityInclusion,
is_access_restriction_valid,
)
from invenio_rdm_records.requests.community_submission import CommunitySubmission
from invenio_rdm_records.services.errors import InvalidAccessRestrictions
Expand Down Expand Up @@ -45,10 +44,6 @@ def submit(self, identity, record, community, request, data, uow):
if request.type.type_id not in self.supported_types:
raise ValueError("Invalid request type.")

# validate record and community access
if not is_access_restriction_valid(record, community):
raise InvalidAccessRestrictions()

# All other preconditions can be checked by the action itself which can
# raise appropriate exceptions.
return current_requests_service.execute_action(
Expand Down

0 comments on commit 06800d4

Please sign in to comment.