dev: revamp pages authorization (#6094)
This commit is contained in:
parent
9f14167ef5
commit
8c04aa6f51
4 changed files with 48 additions and 30 deletions
|
|
@ -114,7 +114,7 @@ class PageViewSet(BaseViewSet):
|
|||
.distinct()
|
||||
)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
|
||||
def create(self, request, slug, project_id):
|
||||
serializer = PageSerializer(
|
||||
data=request.data,
|
||||
|
|
@ -134,7 +134,7 @@ class PageViewSet(BaseViewSet):
|
|||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
|
||||
def partial_update(self, request, slug, project_id, pk):
|
||||
try:
|
||||
page = Page.objects.get(
|
||||
|
|
@ -234,7 +234,7 @@ class PageViewSet(BaseViewSet):
|
|||
)
|
||||
return Response(data, status=status.HTTP_200_OK)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def lock(self, request, slug, project_id, pk):
|
||||
page = Page.objects.filter(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
|
|
@ -244,7 +244,7 @@ class PageViewSet(BaseViewSet):
|
|||
page.save()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def unlock(self, request, slug, project_id, pk):
|
||||
page = Page.objects.filter(
|
||||
pk=pk, workspace__slug=slug, projects__id=project_id
|
||||
|
|
@ -255,7 +255,7 @@ class PageViewSet(BaseViewSet):
|
|||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def access(self, request, slug, project_id, pk):
|
||||
access = request.data.get("access", 0)
|
||||
page = Page.objects.filter(
|
||||
|
|
@ -296,7 +296,7 @@ class PageViewSet(BaseViewSet):
|
|||
pages = PageSerializer(queryset, many=True).data
|
||||
return Response(pages, status=status.HTTP_200_OK)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def archive(self, request, slug, project_id, pk):
|
||||
page = Page.objects.get(pk=pk, workspace__slug=slug, projects__id=project_id)
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ class PageViewSet(BaseViewSet):
|
|||
|
||||
return Response({"archived_at": str(datetime.now())}, status=status.HTTP_200_OK)
|
||||
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def unarchive(self, request, slug, project_id, pk):
|
||||
page = Page.objects.get(pk=pk, workspace__slug=slug, projects__id=project_id)
|
||||
|
||||
|
|
@ -348,7 +348,7 @@ class PageViewSet(BaseViewSet):
|
|||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@allow_permission([ROLE.ADMIN], creator=True, model=Page)
|
||||
@allow_permission([ROLE.ADMIN], model=Page, creator=True)
|
||||
def destroy(self, request, slug, project_id, pk):
|
||||
page = Page.objects.get(pk=pk, workspace__slug=slug, projects__id=project_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ import { BreadcrumbLink, Logo } from "@/components/common";
|
|||
// constants
|
||||
import { EPageAccess } from "@/constants/page";
|
||||
// hooks
|
||||
import { useEventTracker, useProject, useProjectPages, useUserPermissions } from "@/hooks/store";
|
||||
// plane web hooks
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
|
||||
import { useEventTracker, useProject, useProjectPages } from "@/hooks/store";
|
||||
|
||||
export const PagesListHeader = observer(() => {
|
||||
// states
|
||||
|
|
@ -26,16 +24,9 @@ export const PagesListHeader = observer(() => {
|
|||
const searchParams = useSearchParams();
|
||||
const pageType = searchParams.get("type");
|
||||
// store hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const { createPage } = useProjectPages();
|
||||
const { canCurrentUserCreatePage, createPage } = useProjectPages();
|
||||
const { setTrackElement } = useEventTracker();
|
||||
// auth
|
||||
const canUserCreatePage = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
// handle page create
|
||||
const handleCreatePage = async () => {
|
||||
setIsCreatingPage(true);
|
||||
|
|
@ -87,7 +78,7 @@ export const PagesListHeader = observer(() => {
|
|||
</Breadcrumbs>
|
||||
</div>
|
||||
</Header.LeftItem>
|
||||
{canUserCreatePage ? (
|
||||
{canCurrentUserCreatePage ? (
|
||||
<Header.RightItem>
|
||||
<Button variant="primary" size="sm" onClick={handleCreatePage} loading={isCreatingPage}>
|
||||
{isCreatingPage ? "Adding" : "Add page"}
|
||||
|
|
|
|||
|
|
@ -215,12 +215,15 @@ export class Page implements IPage {
|
|||
*/
|
||||
get canCurrentUserEditPage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
);
|
||||
return this.isCurrentUserOwner || (!!currentUserProjectRole && currentUserProjectRole >= EUserPermissions.MEMBER);
|
||||
const isPagePublic = this.access === EPageAccess.PUBLIC;
|
||||
return (
|
||||
(isPagePublic && !!currentUserProjectRole && currentUserProjectRole >= EUserPermissions.MEMBER) ||
|
||||
(!isPagePublic && this.isCurrentUserOwner)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -228,26 +231,35 @@ export class Page implements IPage {
|
|||
*/
|
||||
get canCurrentUserDuplicatePage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
);
|
||||
return this.isCurrentUserOwner || (!!currentUserProjectRole && currentUserProjectRole >= EUserPermissions.MEMBER);
|
||||
return !!currentUserProjectRole && currentUserProjectRole >= EUserPermissions.MEMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description returns true if the current logged in user can lock the page
|
||||
*/
|
||||
get canCurrentUserLockPage() {
|
||||
return this.isCurrentUserOwner;
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
);
|
||||
return this.isCurrentUserOwner || currentUserProjectRole === EUserPermissions.ADMIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description returns true if the current logged in user can change the access of the page
|
||||
*/
|
||||
get canCurrentUserChangeAccess() {
|
||||
return this.isCurrentUserOwner;
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
);
|
||||
return this.isCurrentUserOwner || currentUserProjectRole === EUserPermissions.ADMIN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -255,7 +267,6 @@ export class Page implements IPage {
|
|||
*/
|
||||
get canCurrentUserArchivePage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
|
|
@ -268,7 +279,6 @@ export class Page implements IPage {
|
|||
*/
|
||||
get canCurrentUserDeletePage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
|
|
@ -281,7 +291,6 @@ export class Page implements IPage {
|
|||
*/
|
||||
get canCurrentUserFavoritePage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import set from "lodash/set";
|
||||
import unset from "lodash/unset";
|
||||
import { makeObservable, observable, runInAction, action, reaction } from "mobx";
|
||||
import { makeObservable, observable, runInAction, action, reaction, computed } from "mobx";
|
||||
import { computedFn } from "mobx-utils";
|
||||
// types
|
||||
import { TPage, TPageFilters, TPageNavigationTabs } from "@plane/types";
|
||||
// helpers
|
||||
import { filterPagesByPageType, getPageName, orderPages, shouldFilterPage } from "@/helpers/page.helper";
|
||||
// plane web constants
|
||||
import { EUserPermissions } from "@/plane-web/constants";
|
||||
// services
|
||||
import { ProjectPageService } from "@/services/page";
|
||||
// store
|
||||
|
|
@ -24,6 +26,7 @@ export interface IProjectPageStore {
|
|||
filters: TPageFilters;
|
||||
// computed
|
||||
isAnyPageAvailable: boolean;
|
||||
canCurrentUserCreatePage: boolean;
|
||||
// helper actions
|
||||
getCurrentProjectPageIds: (pageType: TPageNavigationTabs) => string[] | undefined;
|
||||
getCurrentProjectFilteredPageIds: (pageType: TPageNavigationTabs) => string[] | undefined;
|
||||
|
|
@ -62,6 +65,9 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
data: observable,
|
||||
error: observable,
|
||||
filters: observable,
|
||||
// computed
|
||||
isAnyPageAvailable: computed,
|
||||
canCurrentUserCreatePage: computed,
|
||||
// helper actions
|
||||
updateFilters: action,
|
||||
clearAllFilters: action,
|
||||
|
|
@ -92,6 +98,18 @@ export class ProjectPageStore implements IProjectPageStore {
|
|||
return Object.keys(this.data).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description returns true if the current logged in user can create a page
|
||||
*/
|
||||
get canCurrentUserCreatePage() {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
const currentUserProjectRole = this.store.user.permission.projectPermissionsByWorkspaceSlugAndProjectId(
|
||||
workspaceSlug?.toString() || "",
|
||||
projectId?.toString() || ""
|
||||
);
|
||||
return !!currentUserProjectRole && currentUserProjectRole >= EUserPermissions.MEMBER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description get the current project page ids based on the pageType
|
||||
* @param {TPageNavigationTabs} pageType
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue