[WEB-3600] fix: private project join issue (#6799)
* fix: private project join issue * chore: return network value * fix: refactor * fix: refactor * fix: type * chore: added restricition for private projects * chore: removed extra validations * chore: added value to access enum --------- Co-authored-by: sangeethailango <sangeethailango21@gmail.com> Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
parent
cebd0b3599
commit
41447e566a
6 changed files with 48 additions and 10 deletions
|
|
@ -179,6 +179,7 @@ class ProjectViewSet(BaseViewSet):
|
||||||
"inbox_view",
|
"inbox_view",
|
||||||
"guest_view_all_features",
|
"guest_view_all_features",
|
||||||
"project_lead",
|
"project_lead",
|
||||||
|
"network",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"created_by",
|
"created_by",
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,17 @@ from rest_framework.permissions import AllowAny
|
||||||
# Module imports
|
# Module imports
|
||||||
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 allow_permission, ROLE
|
from plane.app.permissions import allow_permission, ROLE
|
||||||
|
|
||||||
from plane.db.models import (
|
from plane.db.models import (
|
||||||
ProjectMember,
|
ProjectMember,
|
||||||
Workspace,
|
Workspace,
|
||||||
ProjectMemberInvite,
|
ProjectMemberInvite,
|
||||||
User,
|
User,
|
||||||
WorkspaceMember,
|
WorkspaceMember,
|
||||||
|
Project,
|
||||||
IssueUserProperty,
|
IssueUserProperty,
|
||||||
)
|
)
|
||||||
|
from plane.db.models.project import ProjectNetwork
|
||||||
|
|
||||||
|
|
||||||
class ProjectInvitationsViewset(BaseViewSet):
|
class ProjectInvitationsViewset(BaseViewSet):
|
||||||
|
|
@ -128,6 +128,7 @@ class UserProjectInvitationsViewset(BaseViewSet):
|
||||||
.select_related("workspace", "workspace__owner", "project")
|
.select_related("workspace", "workspace__owner", "project")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@allow_permission([ROLE.ADMIN, ROLE.MEMBER], level="WORKSPACE")
|
||||||
def create(self, request, slug):
|
def create(self, request, slug):
|
||||||
project_ids = request.data.get("project_ids", [])
|
project_ids = request.data.get("project_ids", [])
|
||||||
|
|
||||||
|
|
@ -136,9 +137,18 @@ class UserProjectInvitationsViewset(BaseViewSet):
|
||||||
member=request.user, workspace__slug=slug, is_active=True
|
member=request.user, workspace__slug=slug, is_active=True
|
||||||
)
|
)
|
||||||
|
|
||||||
if workspace_member.role not in [ROLE.ADMIN.value, ROLE.MEMBER.value]:
|
# Get all the projects
|
||||||
|
projects = Project.objects.filter(
|
||||||
|
id__in=project_ids, workspace__slug=slug
|
||||||
|
).only("id", "network")
|
||||||
|
# Check if user has permission to join each project
|
||||||
|
for project in projects:
|
||||||
|
if (
|
||||||
|
project.network == ProjectNetwork.SECRET.value
|
||||||
|
and workspace_member.role != ROLE.ADMIN.value
|
||||||
|
):
|
||||||
return Response(
|
return Response(
|
||||||
{"error": "You do not have permission to join the project"},
|
{"error": "Only workspace admins can join private project"},
|
||||||
status=status.HTTP_403_FORBIDDEN,
|
status=status.HTTP_403_FORBIDDEN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
# Python imports
|
# Python imports
|
||||||
import pytz
|
import pytz
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -17,6 +18,15 @@ from .base import BaseModel
|
||||||
ROLE_CHOICES = ((20, "Admin"), (15, "Member"), (5, "Guest"))
|
ROLE_CHOICES = ((20, "Admin"), (15, "Member"), (5, "Guest"))
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectNetwork(Enum):
|
||||||
|
SECRET = 0
|
||||||
|
PUBLIC = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def choices(cls):
|
||||||
|
return [(0, "Secret"), (2, "Public")]
|
||||||
|
|
||||||
|
|
||||||
def get_default_props():
|
def get_default_props():
|
||||||
return {
|
return {
|
||||||
"filters": {
|
"filters": {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ export enum EUserPermissions {
|
||||||
|
|
||||||
export type TUserPermissions = EUserPermissions.ADMIN | EUserPermissions.MEMBER | EUserPermissions.GUEST;
|
export type TUserPermissions = EUserPermissions.ADMIN | EUserPermissions.MEMBER | EUserPermissions.GUEST;
|
||||||
|
|
||||||
|
// project network
|
||||||
|
export enum EProjectNetwork {
|
||||||
|
PRIVATE = 0,
|
||||||
|
PUBLIC = 2,
|
||||||
|
}
|
||||||
|
|
||||||
// project pages
|
// project pages
|
||||||
export enum EPageAccess {
|
export enum EPageAccess {
|
||||||
PUBLIC = 0,
|
PUBLIC = 0,
|
||||||
|
|
|
||||||
2
packages/types/src/project/projects.d.ts
vendored
2
packages/types/src/project/projects.d.ts
vendored
|
|
@ -27,6 +27,7 @@ export interface IPartialProject {
|
||||||
inbox_view: boolean;
|
inbox_view: boolean;
|
||||||
guest_view_all_features?: boolean;
|
guest_view_all_features?: boolean;
|
||||||
project_lead?: IUserLite | string | null;
|
project_lead?: IUserLite | string | null;
|
||||||
|
network?: number;
|
||||||
// Timestamps
|
// Timestamps
|
||||||
created_at?: Date;
|
created_at?: Date;
|
||||||
updated_at?: Date;
|
updated_at?: Date;
|
||||||
|
|
@ -50,7 +51,6 @@ export interface IProject extends IPartialProject {
|
||||||
anchor?: string | null;
|
anchor?: string | null;
|
||||||
is_favorite?: boolean;
|
is_favorite?: boolean;
|
||||||
members?: string[];
|
members?: string[];
|
||||||
network?: number;
|
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import useSWR from "swr";
|
||||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// components
|
// components
|
||||||
|
import { EProjectNetwork } from "@plane/types/src/enums";
|
||||||
import { JoinProject } from "@/components/auth-screens";
|
import { JoinProject } from "@/components/auth-screens";
|
||||||
import { LogoSpinner } from "@/components/common";
|
import { LogoSpinner } from "@/components/common";
|
||||||
import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state";
|
import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state";
|
||||||
|
|
@ -70,6 +71,11 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
|
||||||
workspaceSlug.toString(),
|
workspaceSlug.toString(),
|
||||||
projectId?.toString()
|
projectId?.toString()
|
||||||
);
|
);
|
||||||
|
const isWorkspaceAdmin = allowPermissions(
|
||||||
|
[EUserPermissions.ADMIN],
|
||||||
|
EUserPermissionsLevel.WORKSPACE,
|
||||||
|
workspaceSlug.toString()
|
||||||
|
);
|
||||||
|
|
||||||
// Initialize module timeline chart
|
// Initialize module timeline chart
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -168,10 +174,15 @@ export const ProjectAuthWrapper: FC<IProjectAuthWrapper> = observer((props) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// check if the user don't have permission to access the project
|
// check if the user don't have permission to access the project
|
||||||
if (projectExists && projectId && hasPermissionToCurrentProject === false) return <JoinProject />;
|
if (
|
||||||
|
((projectExists?.network && projectExists?.network !== EProjectNetwork.PRIVATE) || isWorkspaceAdmin) &&
|
||||||
|
projectId &&
|
||||||
|
hasPermissionToCurrentProject === false
|
||||||
|
)
|
||||||
|
return <JoinProject />;
|
||||||
|
|
||||||
// check if the project info is not found.
|
// check if the project info is not found.
|
||||||
if (loader === "loaded" && !projectExists && projectId && !!hasPermissionToCurrentProject === false)
|
if (loader === "loaded" && projectId && !!hasPermissionToCurrentProject === false)
|
||||||
return (
|
return (
|
||||||
<div className="grid h-screen place-items-center bg-custom-background-100">
|
<div className="grid h-screen place-items-center bg-custom-background-100">
|
||||||
<DetailedEmptyState
|
<DetailedEmptyState
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue