[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:
parent
aed2f2dd47
commit
33dd5fe8cc
4 changed files with 57 additions and 35 deletions
|
|
@ -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 (
|
||||||
|
ProjectMember.objects.filter(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
member=request.user,
|
member=request.user,
|
||||||
role=5,
|
role=5,
|
||||||
is_active=True,
|
is_active=True,
|
||||||
).exists():
|
).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,
|
||||||
|
|
|
||||||
|
|
@ -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,23 +56,20 @@ 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_role = WorkspaceMember.objects.filter(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
project_id=project_id,
|
member__email=email.get("email"),
|
||||||
member_id=request.user.id,
|
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
|
|
||||||
for email in emails
|
|
||||||
if int(email.get("role", 5)) > requesting_user.role
|
|
||||||
]
|
|
||||||
):
|
):
|
||||||
return Response(
|
return Response(
|
||||||
{"error": "You cannot invite a user with higher role"},
|
{
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
"error": "You cannot invite a user with different role than workspace role"
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
workspace = Workspace.objects.get(slug=slug)
|
workspace = Workspace.objects.get(slug=slug)
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue