[WEB-2443] fix: project intake edit permission (#5588)

* fix: project intake edit permission

* chore: inbox issue validation changes

* fix: intake edit permission updated

* fix: project invite modal

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2024-09-12 14:44:21 +05:30 committed by GitHub
parent aed2f2dd47
commit 33dd5fe8cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 57 additions and 35 deletions

View file

@ -170,6 +170,7 @@ class InboxIssueViewSet(BaseViewSet):
inbox_id = Inbox.objects.get( inbox_id = Inbox.objects.get(
workspace__slug=slug, project_id=project_id workspace__slug=slug, project_id=project_id
) )
project = Project.objects.get(pk=project_id)
filters = issue_filters(request.GET, "GET", "issue__") filters = issue_filters(request.GET, "GET", "issue__")
inbox_issue = ( inbox_issue = (
InboxIssue.objects.filter( InboxIssue.objects.filter(
@ -199,13 +200,16 @@ class InboxIssueViewSet(BaseViewSet):
if inbox_status: if inbox_status:
inbox_issue = inbox_issue.filter(status__in=inbox_status) inbox_issue = inbox_issue.filter(status__in=inbox_status)
if ProjectMember.objects.filter( if (
workspace__slug=slug, ProjectMember.objects.filter(
project_id=project_id, workspace__slug=slug,
member=request.user, project_id=project_id,
role=5, member=request.user,
is_active=True, role=5,
).exists(): is_active=True,
).exists()
and not project.guest_view_all_features
):
inbox_issue = inbox_issue.filter(created_by=request.user) inbox_issue = inbox_issue.filter(created_by=request.user)
return self.paginate( return self.paginate(
request=request, request=request,
@ -517,6 +521,7 @@ class InboxIssueViewSet(BaseViewSet):
allowed_roles=[ allowed_roles=[
ROLE.ADMIN, ROLE.ADMIN,
ROLE.MEMBER, ROLE.MEMBER,
ROLE.GUEST,
], ],
creator=True, creator=True,
model=Issue, model=Issue,
@ -525,6 +530,7 @@ class InboxIssueViewSet(BaseViewSet):
inbox_id = Inbox.objects.get( inbox_id = Inbox.objects.get(
workspace__slug=slug, project_id=project_id workspace__slug=slug, project_id=project_id
) )
project = Project.objects.get(pk=project_id)
inbox_issue = ( inbox_issue = (
InboxIssue.objects.select_related("issue") InboxIssue.objects.select_related("issue")
.prefetch_related( .prefetch_related(
@ -551,6 +557,21 @@ class InboxIssueViewSet(BaseViewSet):
) )
.get(inbox_id=inbox_id.id, issue_id=pk, project_id=project_id) .get(inbox_id=inbox_id.id, issue_id=pk, project_id=project_id)
) )
if (
ProjectMember.objects.filter(
workspace__slug=slug,
project_id=project_id,
member=request.user,
role=5,
is_active=True,
).exists()
and not project.guest_view_all_features
and not inbox_issue.created_by == request.user
):
return Response(
{"error": "You are not allowed to view this issue"},
status=status.HTTP_400_BAD_REQUEST,
)
issue = InboxIssueDetailSerializer(inbox_issue).data issue = InboxIssueDetailSerializer(inbox_issue).data
return Response( return Response(
issue, issue,

View file

@ -17,7 +17,7 @@ from rest_framework.permissions import AllowAny
from .base import BaseViewSet, BaseAPIView from .base import BaseViewSet, BaseAPIView
from plane.app.serializers import ProjectMemberInviteSerializer from plane.app.serializers import ProjectMemberInviteSerializer
from plane.app.permissions import ProjectBasePermission from plane.app.permissions import allow_permission, ROLE
from plane.db.models import ( from plane.db.models import (
ProjectMember, ProjectMember,
@ -35,10 +35,6 @@ class ProjectInvitationsViewset(BaseViewSet):
search_fields = [] search_fields = []
permission_classes = [
ProjectBasePermission,
]
def get_queryset(self): def get_queryset(self):
return self.filter_queryset( return self.filter_queryset(
super() super()
@ -49,6 +45,7 @@ class ProjectInvitationsViewset(BaseViewSet):
.select_related("workspace", "workspace__owner") .select_related("workspace", "workspace__owner")
) )
@allow_permission([ROLE.ADMIN])
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
emails = request.data.get("emails", []) emails = request.data.get("emails", [])
@ -59,24 +56,21 @@ class ProjectInvitationsViewset(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
requesting_user = ProjectMember.objects.get( for email in emails:
workspace__slug=slug, workspace_role = WorkspaceMember.objects.filter(
project_id=project_id, workspace__slug=slug,
member_id=request.user.id, member__email=email.get("email"),
) is_active=True,
).role
# Check if any invited user has an higher role if workspace_role in [5, 20] and workspace_role != email.get(
if len( "role", 5
[ ):
email return Response(
for email in emails {
if int(email.get("role", 5)) > requesting_user.role "error": "You cannot invite a user with different role than workspace role"
] },
): )
return Response(
{"error": "You cannot invite a user with higher role"},
status=status.HTTP_400_BAD_REQUEST,
)
workspace = Workspace.objects.get(slug=slug) workspace = Workspace.objects.get(slug=slug)

View file

@ -5,7 +5,7 @@ import useSWR from "swr";
import { ContentWrapper } from "@plane/ui"; import { ContentWrapper } from "@plane/ui";
import { InboxIssueActionsHeader, InboxIssueMainContent } from "@/components/inbox"; import { InboxIssueActionsHeader, InboxIssueMainContent } from "@/components/inbox";
// hooks // hooks
import { useProjectInbox, useUserPermissions } from "@/hooks/store"; import { useProjectInbox, useUser, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router"; import { useAppRouter } from "@/hooks/use-app-router";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
@ -34,9 +34,10 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
// states // states
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
// hooks // hooks
const { data: currentUser } = useUser();
const { currentTab, fetchInboxIssueById, getIssueInboxByIssueId, getIsIssueAvailable } = useProjectInbox(); const { currentTab, fetchInboxIssueById, getIssueInboxByIssueId, getIsIssueAvailable } = useProjectInbox();
const inboxIssue = getIssueInboxByIssueId(inboxIssueId); const inboxIssue = getIssueInboxByIssueId(inboxIssueId);
const { allowPermissions } = useUserPermissions(); const { allowPermissions, projectPermissionsByWorkspaceSlugAndProjectId } = useUserPermissions();
// derived values // derived values
const isIssueAvailable = getIsIssueAvailable(inboxIssueId?.toString() || ""); const isIssueAvailable = getIsIssueAvailable(inboxIssueId?.toString() || "");
@ -61,7 +62,13 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
} }
); );
const isEditable = allowPermissions([EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.PROJECT); const isEditable = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
EUserPermissionsLevel.PROJECT
);
const isGuest = projectPermissionsByWorkspaceSlugAndProjectId(workspaceSlug, projectId) === EUserPermissions.GUEST;
const isOwner = inboxIssue.issue.created_by === currentUser?.id;
const readOnly = !isOwner && isGuest;
if (!inboxIssue) return <></>; if (!inboxIssue) return <></>;
@ -87,7 +94,7 @@ export const InboxContentRoot: FC<TInboxContentRoot> = observer((props) => {
workspaceSlug={workspaceSlug} workspaceSlug={workspaceSlug}
projectId={projectId} projectId={projectId}
inboxIssue={inboxIssue} inboxIssue={inboxIssue}
isEditable={isEditable && !isIssueDisabled} isEditable={isEditable && !isIssueDisabled && !readOnly}
isSubmitting={isSubmitting} isSubmitting={isSubmitting}
setIsSubmitting={setIsSubmitting} setIsSubmitting={setIsSubmitting}
/> />

View file

@ -173,10 +173,10 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
const currentMemberWorkspaceRole = getWorkspaceMemberDetails(value)?.role; const currentMemberWorkspaceRole = getWorkspaceMemberDetails(value)?.role;
if (!value || !currentMemberWorkspaceRole) return ROLE; if (!value || !currentMemberWorkspaceRole) return ROLE;
const isGuest = [EUserPermissions.GUEST].includes(currentMemberWorkspaceRole); const isGuestOROwner = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(currentMemberWorkspaceRole);
return Object.fromEntries( return Object.fromEntries(
Object.entries(ROLE).filter(([key]) => !isGuest || [5].includes(parseInt(key))) Object.entries(ROLE).filter(([key]) => !isGuestOROwner || [currentMemberWorkspaceRole].includes(parseInt(key)))
); );
}; };