[ACA-1917] Extensions - evaluate actions for locked files (#858)

* locked file evaluator

* add extension reference

* update docs

* disable versioning for locked files

* disable metadata edit for locked files

* update e2e
This commit is contained in:
Cilibiu Bogdan 2018-12-06 17:29:13 +02:00 committed by Denys Vuika
parent db66c72a06
commit 4c274acb3c
6 changed files with 77 additions and 10 deletions

View File

@ -143,6 +143,7 @@ The button will be visible only when the linked rule evaluates to `true`.
| app.selection.file | A single File node is selected. |
| app.selection.file.canShare | User is able to share the selected file. |
| app.selection.file.isShared | A shared node is selected |
| app.selection.file.isLocked | File is locked for editing |
| app.selection.library | A single Library node is selected. |
| app.selection.isPrivateLibrary | A private Library node is selected. |
| app.selection.hasLibraryRole | The selected Library node has a role property. |

View File

@ -59,17 +59,24 @@ describe('Delete and undo delete', () => {
const file4 = `file4-${Utils.random()}.txt`; let file4Id;
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
const folder2 = `folder2-${Utils.random()}`; let folder2Id;
const fileLocked1 = `fileLocked-${Utils.random()}.txt`; let fileLocked1Id;
const folder3 = `folder3-${Utils.random()}`; let folder3Id;
const fileLocked1 = `fileLocked1-${Utils.random()}.txt`; let fileLocked1Id;
const fileLocked2 = `fileLocked2-${Utils.random()}.txt`; let fileLocked2Id;
beforeAll(async (done) => {
file1Id = (await apis.user.nodes.createFile(file1)).entry.id;
file2Id = (await apis.user.nodes.createFile(file2)).entry.id;
folder1Id = (await apis.user.nodes.createFolder(folder1)).entry.id;
folder2Id = (await apis.user.nodes.createFolder(folder2)).entry.id;
await apis.user.nodes.createFile(file3, folder1Id);
file4Id = (await apis.user.nodes.createFile(file4, folder2Id)).entry.id;
await apis.user.nodes.lockFile(file4Id);
folder3Id = (await apis.user.nodes.createFolder(folder3)).entry.id;
fileLocked2Id = (await apis.user.nodes.createFile(fileLocked2, folder3Id)).entry.id;
await apis.user.nodes.lockFile(fileLocked2Id);
fileLocked1Id = (await apis.user.nodes.createFile(fileLocked1)).entry.id;
await apis.user.nodes.lockFile(fileLocked1Id);
@ -90,7 +97,8 @@ describe('Delete and undo delete', () => {
afterAll(async (done) => {
await apis.user.nodes.unlockFile(file4Id);
await apis.user.nodes.unlockFile(fileLocked1Id);
await apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, fileLocked1Id]);
await apis.user.nodes.unlockFile(fileLocked2Id);
await apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, folder3Id, fileLocked1Id]);
await apis.user.search.waitForApi(username, {expect: 0});
done();
});
@ -171,7 +179,7 @@ describe('Delete and undo delete', () => {
});
it('notification on multiple items deletion - all items fail to delete - [C217130]', async () => {
await dataTable.selectMultipleItems([fileLocked1, folder2]);
await dataTable.selectMultipleItems([folder3, folder2]);
await toolbar.openMoreMenu();
await toolbar.menu.clickMenuItem('Delete');
const message = await page.getSnackBarMessage();
@ -339,23 +347,28 @@ describe('Delete and undo delete', () => {
const favoriteFile4 = `favFile4-${Utils.random()}.txt`; let favoriteFile4Id;
const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id;
const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id;
const favoriteFileLocked1 = `favFileLocked-${Utils.random()}.txt`; let favoriteFileLocked1Id;
const favoriteFolder3 = `favFolder3-${Utils.random()}`; let favoriteFolder3Id;
const favoriteFileLocked1 = `favFileLocked1-${Utils.random()}.txt`; let favoriteFileLocked1Id;
const favoriteFileLocked2 = `favFileLocked2-${Utils.random()}.txt`; let favoriteFileLocked2Id;
beforeAll(async (done) => {
favoriteFile1Id = (await apis.user.nodes.createFile(favoriteFile1)).entry.id;
favoriteFile2Id = (await apis.user.nodes.createFile(favoriteFile2)).entry.id;
favoriteFolder1Id = (await apis.user.nodes.createFolder(favoriteFolder1)).entry.id;
favoriteFolder2Id = (await apis.user.nodes.createFolder(favoriteFolder2)).entry.id;
favoriteFolder3Id = (await apis.user.nodes.createFolder(favoriteFolder3)).entry.id;
await apis.user.nodes.createFile(favoriteFile3, favoriteFolder1Id);
favoriteFile4Id = (await apis.user.nodes.createFile(favoriteFile4, favoriteFolder2Id)).entry.id;
favoriteFileLocked2Id = (await apis.user.nodes.createFile(favoriteFileLocked2, favoriteFolder3Id)).entry.id;
await apis.user.nodes.lockFile(favoriteFile4Id);
await apis.user.nodes.lockFile(favoriteFileLocked2Id);
favoriteFileLocked1Id = (await apis.user.nodes.createFile(favoriteFileLocked1)).entry.id;
await apis.user.nodes.lockFile(favoriteFileLocked1Id);
await apis.user.favorites.addFavoritesByIds('file', [ favoriteFile1Id, favoriteFile2Id, favoriteFileLocked1Id ]);
await apis.user.favorites.addFavoritesByIds('folder', [ favoriteFolder1Id, favoriteFolder2Id ]);
await apis.user.favorites.waitForApi({ expect: 5 });
await apis.user.favorites.addFavoritesByIds('folder', [ favoriteFolder1Id, favoriteFolder2Id, favoriteFolder3Id ]);
await apis.user.favorites.waitForApi({ expect: 6 });
await loginPage.loginWith(username);
done();
@ -374,8 +387,9 @@ describe('Delete and undo delete', () => {
afterAll(async (done) => {
await apis.user.nodes.unlockFile(favoriteFile4Id);
await apis.user.nodes.unlockFile(favoriteFileLocked1Id);
await apis.user.nodes.unlockFile(favoriteFileLocked2Id);
await apis.user.nodes.deleteNodesById([
favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id
favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id, favoriteFolder3Id
]);
await apis.user.search.waitForApi(username, {expect: 0});
done();
@ -456,7 +470,7 @@ describe('Delete and undo delete', () => {
});
it('notification on multiple items deletion - all items fail to delete - [C280521]', async () => {
await dataTable.selectMultipleItems([favoriteFileLocked1, favoriteFolder2]);
await dataTable.selectMultipleItems([favoriteFolder3, favoriteFolder2]);
await toolbar.openMoreMenu();
await toolbar.menu.clickMenuItem('Delete');
const message = await page.getSnackBarMessage();

View File

@ -65,6 +65,25 @@ export class MetadataTabComponent {
}
get canUpdateNode() {
return this.node && this.permission.check(this.node, ['update']);
if (this.node) {
if (this.fileIsLocked()) {
return false;
}
return this.permission.check(this.node, ['update']);
}
return false;
}
private fileIsLocked() {
if (!this.node.isFile) {
return false;
}
return (
this.node.isLocked ||
(this.node.properties &&
this.node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
);
}
}

View File

@ -114,6 +114,7 @@ export class CoreExtensionsModule {
'app.selection.file': app.hasFileSelected,
'app.selection.file.canShare': app.canShareFile,
'app.selection.file.isShared': app.isShared,
'app.selection.file.isLocked': app.hasLockedFiles,
'app.selection.library': app.hasLibrarySelected,
'app.selection.isPrivateLibrary': app.isPrivateLibrary,
'app.selection.hasLibraryRole': app.hasLibraryRole,

View File

@ -107,6 +107,10 @@ export function canDeleteSelection(
isNotSearchResults(context, ...args) &&
!context.selection.isEmpty
) {
if (hasLockedFiles(context, ...args)) {
return false;
}
// temp workaround for Search api
if (isFavorites(context, ...args)) {
return true;
@ -244,6 +248,10 @@ export function canUpdateSelectedNode(
if (context.selection && !context.selection.isEmpty) {
const node = context.selection.first;
if (node.entry.isFile && hasLockedFiles(context, ...args)) {
return false;
}
if (node.entry.hasOwnProperty('allowableOperationsOnTarget')) {
return context.permissions.check(node, ['update'], {
target: 'allowableOperationsOnTarget'
@ -269,3 +277,20 @@ export function canUpdateSelectedFolder(
}
return false;
}
export function hasLockedFiles(
context: RuleContext,
...args: RuleParameter[]
): boolean {
return context.selection.nodes.some(node => {
if (!node.entry.isFile) {
return false;
}
return (
node.entry.isLocked ||
(node.entry.properties &&
node.entry.properties['cm:lockType'] === 'READ_ONLY_LOCK')
);
});
}

View File

@ -165,7 +165,14 @@
"type": "core.every",
"parameters": [
{ "type": "rule", "value": "app.selection.file" },
{ "type": "rule", "value": "app.navigation.isNotTrashcan" }
{ "type": "rule", "value": "app.navigation.isNotTrashcan" },
{
"type": "rule",
"value": "core.not",
"parameters": [
{ "type": "rule", "value": "app.selection.file.isLocked" }
]
}
]
},
{