🛂(frontend) only owner can make a child doc a main doc
We get some side effects when an admin tries to make a child doc a main doc. We ensure that only the owner can do this.
This commit is contained in:
@@ -276,7 +276,6 @@ export const mockedDocument = async (page: Page, data: object) => {
|
|||||||
ancestors_link_role: null,
|
ancestors_link_role: null,
|
||||||
created_at: '2021-09-01T09:00:00Z',
|
created_at: '2021-09-01T09:00:00Z',
|
||||||
user_role: 'owner',
|
user_role: 'owner',
|
||||||
user_roles: ['owner'],
|
|
||||||
...doc,
|
...doc,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ test.describe('Doc grid dnd', () => {
|
|||||||
|
|
||||||
await expect(dragOverlay).toBeVisible();
|
await expect(dragOverlay).toBeVisible();
|
||||||
await expect(dragOverlay).toHaveText(
|
await expect(dragOverlay).toHaveText(
|
||||||
'You must have admin rights to move the document',
|
'You must be the owner to move the document',
|
||||||
);
|
);
|
||||||
|
|
||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
addNewMember,
|
||||||
createDoc,
|
createDoc,
|
||||||
expectLoginPage,
|
expectLoginPage,
|
||||||
keyCloakSignIn,
|
keyCloakSignIn,
|
||||||
@@ -12,8 +13,11 @@ import {
|
|||||||
import { clickOnAddRootSubPage, createRootSubPage } from './sub-pages-utils';
|
import { clickOnAddRootSubPage, createRootSubPage } from './sub-pages-utils';
|
||||||
|
|
||||||
test.describe('Doc Tree', () => {
|
test.describe('Doc Tree', () => {
|
||||||
test('create new sub pages', async ({ page, browserName }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('create new sub pages', async ({ page, browserName }) => {
|
||||||
const [titleParent] = await createDoc(
|
const [titleParent] = await createDoc(
|
||||||
page,
|
page,
|
||||||
'doc-tree-content',
|
'doc-tree-content',
|
||||||
@@ -58,7 +62,6 @@ test.describe('Doc Tree', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('check the reorder of sub pages', async ({ page, browserName }) => {
|
test('check the reorder of sub pages', async ({ page, browserName }) => {
|
||||||
await page.goto('/');
|
|
||||||
await createDoc(page, 'doc-tree-content', browserName, 1);
|
await createDoc(page, 'doc-tree-content', browserName, 1);
|
||||||
const addButton = page.getByRole('button', { name: 'New doc' });
|
const addButton = page.getByRole('button', { name: 'New doc' });
|
||||||
await expect(addButton).toBeVisible();
|
await expect(addButton).toBeVisible();
|
||||||
@@ -165,7 +168,6 @@ test.describe('Doc Tree', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('it detaches a document', async ({ page, browserName }) => {
|
test('it detaches a document', async ({ page, browserName }) => {
|
||||||
await page.goto('/');
|
|
||||||
const [docParent] = await createDoc(
|
const [docParent] = await createDoc(
|
||||||
page,
|
page,
|
||||||
'doc-tree-detach',
|
'doc-tree-detach',
|
||||||
@@ -202,6 +204,55 @@ test.describe('Doc Tree', () => {
|
|||||||
await header.locator('h2').getByText('Docs').click();
|
await header.locator('h2').getByText('Docs').click();
|
||||||
await expect(page.getByText(docChild)).toBeVisible();
|
await expect(page.getByText(docChild)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Only owner can detaches a document', async ({ page, browserName }) => {
|
||||||
|
const [docParent] = await createDoc(
|
||||||
|
page,
|
||||||
|
'doc-tree-detach',
|
||||||
|
browserName,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
await verifyDocName(page, docParent);
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Share' }).click();
|
||||||
|
|
||||||
|
await addNewMember(page, 0, 'Owner', 'impress');
|
||||||
|
|
||||||
|
const list = page.getByTestId('doc-share-quick-search');
|
||||||
|
const currentUser = list.getByTestId(
|
||||||
|
`doc-share-member-row-user@${browserName}.test`,
|
||||||
|
);
|
||||||
|
const currentUserRole = currentUser.getByLabel('doc-role-dropdown');
|
||||||
|
await currentUserRole.click();
|
||||||
|
await page.getByLabel('Administrator').click();
|
||||||
|
await list.click();
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Ok' }).click();
|
||||||
|
|
||||||
|
const { name: docChild } = await createRootSubPage(
|
||||||
|
page,
|
||||||
|
browserName,
|
||||||
|
'doc-tree-detach-child',
|
||||||
|
);
|
||||||
|
|
||||||
|
const docTree = page.getByTestId('doc-tree');
|
||||||
|
await expect(docTree.getByText(docChild)).toBeVisible();
|
||||||
|
await docTree.click();
|
||||||
|
const child = docTree
|
||||||
|
.getByRole('treeitem')
|
||||||
|
.locator('.--docs-sub-page-item')
|
||||||
|
.filter({
|
||||||
|
hasText: docChild,
|
||||||
|
});
|
||||||
|
await child.hover();
|
||||||
|
const menu = child.getByText(`more_horiz`);
|
||||||
|
await menu.click();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.getByRole('menuitem', { name: 'Move to my docs' }),
|
||||||
|
).toHaveAttribute('aria-disabled', 'true');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Doc Tree: Inheritance', () => {
|
test.describe('Doc Tree: Inheritance', () => {
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ export interface Doc {
|
|||||||
numchild: number;
|
numchild: number;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
user_role: Role;
|
user_role: Role;
|
||||||
user_roles: Role[];
|
|
||||||
abilities: {
|
abilities: {
|
||||||
accesses_manage: boolean;
|
accesses_manage: boolean;
|
||||||
accesses_view: boolean;
|
accesses_view: boolean;
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ import { css } from 'styled-components';
|
|||||||
|
|
||||||
import { Box, BoxButton, Icon } from '@/components';
|
import { Box, BoxButton, Icon } from '@/components';
|
||||||
|
|
||||||
import { Doc, ModalRemoveDoc, useCopyDocLink } from '../../doc-management';
|
import {
|
||||||
|
Doc,
|
||||||
|
ModalRemoveDoc,
|
||||||
|
Role,
|
||||||
|
useCopyDocLink,
|
||||||
|
} from '../../doc-management';
|
||||||
import { useCreateChildrenDoc } from '../api/useCreateChildren';
|
import { useCreateChildrenDoc } from '../api/useCreateChildren';
|
||||||
import { useDetachDoc } from '../api/useDetach';
|
import { useDetachDoc } from '../api/useDetach';
|
||||||
import MoveDocIcon from '../assets/doc-extract-bold.svg';
|
import MoveDocIcon from '../assets/doc-extract-bold.svg';
|
||||||
@@ -70,7 +75,7 @@ export const DocTreeItemActions = ({
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
label: t('Move to my docs'),
|
label: t('Move to my docs'),
|
||||||
isDisabled: !doc.abilities.move,
|
isDisabled: doc.user_role !== Role.OWNER,
|
||||||
icon: (
|
icon: (
|
||||||
<Box
|
<Box
|
||||||
$css={css`
|
$css={css`
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export const DocGridContentList = ({ docs }: DocGridContentListProps) => {
|
|||||||
|
|
||||||
const overlayText = useMemo(() => {
|
const overlayText = useMemo(() => {
|
||||||
if (!canDrag) {
|
if (!canDrag) {
|
||||||
return t('You must have admin rights to move the document');
|
return t('You must be the owner to move the document');
|
||||||
}
|
}
|
||||||
if (!canDrop) {
|
if (!canDrop) {
|
||||||
return t('You must be at least the editor of the target document');
|
return t('You must be at least the editor of the target document');
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { Doc } from '@/docs/doc-management';
|
import { Doc, Role } from '@/docs/doc-management';
|
||||||
|
|
||||||
export type DocDragEndData = {
|
export type DocDragEndData = {
|
||||||
sourceDocumentId: string;
|
sourceDocumentId: string;
|
||||||
@@ -26,7 +26,7 @@ export function useDragAndDrop(onDrag: (data: DocDragEndData) => void) {
|
|||||||
const [selectedDoc, setSelectedDoc] = useState<Doc>();
|
const [selectedDoc, setSelectedDoc] = useState<Doc>();
|
||||||
const [canDrop, setCanDrop] = useState<boolean>();
|
const [canDrop, setCanDrop] = useState<boolean>();
|
||||||
|
|
||||||
const canDrag = !!selectedDoc?.abilities.move;
|
const canDrag = selectedDoc?.user_role === Role.OWNER;
|
||||||
|
|
||||||
const mouseSensor = useSensor(MouseSensor, { activationConstraint });
|
const mouseSensor = useSensor(MouseSensor, { activationConstraint });
|
||||||
const touchSensor = useSensor(TouchSensor, { activationConstraint });
|
const touchSensor = useSensor(TouchSensor, { activationConstraint });
|
||||||
|
|||||||
@@ -209,7 +209,6 @@ export class ApiPlugin implements WorkboxPlugin {
|
|||||||
},
|
},
|
||||||
link_reach: LinkReach.RESTRICTED,
|
link_reach: LinkReach.RESTRICTED,
|
||||||
link_role: LinkRole.READER,
|
link_role: LinkRole.READER,
|
||||||
user_roles: [Role.OWNER],
|
|
||||||
user_role: Role.OWNER,
|
user_role: Role.OWNER,
|
||||||
path: '',
|
path: '',
|
||||||
computed_link_reach: LinkReach.RESTRICTED,
|
computed_link_reach: LinkReach.RESTRICTED,
|
||||||
|
|||||||
Reference in New Issue
Block a user