Skip to content

Commit 4033580

Browse files
committed
Merge remote-tracking branch 'origin/next' into stable
2 parents e603e84 + 800b195 commit 4033580

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+817
-44
lines changed

packages/api-aco/__tests__/flp.tasks.test.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,70 @@ describe("Folder Level Permissions - UPDATE FLP - Simple", () => {
323323
}
324324
]
325325
});
326+
327+
// Update child folder with its own permissions
328+
await context.aco.folder.update(childFolder.id, {
329+
permissions: [
330+
{
331+
target: "admin:5678",
332+
level: "editor"
333+
}
334+
]
335+
});
336+
337+
{
338+
// Check child folder
339+
const updatedChildFlp = await context.aco.flp.get(childFolder.id);
340+
expect(updatedChildFlp).toMatchObject({
341+
id: childFolder.id,
342+
type,
343+
slug: childFolder.slug,
344+
parentId: parentFolder.id,
345+
permissions: [
346+
{
347+
target: "admin:5678",
348+
level: "editor"
349+
},
350+
{
351+
target: "admin:1234",
352+
level: "viewer",
353+
inheritedFrom: `parent:${parentFolder.id}`
354+
}
355+
]
356+
});
357+
}
358+
359+
// Update the parent folder removing all permissions
360+
await context.aco.folder.update(parentFolder.id, {
361+
permissions: []
362+
});
363+
364+
// Check parent folder
365+
const updatedParentFlp = await context.aco.flp.get(parentFolder.id);
366+
expect(updatedParentFlp).toMatchObject({
367+
id: parentFolder.id,
368+
type,
369+
slug: parentFolder.slug,
370+
parentId: ROOT_FOLDER,
371+
permissions: []
372+
});
373+
374+
{
375+
// Check child folder
376+
const updatedChildFlp = await context.aco.flp.get(childFolder.id);
377+
expect(updatedChildFlp).toMatchObject({
378+
id: childFolder.id,
379+
type,
380+
slug: childFolder.slug,
381+
parentId: parentFolder.id,
382+
permissions: [
383+
{
384+
target: "admin:5678",
385+
level: "editor"
386+
}
387+
]
388+
});
389+
}
326390
});
327391
});
328392

@@ -644,6 +708,53 @@ describe("Folder Level Permissions - UPDATE FLP - Complex", () => {
644708
}
645709
}
646710

711+
// Update level2 with its empty permissions: it should always inherit permissions from level1 and propagate them down
712+
await context.aco.folder.update(level2.id, {
713+
permissions: []
714+
});
715+
716+
// Verify level2 has no permissions
717+
for (let i = 0; i < folders.length; i++) {
718+
const folder = folders[i];
719+
const flp = await context.aco.flp.get(folder.id);
720+
721+
const expectedPath = folders
722+
.slice(0, i + 1)
723+
.map(f => f.slug)
724+
.join("/");
725+
726+
if (i === 0) {
727+
expect(flp).toMatchObject({
728+
id: folder.id,
729+
type,
730+
slug: folder.slug,
731+
parentId: ROOT_FOLDER,
732+
path: `${ROOT_FOLDER}/${expectedPath}`,
733+
permissions: [
734+
{
735+
target: "admin:user1",
736+
level: "viewer"
737+
}
738+
]
739+
});
740+
} else {
741+
expect(flp).toMatchObject({
742+
id: folder.id,
743+
type,
744+
slug: folder.slug,
745+
parentId: folders[i - 1].id,
746+
path: `${ROOT_FOLDER}/${expectedPath}`,
747+
permissions: [
748+
{
749+
target: "admin:user1",
750+
level: "viewer",
751+
inheritedFrom: `parent:${folders[i - 1].id}`
752+
}
753+
]
754+
});
755+
}
756+
}
757+
647758
// Update level3 with its own permissions
648759
await context.aco.folder.update(level3.id, {
649760
permissions: [

packages/api-aco/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@webiny/handler": "0.0.0",
3535
"@webiny/handler-graphql": "0.0.0",
3636
"@webiny/pubsub": "0.0.0",
37+
"@webiny/shared-aco": "0.0.0",
3738
"@webiny/tasks": "0.0.0",
3839
"@webiny/utils": "0.0.0",
3940
"@webiny/validation": "0.0.0",

packages/api-aco/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export const ROOT_FOLDER = "root";
1+
export * from "@webiny/shared-aco";
22
export const PB_PAGE_TYPE = "PbPage";
33
export const FM_FILE_TYPE = "FmFile";

packages/api-aco/src/flp/flp.types.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
11
import { Topic } from "@webiny/pubsub/types";
22
import { ITaskRunParams } from "@webiny/tasks/types";
33
import { type AcoContext, type Folder } from "~/types";
4+
import type { FolderLevelPermission, FolderPermission } from "@webiny/shared-aco/flp/flp.types";
45

5-
export type FolderAccessLevel = "owner" | "viewer" | "editor" | "public" | "no-access";
6-
7-
export interface FolderPermission {
8-
target: string;
9-
level: FolderAccessLevel;
10-
inheritedFrom?: string;
11-
}
12-
13-
export interface FolderLevelPermission {
14-
id: string;
15-
parentId: string;
16-
slug: string;
17-
path: string;
18-
permissions: FolderPermission[];
19-
type: string;
20-
}
6+
export * from "@webiny/shared-aco/flp/flp.types";
217

228
/********
239
* CRUD operations

packages/api-aco/src/flp/useCases/CreateFlp.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { WebinyError } from "@webiny/error";
22
import { Path } from "~/utils/Path";
3-
import { Permissions } from "./Permissions";
3+
import { Permissions, ROOT_FOLDER } from "@webiny/shared-aco";
44
import type { FolderLevelPermission as IFolderLevelPermission } from "~/flp/flp.types";
55
import type { Folder } from "~/folder/folder.types";
66
import type { AcoContext } from "~/types";
7-
import { ROOT_FOLDER } from "~/constants";
87

98
export class CreateFlp {
109
private context: AcoContext;

packages/api-aco/src/flp/useCases/UpdateFlp.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { WebinyError } from "@webiny/error";
22
import { Path } from "~/utils/Path";
3-
import { Permissions } from "./Permissions";
4-
import { ROOT_FOLDER } from "~/constants";
3+
import { Permissions, ROOT_FOLDER } from "@webiny/shared-aco";
54
import type { AcoContext, Folder, FolderLevelPermission, FolderPermission } from "~/types";
65
import { FOLDER_MODEL_ID } from "~/folder/folder.model";
76

packages/api-aco/tsconfig.build.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
{ "path": "../handler/tsconfig.build.json" },
1515
{ "path": "../handler-graphql/tsconfig.build.json" },
1616
{ "path": "../pubsub/tsconfig.build.json" },
17+
{ "path": "../shared-aco/tsconfig.build.json" },
1718
{ "path": "../tasks/tsconfig.build.json" },
1819
{ "path": "../utils/tsconfig.build.json" },
1920
{ "path": "../validation/tsconfig.build.json" },

packages/api-aco/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
{ "path": "../handler" },
1515
{ "path": "../handler-graphql" },
1616
{ "path": "../pubsub" },
17+
{ "path": "../shared-aco" },
1718
{ "path": "../tasks" },
1819
{ "path": "../utils" },
1920
{ "path": "../validation" },
@@ -58,6 +59,8 @@
5859
"@webiny/handler-graphql": ["../handler-graphql/src"],
5960
"@webiny/pubsub/*": ["../pubsub/src/*"],
6061
"@webiny/pubsub": ["../pubsub/src"],
62+
"@webiny/shared-aco/*": ["../shared-aco/src/*"],
63+
"@webiny/shared-aco": ["../shared-aco/src"],
6164
"@webiny/tasks/*": ["../tasks/src/*"],
6265
"@webiny/tasks": ["../tasks/src"],
6366
"@webiny/utils/*": ["../utils/src/*"],

packages/api-headless-cms-ddb-es/src/dynamoDb/storage/richText.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ export const createRichTextStorageTransformPlugin = () => {
2424
}
2525

2626
try {
27-
return await compressor.getCompressor().decompress(storageValue);
27+
const uncompressed = await compressor.getCompressor().decompress(storageValue);
28+
29+
// We must make sure the rich text value is an object.
30+
// It is possible that it is a string if developers call the API with an already stringified value.
31+
if (typeof uncompressed === "string") {
32+
return JSON.parse(uncompressed);
33+
}
34+
return uncompressed;
2835
} catch {
2936
return storageValue;
3037
}

packages/api-headless-cms-ddb/src/dynamoDb/storage/richText.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ export const createRichTextStorageTransformPlugin = () => {
2727
}
2828

2929
try {
30-
return await compressor.getCompressor().decompress(storageValue);
30+
const uncompressed = await compressor.getCompressor().decompress(storageValue);
31+
32+
// We must make sure the rich text value is an object.
33+
// It is possible that it is a string if developers call the API with an already stringified value.
34+
if (typeof uncompressed === "string") {
35+
return JSON.parse(uncompressed);
36+
}
37+
return uncompressed;
3138
} catch {
3239
return storageValue;
3340
}

0 commit comments

Comments
 (0)