@webiny/api-aco 0.0.0-unstable.7be00a75a9 → 0.0.0-unstable.7c2def32a7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AcoFeature.d.ts +5 -0
- package/AcoFeature.js +134 -0
- package/AcoFeature.js.map +1 -0
- package/AcoFolderSchemaFactory.d.ts +32 -0
- package/AcoFolderSchemaFactory.js +82 -0
- package/AcoFolderSchemaFactory.js.map +1 -0
- package/createAcoGraphQL.d.ts +8 -4
- package/createAcoGraphQL.js +56 -96
- package/createAcoGraphQL.js.map +1 -1
- package/domain/folder/abstractions.d.ts +12 -5
- package/domain/folder/abstractions.js +2 -2
- package/domain/folder/abstractions.js.map +1 -1
- package/domain/folder/folder.model.js +2 -1
- package/domain/folder/folder.model.js.map +1 -1
- package/exports/api/aco/flp.d.ts +1 -0
- package/exports/api/aco/flp.js +1 -0
- package/exports/api/aco/folder.d.ts +2 -1
- package/exports/api/aco/folder.js +1 -1
- package/features/ai/CreateFolderTool.d.ts +49 -0
- package/features/ai/CreateFolderTool.js +58 -0
- package/features/ai/CreateFolderTool.js.map +1 -0
- package/features/ai/CreateTeamTool.d.ts +48 -0
- package/features/ai/CreateTeamTool.js +56 -0
- package/features/ai/CreateTeamTool.js.map +1 -0
- package/features/ai/DeleteFolderTool.d.ts +48 -0
- package/features/ai/DeleteFolderTool.js +55 -0
- package/features/ai/DeleteFolderTool.js.map +1 -0
- package/features/ai/GrantFolderAccessTool.d.ts +77 -0
- package/features/ai/GrantFolderAccessTool.js +80 -0
- package/features/ai/GrantFolderAccessTool.js.map +1 -0
- package/features/ai/ListFoldersTool.d.ts +47 -0
- package/features/ai/ListFoldersTool.js +57 -0
- package/features/ai/ListFoldersTool.js.map +1 -0
- package/features/ai/ListRolesTool.d.ts +39 -0
- package/features/ai/ListRolesTool.js +48 -0
- package/features/ai/ListRolesTool.js.map +1 -0
- package/features/ai/ListTeamsTool.d.ts +39 -0
- package/features/ai/ListTeamsTool.js +48 -0
- package/features/ai/ListTeamsTool.js.map +1 -0
- package/features/ai/RevokeFolderAccessTool.d.ts +63 -0
- package/features/ai/RevokeFolderAccessTool.js +69 -0
- package/features/ai/RevokeFolderAccessTool.js.map +1 -0
- package/features/ai/assertTargetIsUsable.d.ts +10 -0
- package/features/ai/assertTargetIsUsable.js +14 -0
- package/features/ai/assertTargetIsUsable.js.map +1 -0
- package/features/ai/feature.d.ts +12 -0
- package/features/ai/feature.js +25 -0
- package/features/ai/feature.js.map +1 -0
- package/features/ai/index.d.ts +9 -0
- package/features/ai/index.js +9 -0
- package/features/ai/loadFolderPermissions.d.ts +16 -0
- package/features/ai/loadFolderPermissions.js +14 -0
- package/features/ai/loadFolderPermissions.js.map +1 -0
- package/features/cms/decorators/ListDeletedEntriesWithFlpDecorator.js +1 -0
- package/features/cms/decorators/ListDeletedEntriesWithFlpDecorator.js.map +1 -1
- package/features/cms/decorators/ListEntriesWithFlpDecorator.js +1 -0
- package/features/cms/decorators/ListEntriesWithFlpDecorator.js.map +1 -1
- package/features/cms/decorators/ListLatestEntriesWithFlpDecorator.js +1 -0
- package/features/cms/decorators/ListLatestEntriesWithFlpDecorator.js.map +1 -1
- package/features/cms/decorators/ListPublishedEntriesWithFlpDecorator.js +1 -0
- package/features/cms/decorators/ListPublishedEntriesWithFlpDecorator.js.map +1 -1
- package/features/cms/decorators/MoveEntryWithFlpDecorator.d.ts +1 -1
- package/features/flp/CreateFlp/CreateFlpUseCase.d.ts +3 -3
- package/features/flp/CreateFlp/CreateFlpUseCase.js +4 -4
- package/features/flp/CreateFlp/CreateFlpUseCase.js.map +1 -1
- package/features/flp/CreateFlp/feature.d.ts +1 -6
- package/features/flp/CreateFlp/feature.js +3 -2
- package/features/flp/CreateFlp/feature.js.map +1 -1
- package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.d.ts +8 -5
- package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.js +21 -14
- package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.js.map +1 -1
- package/features/flp/DeleteFlp/DeleteFlpUseCase.d.ts +3 -3
- package/features/flp/DeleteFlp/DeleteFlpUseCase.js +3 -3
- package/features/flp/DeleteFlp/DeleteFlpUseCase.js.map +1 -1
- package/features/flp/DeleteFlp/feature.d.ts +1 -6
- package/features/flp/DeleteFlp/feature.js +3 -2
- package/features/flp/DeleteFlp/feature.js.map +1 -1
- package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.d.ts +6 -5
- package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.js +16 -13
- package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.js.map +1 -1
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.d.ts +3 -3
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js +6 -6
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js.map +1 -1
- package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.d.ts +25 -0
- package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.js +48 -0
- package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.js.map +1 -0
- package/features/flp/FolderLevelPermissions/index.d.ts +1 -0
- package/features/flp/FolderLevelPermissions/index.js +1 -0
- package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.d.ts +13 -0
- package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.js +26 -0
- package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.js.map +1 -0
- package/features/flp/GetFlp/feature.d.ts +1 -1
- package/features/flp/GetFlp/feature.js +3 -2
- package/features/flp/GetFlp/feature.js.map +1 -1
- package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.d.ts +13 -0
- package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.js +27 -0
- package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.js.map +1 -0
- package/features/flp/ListFlps/feature.d.ts +1 -1
- package/features/flp/ListFlps/feature.js +3 -2
- package/features/flp/ListFlps/feature.js.map +1 -1
- package/features/flp/UpdateFlp/UpdateFlpUseCase.d.ts +15 -8
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js +37 -42
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js.map +1 -1
- package/features/flp/UpdateFlp/abstractions.d.ts +6 -2
- package/features/flp/UpdateFlp/abstractions.js.map +1 -1
- package/features/flp/UpdateFlp/feature.d.ts +1 -6
- package/features/flp/UpdateFlp/feature.js +7 -2
- package/features/flp/UpdateFlp/feature.js.map +1 -1
- package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.d.ts +8 -5
- package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js +21 -16
- package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js.map +1 -1
- package/features/flp/shared/CodeFlpMerger.d.ts +26 -0
- package/features/flp/shared/CodeFlpMerger.js +20 -0
- package/features/flp/shared/CodeFlpMerger.js.map +1 -0
- package/features/flp/shared/CodeFlpPath.d.ts +15 -0
- package/features/flp/shared/CodeFlpPath.js +29 -0
- package/features/flp/shared/CodeFlpPath.js.map +1 -0
- package/features/flp/shared/CodeFlpTarget.d.ts +10 -0
- package/features/flp/shared/CodeFlpTarget.js +26 -0
- package/features/flp/shared/CodeFlpTarget.js.map +1 -0
- package/features/flp/shared/CodeFlpsProvider.d.ts +14 -0
- package/features/flp/shared/CodeFlpsProvider.js +33 -0
- package/features/flp/shared/CodeFlpsProvider.js.map +1 -0
- package/features/flp/shared/abstractions.d.ts +77 -0
- package/features/flp/shared/abstractions.js +19 -0
- package/features/flp/shared/abstractions.js.map +1 -0
- package/features/flp/shared/feature.d.ts +5 -0
- package/features/flp/shared/feature.js +17 -0
- package/features/flp/shared/feature.js.map +1 -0
- package/features/flp/shared/index.d.ts +4 -0
- package/features/flp/shared/index.js +4 -0
- package/features/folder/CreateFolder/CreateFolderRepository.d.ts +3 -3
- package/features/folder/CreateFolder/CreateFolderRepository.js +10 -7
- package/features/folder/CreateFolder/CreateFolderRepository.js.map +1 -1
- package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.d.ts +9 -1
- package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.js +20 -3
- package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.js.map +1 -1
- package/features/folder/DeleteFolder/DeleteFolderRepository.d.ts +3 -3
- package/features/folder/DeleteFolder/DeleteFolderRepository.js +6 -5
- package/features/folder/DeleteFolder/DeleteFolderRepository.js.map +1 -1
- package/features/folder/DeleteFolder/decorators/DeleteFolderWithFolderLevelPermissions.d.ts +1 -1
- package/features/folder/EnsureFolderIsEmpty/EnsureFolderIsEmpty.js +4 -0
- package/features/folder/EnsureFolderIsEmpty/EnsureFolderIsEmpty.js.map +1 -1
- package/features/folder/EnsureHcmsFolderIsEmptyOnDelete/ModelFolderBeforeDeleteHandler.js +4 -0
- package/features/folder/EnsureHcmsFolderIsEmptyOnDelete/ModelFolderBeforeDeleteHandler.js.map +1 -1
- package/features/folder/FolderModelProvider.d.ts +26 -0
- package/features/folder/FolderModelProvider.js +22 -0
- package/features/folder/FolderModelProvider.js.map +1 -0
- package/features/folder/GetAncestors/GetAncestorsRepository.d.ts +3 -3
- package/features/folder/GetAncestors/GetAncestorsRepository.js +6 -5
- package/features/folder/GetAncestors/GetAncestorsRepository.js.map +1 -1
- package/features/folder/GetFolder/GetFolderRepository.d.ts +3 -3
- package/features/folder/GetFolder/GetFolderRepository.js +6 -5
- package/features/folder/GetFolder/GetFolderRepository.js.map +1 -1
- package/features/folder/GetFolder/decorators/GetFolderWithFolderLevelPermissions.d.ts +8 -8
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.d.ts +3 -3
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js +10 -8
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js.map +1 -1
- package/features/folder/ListFolders/ListFoldersRepository.d.ts +3 -3
- package/features/folder/ListFolders/ListFoldersRepository.js +8 -7
- package/features/folder/ListFolders/ListFoldersRepository.js.map +1 -1
- package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.d.ts +11 -0
- package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.js +38 -0
- package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.js.map +1 -0
- package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.d.ts +12 -0
- package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.js +24 -0
- package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.js.map +1 -0
- package/features/folder/NotifyFolderChange/abstractions.d.ts +28 -0
- package/features/folder/NotifyFolderChange/abstractions.js +8 -0
- package/features/folder/NotifyFolderChange/abstractions.js.map +1 -0
- package/features/folder/NotifyFolderChange/feature.d.ts +9 -0
- package/features/folder/NotifyFolderChange/feature.js +13 -0
- package/features/folder/NotifyFolderChange/feature.js.map +1 -0
- package/features/folder/NotifyFolderChange/index.d.ts +2 -0
- package/features/folder/NotifyFolderChange/index.js +2 -0
- package/features/folder/UpdateFolder/UpdateFolderRepository.d.ts +3 -3
- package/features/folder/UpdateFolder/UpdateFolderRepository.js +11 -8
- package/features/folder/UpdateFolder/UpdateFolderRepository.js.map +1 -1
- package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.d.ts +14 -1
- package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js +52 -4
- package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js.map +1 -1
- package/features/folder/shared/abstractions.d.ts +14 -0
- package/features/folder/shared/abstractions.js +4 -1
- package/features/folder/shared/abstractions.js.map +1 -1
- package/filter/filter.gql.d.ts +2 -3
- package/filter/filter.gql.js +61 -27
- package/filter/filter.gql.js.map +1 -1
- package/filter/filter.model.js +2 -1
- package/filter/filter.model.js.map +1 -1
- package/filter/filter.so.d.ts +8 -2
- package/filter/filter.so.js +21 -9
- package/filter/filter.so.js.map +1 -1
- package/flp/flp.types.d.ts +6 -1
- package/flp/index.d.ts +0 -1
- package/flp/index.js +0 -1
- package/flp/tasks/createFlp.task.d.ts +12 -5
- package/flp/tasks/createFlp.task.js +32 -15
- package/flp/tasks/createFlp.task.js.map +1 -1
- package/flp/tasks/deleteFlp.task.d.ts +10 -5
- package/flp/tasks/deleteFlp.task.js +22 -13
- package/flp/tasks/deleteFlp.task.js.map +1 -1
- package/flp/tasks/index.d.ts +0 -1
- package/flp/tasks/index.js +1 -14
- package/flp/tasks/index.js.map +1 -1
- package/flp/tasks/syncFlp.task.d.ts +10 -5
- package/flp/tasks/syncFlp.task.js +34 -13
- package/flp/tasks/syncFlp.task.js.map +1 -1
- package/flp/tasks/updateFlp.task.d.ts +12 -5
- package/flp/tasks/updateFlp.task.js +40 -19
- package/flp/tasks/updateFlp.task.js.map +1 -1
- package/folder/createFolderTypeDefs.js +4 -1
- package/folder/createFolderTypeDefs.js.map +1 -1
- package/folder/folder.gql.d.ts +1 -1
- package/folder/folder.gql.js +10 -4
- package/folder/folder.gql.js.map +1 -1
- package/index.d.ts +1 -6
- package/index.js +1 -11
- package/package.json +25 -26
- package/types.d.ts +1 -2
- package/types.js.map +1 -1
- package/utils/createOperationsWrapper.d.ts +5 -2
- package/utils/createOperationsWrapper.js +5 -5
- package/utils/createOperationsWrapper.js.map +1 -1
- package/utils/decorators/CmsEntriesCrudDecorators.js +9 -5
- package/utils/decorators/CmsEntriesCrudDecorators.js.map +1 -1
- package/utils/resolve.d.ts +2 -2
- package/utils/resolve.js +1 -1
- package/utils/resolve.js.map +1 -1
- package/createAcoContext.d.ts +0 -9
- package/createAcoContext.js +0 -109
- package/createAcoContext.js.map +0 -1
- package/createAcoStorageOperations.d.ts +0 -12
- package/createAcoStorageOperations.js +0 -9
- package/createAcoStorageOperations.js.map +0 -1
- package/createAcoTasks.d.ts +0 -1
- package/createAcoTasks.js +0 -14
- package/createAcoTasks.js.map +0 -1
- package/flp/flp.so.d.ts +0 -20
- package/flp/flp.so.js +0 -183
- package/flp/flp.so.js.map +0 -1
- package/index.js.map +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createImplementation } from "@webiny/di";
|
|
2
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
3
|
+
import { WebsocketsSendToIdentityUseCase } from "@webiny/api-websockets/exports/api.js";
|
|
4
|
+
import { FOLDER_CREATED_WEBSOCKET_ACTION, FOLDER_DELETED_WEBSOCKET_ACTION, FOLDER_UPDATED_WEBSOCKET_ACTION, NotifyFolderChangeUseCase } from "./abstractions.js";
|
|
5
|
+
const ACTIONS = {
|
|
6
|
+
created: FOLDER_CREATED_WEBSOCKET_ACTION,
|
|
7
|
+
updated: FOLDER_UPDATED_WEBSOCKET_ACTION,
|
|
8
|
+
deleted: FOLDER_DELETED_WEBSOCKET_ACTION
|
|
9
|
+
};
|
|
10
|
+
class NotifyFolderChangeUseCaseImpl {
|
|
11
|
+
constructor(identityContext, sendToIdentity){
|
|
12
|
+
this.identityContext = identityContext;
|
|
13
|
+
this.sendToIdentity = sendToIdentity;
|
|
14
|
+
}
|
|
15
|
+
async execute({ id, change, identityId }) {
|
|
16
|
+
const recipient = identityId ?? this.identityContext.getIdentity()?.id;
|
|
17
|
+
if (!recipient) return;
|
|
18
|
+
await this.sendToIdentity.execute({
|
|
19
|
+
id: recipient
|
|
20
|
+
}, {
|
|
21
|
+
action: ACTIONS[change],
|
|
22
|
+
data: {
|
|
23
|
+
id
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const NotifyFolderChangeUseCase_NotifyFolderChangeUseCase = createImplementation({
|
|
29
|
+
abstraction: NotifyFolderChangeUseCase,
|
|
30
|
+
implementation: NotifyFolderChangeUseCaseImpl,
|
|
31
|
+
dependencies: [
|
|
32
|
+
IdentityContext,
|
|
33
|
+
WebsocketsSendToIdentityUseCase
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
export { NotifyFolderChangeUseCase_NotifyFolderChangeUseCase as NotifyFolderChangeUseCase };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=NotifyFolderChangeUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.js","sources":["../../../../src/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.ts"],"sourcesContent":["import { createImplementation } from \"@webiny/di\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport { WebsocketsSendToIdentityUseCase } from \"@webiny/api-websockets/exports/api.js\";\nimport {\n FOLDER_CREATED_WEBSOCKET_ACTION,\n FOLDER_DELETED_WEBSOCKET_ACTION,\n FOLDER_UPDATED_WEBSOCKET_ACTION,\n NotifyFolderChangeUseCase as UseCaseAbstraction\n} from \"./abstractions.js\";\n\nconst ACTIONS: Record<UseCaseAbstraction.Params[\"change\"], string> = {\n created: FOLDER_CREATED_WEBSOCKET_ACTION,\n updated: FOLDER_UPDATED_WEBSOCKET_ACTION,\n deleted: FOLDER_DELETED_WEBSOCKET_ACTION\n};\n\n/*\n * The change is already saved whether or not the message goes out, so the send's result is not the\n * caller's result. When it fails, the admin shows the change after its next reload, as it did before.\n */\nclass NotifyFolderChangeUseCaseImpl implements UseCaseAbstraction.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private sendToIdentity: WebsocketsSendToIdentityUseCase.Interface\n ) {}\n\n async execute({ id, change, identityId }: UseCaseAbstraction.Params): Promise<void> {\n const recipient = identityId ?? this.identityContext.getIdentity()?.id;\n if (!recipient) {\n return;\n }\n\n await this.sendToIdentity.execute(\n { id: recipient },\n { action: ACTIONS[change], data: { id } }\n );\n }\n}\n\nexport const NotifyFolderChangeUseCase = createImplementation({\n abstraction: UseCaseAbstraction,\n implementation: NotifyFolderChangeUseCaseImpl,\n dependencies: [IdentityContext, WebsocketsSendToIdentityUseCase]\n});\n"],"names":["ACTIONS","FOLDER_CREATED_WEBSOCKET_ACTION","FOLDER_UPDATED_WEBSOCKET_ACTION","FOLDER_DELETED_WEBSOCKET_ACTION","NotifyFolderChangeUseCaseImpl","identityContext","sendToIdentity","id","change","identityId","recipient","NotifyFolderChangeUseCase","createImplementation","UseCaseAbstraction","IdentityContext","WebsocketsSendToIdentityUseCase"],"mappings":";;;;AAUA,MAAMA,UAA+D;IACjE,SAASC;IACT,SAASC;IACT,SAASC;AACb;AAMA,MAAMC;IACF,YACYC,eAA0C,EAC1CC,cAAyD,CACnE;aAFUD,eAAe,GAAfA;aACAC,cAAc,GAAdA;IACT;IAEH,MAAM,QAAQ,EAAEC,EAAE,EAAEC,MAAM,EAAEC,UAAU,EAA6B,EAAiB;QAChF,MAAMC,YAAYD,cAAc,IAAI,CAAC,eAAe,CAAC,WAAW,IAAI;QACpE,IAAI,CAACC,WACD;QAGJ,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAC7B;YAAE,IAAIA;QAAU,GAChB;YAAE,QAAQV,OAAO,CAACQ,OAAO;YAAE,MAAM;gBAAED;YAAG;QAAE;IAEhD;AACJ;AAEO,MAAMI,sDAA4BC,qBAAqB;IAC1D,aAAaC;IACb,gBAAgBT;IAChB,cAAc;QAACU;QAAiBC;KAAgC;AACpE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FolderAfterDeleteEventHandler } from "../../../features/folder/DeleteFolder/abstractions.js";
|
|
2
|
+
import type { FolderAfterDeleteEvent } from "../../../features/folder/DeleteFolder/events.js";
|
|
3
|
+
import { NotifyFolderChangeUseCase } from "./abstractions.js";
|
|
4
|
+
declare class NotifyOnFolderDeletedHandlerImpl implements FolderAfterDeleteEventHandler.Interface {
|
|
5
|
+
private notifyFolderChange;
|
|
6
|
+
constructor(notifyFolderChange: NotifyFolderChangeUseCase.Interface);
|
|
7
|
+
handle(event: FolderAfterDeleteEvent): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare const NotifyOnFolderDeletedHandler: typeof NotifyOnFolderDeletedHandlerImpl & {
|
|
10
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher/abstractions.js").IEventHandler<import("@webiny/api-core/features/eventPublisher/abstractions.js").DomainEvent<import("~/features/folder/DeleteFolder/abstractions.js").FolderAfterDeletePayload>>>;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FolderAfterDeleteEventHandler } from "../DeleteFolder/abstractions.js";
|
|
2
|
+
import { NotifyFolderChangeUseCase } from "./abstractions.js";
|
|
3
|
+
class NotifyOnFolderDeletedHandlerImpl {
|
|
4
|
+
constructor(notifyFolderChange){
|
|
5
|
+
this.notifyFolderChange = notifyFolderChange;
|
|
6
|
+
}
|
|
7
|
+
async handle(event) {
|
|
8
|
+
try {
|
|
9
|
+
await this.notifyFolderChange.execute({
|
|
10
|
+
id: event.payload.folder.id,
|
|
11
|
+
change: "deleted"
|
|
12
|
+
});
|
|
13
|
+
} catch {}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const NotifyOnFolderDeletedHandler = FolderAfterDeleteEventHandler.createImplementation({
|
|
17
|
+
implementation: NotifyOnFolderDeletedHandlerImpl,
|
|
18
|
+
dependencies: [
|
|
19
|
+
NotifyFolderChangeUseCase
|
|
20
|
+
]
|
|
21
|
+
});
|
|
22
|
+
export { NotifyOnFolderDeletedHandler };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=NotifyOnFolderDeletedHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.js","sources":["../../../../src/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.ts"],"sourcesContent":["import { FolderAfterDeleteEventHandler } from \"~/features/folder/DeleteFolder/abstractions.js\";\nimport type { FolderAfterDeleteEvent } from \"~/features/folder/DeleteFolder/events.js\";\nimport { NotifyFolderChangeUseCase } from \"./abstractions.js\";\n\n/*\n * Created and updated folders are announced by the FLP tasks, once the admin can read them back. A\n * deleted folder is only dropped from the admin's cache, so there is nothing to wait for.\n */\nclass NotifyOnFolderDeletedHandlerImpl implements FolderAfterDeleteEventHandler.Interface {\n constructor(private notifyFolderChange: NotifyFolderChangeUseCase.Interface) {}\n\n async handle(event: FolderAfterDeleteEvent): Promise<void> {\n try {\n await this.notifyFolderChange.execute({\n id: event.payload.folder.id,\n change: \"deleted\"\n });\n } catch {\n // The folder is gone either way; the admin drops it on its next reload.\n }\n }\n}\n\nexport const NotifyOnFolderDeletedHandler = FolderAfterDeleteEventHandler.createImplementation({\n implementation: NotifyOnFolderDeletedHandlerImpl,\n dependencies: [NotifyFolderChangeUseCase]\n});\n"],"names":["NotifyOnFolderDeletedHandlerImpl","notifyFolderChange","event","NotifyOnFolderDeletedHandler","FolderAfterDeleteEventHandler","NotifyFolderChangeUseCase"],"mappings":";;AAQA,MAAMA;IACF,YAAoBC,kBAAuD,CAAE;aAAzDA,kBAAkB,GAAlBA;IAA0D;IAE9E,MAAM,OAAOC,KAA6B,EAAiB;QACvD,IAAI;YACA,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;gBAClC,IAAIA,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE;gBAC3B,QAAQ;YACZ;QACJ,EAAE,OAAM,CAER;IACJ;AACJ;AAEO,MAAMC,+BAA+BC,8BAA8B,oBAAoB,CAAC;IAC3F,gBAAgBJ;IAChB,cAAc;QAACK;KAA0B;AAC7C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sent to the user's open admin tabs when a folder changes. The admin keeps its own folder cache,
|
|
3
|
+
* and a change made on the server never passes through it, so without these the admin shows the old
|
|
4
|
+
* state until a reload. Each carries the folder id only; the admin reads the folder back.
|
|
5
|
+
*
|
|
6
|
+
* `created` and `updated` go out when the FLP tasks finish, since folder reads report permissions
|
|
7
|
+
* from the FLP records. `deleted` goes out right after the delete: nothing is read back.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FOLDER_CREATED_WEBSOCKET_ACTION = "aco.folder.created";
|
|
10
|
+
export declare const FOLDER_UPDATED_WEBSOCKET_ACTION = "aco.folder.updated";
|
|
11
|
+
export declare const FOLDER_DELETED_WEBSOCKET_ACTION = "aco.folder.deleted";
|
|
12
|
+
export interface NotifyFolderChangeParams {
|
|
13
|
+
id: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whose open tabs to tell. Defaults to the current identity. The FLP tasks pass the identity
|
|
16
|
+
* that made the change, because they run later, outside that request.
|
|
17
|
+
*/
|
|
18
|
+
identityId?: string;
|
|
19
|
+
change: "created" | "updated" | "deleted";
|
|
20
|
+
}
|
|
21
|
+
export interface INotifyFolderChangeUseCase {
|
|
22
|
+
execute(params: NotifyFolderChangeParams): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare const NotifyFolderChangeUseCase: import("@webiny/di").Abstraction<INotifyFolderChangeUseCase>;
|
|
25
|
+
export declare namespace NotifyFolderChangeUseCase {
|
|
26
|
+
type Interface = INotifyFolderChangeUseCase;
|
|
27
|
+
type Params = NotifyFolderChangeParams;
|
|
28
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createAbstraction } from "@webiny/feature/api";
|
|
2
|
+
const FOLDER_CREATED_WEBSOCKET_ACTION = "aco.folder.created";
|
|
3
|
+
const FOLDER_UPDATED_WEBSOCKET_ACTION = "aco.folder.updated";
|
|
4
|
+
const FOLDER_DELETED_WEBSOCKET_ACTION = "aco.folder.deleted";
|
|
5
|
+
const NotifyFolderChangeUseCase = createAbstraction("Aco/NotifyFolderChangeUseCase");
|
|
6
|
+
export { FOLDER_CREATED_WEBSOCKET_ACTION, FOLDER_DELETED_WEBSOCKET_ACTION, FOLDER_UPDATED_WEBSOCKET_ACTION, NotifyFolderChangeUseCase };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=abstractions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/folder/NotifyFolderChange/abstractions.js","sources":["../../../../src/features/folder/NotifyFolderChange/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\n\n/**\n * Sent to the user's open admin tabs when a folder changes. The admin keeps its own folder cache,\n * and a change made on the server never passes through it, so without these the admin shows the old\n * state until a reload. Each carries the folder id only; the admin reads the folder back.\n *\n * `created` and `updated` go out when the FLP tasks finish, since folder reads report permissions\n * from the FLP records. `deleted` goes out right after the delete: nothing is read back.\n */\nexport const FOLDER_CREATED_WEBSOCKET_ACTION = \"aco.folder.created\";\nexport const FOLDER_UPDATED_WEBSOCKET_ACTION = \"aco.folder.updated\";\nexport const FOLDER_DELETED_WEBSOCKET_ACTION = \"aco.folder.deleted\";\n\nexport interface NotifyFolderChangeParams {\n id: string;\n /**\n * Whose open tabs to tell. Defaults to the current identity. The FLP tasks pass the identity\n * that made the change, because they run later, outside that request.\n */\n identityId?: string;\n change: \"created\" | \"updated\" | \"deleted\";\n}\n\nexport interface INotifyFolderChangeUseCase {\n execute(params: NotifyFolderChangeParams): Promise<void>;\n}\n\nexport const NotifyFolderChangeUseCase = createAbstraction<INotifyFolderChangeUseCase>(\n \"Aco/NotifyFolderChangeUseCase\"\n);\n\nexport namespace NotifyFolderChangeUseCase {\n export type Interface = INotifyFolderChangeUseCase;\n export type Params = NotifyFolderChangeParams;\n}\n"],"names":["FOLDER_CREATED_WEBSOCKET_ACTION","FOLDER_UPDATED_WEBSOCKET_ACTION","FOLDER_DELETED_WEBSOCKET_ACTION","NotifyFolderChangeUseCase","createAbstraction"],"mappings":";AAUO,MAAMA,kCAAkC;AACxC,MAAMC,kCAAkC;AACxC,MAAMC,kCAAkC;AAgBxC,MAAMC,4BAA4BC,kBACrC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tells the user's open admin tabs when a folder is created, updated or deleted. The FLP tasks send
|
|
3
|
+
* created and updated (see `CreateFlpOnFolderCreated` and `UpdateFlpOnFolderUpdated`); deleted goes
|
|
4
|
+
* out from here.
|
|
5
|
+
*/
|
|
6
|
+
export declare const NotifyFolderChangeFeature: {
|
|
7
|
+
name: string;
|
|
8
|
+
register(container: import("@webiny/di").Container): void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { NotifyFolderChangeUseCase } from "./NotifyFolderChangeUseCase.js";
|
|
3
|
+
import { NotifyOnFolderDeletedHandler } from "./NotifyOnFolderDeletedHandler.js";
|
|
4
|
+
const NotifyFolderChangeFeature = createFeature({
|
|
5
|
+
name: "NotifyFolderChange",
|
|
6
|
+
register (container) {
|
|
7
|
+
container.register(NotifyFolderChangeUseCase);
|
|
8
|
+
container.register(NotifyOnFolderDeletedHandler);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
export { NotifyFolderChangeFeature };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/folder/NotifyFolderChange/feature.js","sources":["../../../../src/features/folder/NotifyFolderChange/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { NotifyFolderChangeUseCase } from \"./NotifyFolderChangeUseCase.js\";\nimport { NotifyOnFolderDeletedHandler } from \"./NotifyOnFolderDeletedHandler.js\";\n\n/**\n * Tells the user's open admin tabs when a folder is created, updated or deleted. The FLP tasks send\n * created and updated (see `CreateFlpOnFolderCreated` and `UpdateFlpOnFolderUpdated`); deleted goes\n * out from here.\n */\nexport const NotifyFolderChangeFeature = createFeature({\n name: \"NotifyFolderChange\",\n register(container) {\n container.register(NotifyFolderChangeUseCase);\n container.register(NotifyOnFolderDeletedHandler);\n }\n});\n"],"names":["NotifyFolderChangeFeature","createFeature","container","NotifyFolderChangeUseCase","NotifyOnFolderDeletedHandler"],"mappings":";;;AASO,MAAMA,4BAA4BC,cAAc;IACnD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;IACvB;AACJ"}
|
|
@@ -3,14 +3,14 @@ import { type IUpdateFolderRepository, UpdateFolderRepository as RepositoryAbstr
|
|
|
3
3
|
import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry";
|
|
4
4
|
import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEntry/GetEntryById";
|
|
5
5
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
6
|
-
import {
|
|
6
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
7
7
|
import type { Folder, UpdateFolderParams } from "../../../folder/folder.types.js";
|
|
8
8
|
declare class UpdateFolderRepositoryImpl implements IUpdateFolderRepository {
|
|
9
9
|
private updateEntry;
|
|
10
10
|
private getEntryById;
|
|
11
11
|
private listLatestEntries;
|
|
12
|
-
private
|
|
13
|
-
constructor(updateEntry: UpdateEntryUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface, listLatestEntries: ListLatestEntriesUseCase.Interface,
|
|
12
|
+
private folderModelProvider;
|
|
13
|
+
constructor(updateEntry: UpdateEntryUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface, listLatestEntries: ListLatestEntriesUseCase.Interface, folderModelProvider: FolderModelProvider.Interface);
|
|
14
14
|
execute(id: string, data: UpdateFolderParams): Promise<Result<Folder, RepositoryAbstraction.Error>>;
|
|
15
15
|
private checkExistingFolder;
|
|
16
16
|
private createFolderPath;
|
|
@@ -3,21 +3,22 @@ import { UpdateFolderRepository } from "./abstractions.js";
|
|
|
3
3
|
import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry";
|
|
4
4
|
import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEntry/GetEntryById";
|
|
5
5
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
6
|
-
import {
|
|
6
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
7
7
|
import { EntryToFolderMapper } from "../shared/EntryToFolderMapper.js";
|
|
8
8
|
import { FolderPersistenceError, FolderValidationError } from "../../../domain/folder/errors.js";
|
|
9
9
|
import { Path } from "../../../utils/Path.js";
|
|
10
10
|
import { EntryId } from "@webiny/api-headless-cms/exports/api/cms/entry.js";
|
|
11
11
|
class UpdateFolderRepositoryImpl {
|
|
12
|
-
constructor(updateEntry, getEntryById, listLatestEntries,
|
|
12
|
+
constructor(updateEntry, getEntryById, listLatestEntries, folderModelProvider){
|
|
13
13
|
this.updateEntry = updateEntry;
|
|
14
14
|
this.getEntryById = getEntryById;
|
|
15
15
|
this.listLatestEntries = listLatestEntries;
|
|
16
|
-
this.
|
|
16
|
+
this.folderModelProvider = folderModelProvider;
|
|
17
17
|
}
|
|
18
18
|
async execute(id, data) {
|
|
19
|
+
const folderModel = await this.folderModelProvider.get();
|
|
19
20
|
const entryId = EntryId.from(id);
|
|
20
|
-
const originalResult = await this.getEntryById.execute(
|
|
21
|
+
const originalResult = await this.getEntryById.execute(folderModel, entryId.toString());
|
|
21
22
|
if (originalResult.isFail()) return Result.fail(new FolderPersistenceError(originalResult.error));
|
|
22
23
|
const original = EntryToFolderMapper.toFolder(originalResult.value);
|
|
23
24
|
const checkResult = await this.checkExistingFolder({
|
|
@@ -32,7 +33,7 @@ class UpdateFolderRepositoryImpl {
|
|
|
32
33
|
parentId: void 0 !== data.parentId ? data.parentId : original.parentId
|
|
33
34
|
});
|
|
34
35
|
if (pathResult.isFail()) return Result.fail(pathResult.error);
|
|
35
|
-
const result = await this.updateEntry.execute(
|
|
36
|
+
const result = await this.updateEntry.execute(folderModel, entryId.toString(), {
|
|
36
37
|
values: {
|
|
37
38
|
...data,
|
|
38
39
|
path: pathResult.value
|
|
@@ -43,8 +44,9 @@ class UpdateFolderRepositoryImpl {
|
|
|
43
44
|
return Result.ok(updatedFolder);
|
|
44
45
|
}
|
|
45
46
|
async checkExistingFolder(params) {
|
|
47
|
+
const folderModel = await this.folderModelProvider.get();
|
|
46
48
|
const { id, type, slug, parentId } = params;
|
|
47
|
-
const result = await this.listLatestEntries.execute(
|
|
49
|
+
const result = await this.listLatestEntries.execute(folderModel, {
|
|
48
50
|
where: {
|
|
49
51
|
latest: true,
|
|
50
52
|
entryId_not: id,
|
|
@@ -62,9 +64,10 @@ class UpdateFolderRepositoryImpl {
|
|
|
62
64
|
return Result.ok();
|
|
63
65
|
}
|
|
64
66
|
async createFolderPath(params) {
|
|
67
|
+
const folderModel = await this.folderModelProvider.get();
|
|
65
68
|
const { slug, parentId } = params;
|
|
66
69
|
if (!parentId) return Result.ok(Path.create(slug));
|
|
67
|
-
const parentResult = await this.getEntryById.execute(
|
|
70
|
+
const parentResult = await this.getEntryById.execute(folderModel, EntryId.from(parentId).toString());
|
|
68
71
|
if (parentResult.isFail()) return Result.fail(new FolderPersistenceError(new Error("Parent folder not found. Unable to create the folder path")));
|
|
69
72
|
const parentFolder = EntryToFolderMapper.toFolder(parentResult.value);
|
|
70
73
|
return Result.ok(Path.create(slug, parentFolder.path));
|
|
@@ -76,7 +79,7 @@ const UpdateFolderRepository_UpdateFolderRepository = UpdateFolderRepository.cre
|
|
|
76
79
|
UpdateEntryUseCase,
|
|
77
80
|
GetEntryByIdUseCase,
|
|
78
81
|
ListLatestEntriesUseCase,
|
|
79
|
-
|
|
82
|
+
FolderModelProvider
|
|
80
83
|
]
|
|
81
84
|
});
|
|
82
85
|
export { UpdateFolderRepository_UpdateFolderRepository as UpdateFolderRepository };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/folder/UpdateFolder/UpdateFolderRepository.js","sources":["../../../../src/features/folder/UpdateFolder/UpdateFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n type IUpdateFolderRepository,\n UpdateFolderRepository as RepositoryAbstraction\n} from \"./abstractions.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport { ListLatestEntriesUseCase } from \"@webiny/api-headless-cms/features/contentEntry/ListEntries\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/folder/UpdateFolder/UpdateFolderRepository.js","sources":["../../../../src/features/folder/UpdateFolder/UpdateFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n type IUpdateFolderRepository,\n UpdateFolderRepository as RepositoryAbstraction\n} from \"./abstractions.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport { ListLatestEntriesUseCase } from \"@webiny/api-headless-cms/features/contentEntry/ListEntries\";\nimport { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport type { CmsEntryFolder, Folder, UpdateFolderParams } from \"~/folder/folder.types.js\";\nimport { EntryToFolderMapper } from \"../shared/EntryToFolderMapper.js\";\nimport { FolderPersistenceError, FolderValidationError } from \"~/domain/folder/errors.js\";\nimport { Path } from \"~/utils/Path.js\";\nimport { EntryId } from \"@webiny/api-headless-cms/exports/api/cms/entry.js\";\n\nclass UpdateFolderRepositoryImpl implements IUpdateFolderRepository {\n constructor(\n private updateEntry: UpdateEntryUseCase.Interface,\n private getEntryById: GetEntryByIdUseCase.Interface,\n private listLatestEntries: ListLatestEntriesUseCase.Interface,\n private folderModelProvider: FolderModelProvider.Interface\n ) {}\n\n async execute(\n id: string,\n data: UpdateFolderParams\n ): Promise<Result<Folder, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n const entryId = EntryId.from(id);\n\n // Get the original folder\n const originalResult = await this.getEntryById.execute<CmsEntryFolder>(\n folderModel,\n entryId.toString()\n );\n\n if (originalResult.isFail()) {\n return Result.fail(new FolderPersistenceError(originalResult.error));\n }\n\n const original = EntryToFolderMapper.toFolder(originalResult.value);\n\n // Check if folder with new slug already exists\n const checkResult = await this.checkExistingFolder({\n id,\n type: original.type,\n slug: data.slug || original.slug,\n parentId: data.parentId !== undefined ? data.parentId : original.parentId\n });\n\n if (checkResult.isFail()) {\n return Result.fail(checkResult.error);\n }\n\n // Create new path if slug or parentId changed\n const pathResult = await this.createFolderPath({\n slug: data.slug || original.slug,\n parentId: data.parentId !== undefined ? data.parentId : original.parentId\n });\n\n if (pathResult.isFail()) {\n return Result.fail(pathResult.error);\n }\n\n const result = await this.updateEntry.execute<CmsEntryFolder>(\n folderModel,\n entryId.toString(),\n {\n values: {\n ...data,\n path: pathResult.value\n }\n }\n );\n\n if (result.isFail()) {\n return Result.fail(new FolderPersistenceError(result.error));\n }\n\n const updatedFolder = EntryToFolderMapper.toFolder(result.value);\n return Result.ok(updatedFolder);\n }\n\n private async checkExistingFolder(params: {\n id: string;\n type: string;\n slug: string;\n parentId?: string | null;\n }): Promise<Result<void, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n const { id, type, slug, parentId } = params;\n\n const result = await this.listLatestEntries.execute<CmsEntryFolder>(folderModel, {\n where: {\n latest: true,\n entryId_not: id,\n values: {\n type,\n slug,\n parentId\n }\n },\n limit: 1\n });\n\n if (result.isFail()) {\n return Result.fail(new FolderPersistenceError(result.error));\n }\n\n const { entries } = result.value;\n\n if (entries.length > 0) {\n return Result.fail(\n new FolderValidationError(\n `Folder with slug \"${slug}\" already exists at this level.`\n )\n );\n }\n\n return Result.ok();\n }\n\n private async createFolderPath(params: {\n slug: string;\n parentId?: string | null;\n }): Promise<Result<string, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n const { slug, parentId } = params;\n\n if (!parentId) {\n return Result.ok(Path.create(slug));\n }\n\n const parentResult = await this.getEntryById.execute<CmsEntryFolder>(\n folderModel,\n EntryId.from(parentId).toString()\n );\n\n if (parentResult.isFail()) {\n return Result.fail(\n new FolderPersistenceError(\n new Error(\"Parent folder not found. Unable to create the folder path\")\n )\n );\n }\n\n const parentFolder = EntryToFolderMapper.toFolder(parentResult.value);\n return Result.ok(Path.create(slug, parentFolder.path));\n }\n}\n\nexport const UpdateFolderRepository = RepositoryAbstraction.createImplementation({\n implementation: UpdateFolderRepositoryImpl,\n dependencies: [\n UpdateEntryUseCase,\n GetEntryByIdUseCase,\n ListLatestEntriesUseCase,\n FolderModelProvider\n ]\n});\n"],"names":["UpdateFolderRepositoryImpl","updateEntry","getEntryById","listLatestEntries","folderModelProvider","id","data","folderModel","entryId","EntryId","originalResult","Result","FolderPersistenceError","original","EntryToFolderMapper","checkResult","undefined","pathResult","result","updatedFolder","params","type","slug","parentId","entries","FolderValidationError","Path","parentResult","Error","parentFolder","UpdateFolderRepository","RepositoryAbstraction","UpdateEntryUseCase","GetEntryByIdUseCase","ListLatestEntriesUseCase","FolderModelProvider"],"mappings":"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"}
|
|
@@ -2,12 +2,25 @@ import type { UpdateFolderParams } from "../../../../folder/folder.types.js";
|
|
|
2
2
|
import { FolderLevelPermissions } from "../../../../features/flp/FolderLevelPermissions/index.js";
|
|
3
3
|
import { UpdateFolderUseCase } from "../abstractions.js";
|
|
4
4
|
import { GetFolderUseCase } from "../../../../features/folder/GetFolder/index.js";
|
|
5
|
+
import { CodeFlpsProvider } from "../../../../features/flp/shared/index.js";
|
|
5
6
|
declare class UpdateFolderWithFolderLevelPermissionsImpl implements UpdateFolderUseCase.Interface {
|
|
6
7
|
private getFolder;
|
|
7
8
|
private folderLevelPermissions;
|
|
8
9
|
private readonly decoretee;
|
|
9
|
-
|
|
10
|
+
private readonly codeFlpsProvider?;
|
|
11
|
+
constructor(getFolder: GetFolderUseCase.Interface, folderLevelPermissions: FolderLevelPermissions.Interface, codeFlpsProvider: CodeFlpsProvider.Interface | undefined, decoretee: UpdateFolderUseCase.Interface);
|
|
10
12
|
execute(id: string, params: UpdateFolderParams): UpdateFolderUseCase.Return;
|
|
13
|
+
/**
|
|
14
|
+
* The type and path the folder will have after this update, computed the same way
|
|
15
|
+
* `UpdateFolderRepository` computes them: the submitted slug and parent, falling back to the
|
|
16
|
+
* current ones.
|
|
17
|
+
*/
|
|
18
|
+
private getTargetFolder;
|
|
19
|
+
/**
|
|
20
|
+
* Code-defined permissions are resolved from the folder's own type and path rather than the FLP
|
|
21
|
+
* catalog, so they apply even when the stored record is missing or not yet written.
|
|
22
|
+
*/
|
|
23
|
+
private withCodePermissions;
|
|
11
24
|
}
|
|
12
25
|
export declare const UpdateFolderWithFolderLevelPermissions: typeof UpdateFolderWithFolderLevelPermissionsImpl;
|
|
13
26
|
export {};
|
|
@@ -3,10 +3,13 @@ import { FolderLevelPermissions } from "../../../flp/FolderLevelPermissions/inde
|
|
|
3
3
|
import { UpdateFolderUseCase } from "../abstractions.js";
|
|
4
4
|
import { GetFolderUseCase } from "../../GetFolder/index.js";
|
|
5
5
|
import { FolderCannotMoveToNewParent, FolderValidationError } from "../../../../domain/folder/errors.js";
|
|
6
|
+
import { CodeFlpMerger, CodeFlpsProvider } from "../../../flp/shared/index.js";
|
|
7
|
+
import { Path } from "../../../../utils/Path.js";
|
|
6
8
|
class UpdateFolderWithFolderLevelPermissionsImpl {
|
|
7
|
-
constructor(getFolder, folderLevelPermissions, decoretee){
|
|
9
|
+
constructor(getFolder, folderLevelPermissions, codeFlpsProvider, decoretee){
|
|
8
10
|
this.getFolder = getFolder;
|
|
9
11
|
this.folderLevelPermissions = folderLevelPermissions;
|
|
12
|
+
this.codeFlpsProvider = codeFlpsProvider;
|
|
10
13
|
this.decoretee = decoretee;
|
|
11
14
|
}
|
|
12
15
|
async execute(id, params) {
|
|
@@ -18,7 +21,9 @@ class UpdateFolderWithFolderLevelPermissionsImpl {
|
|
|
18
21
|
permissions: originalPermissions,
|
|
19
22
|
rwd: "w"
|
|
20
23
|
});
|
|
21
|
-
const
|
|
24
|
+
const targetFolder = await this.getTargetFolder(original, params);
|
|
25
|
+
const submittedPermissions = await this.withCodePermissions(targetFolder, params.permissions ?? []);
|
|
26
|
+
const permissions = await this.folderLevelPermissions.getDefaultPermissions(submittedPermissions);
|
|
22
27
|
const stillHasAccess = await this.folderLevelPermissions.canAccessFolder({
|
|
23
28
|
permissions,
|
|
24
29
|
rwd: "w"
|
|
@@ -28,6 +33,7 @@ class UpdateFolderWithFolderLevelPermissionsImpl {
|
|
|
28
33
|
const targetIsValid = permission.target.startsWith("admin:") || permission.target.startsWith("team:");
|
|
29
34
|
if (!targetIsValid) return Result.fail(new FolderValidationError(`Permission target "${permission.target}" is not valid.`));
|
|
30
35
|
if (permission.inheritedFrom) return Result.fail(new FolderValidationError('Permission "inheritedFrom" cannot be set manually.'));
|
|
36
|
+
if (permission.plugin) return Result.fail(new FolderValidationError('Permission "plugin" cannot be set manually. Code-defined permissions are managed via an "FlpFactory".'));
|
|
31
37
|
}
|
|
32
38
|
if (params.parentId && params.parentId !== original.parentId) {
|
|
33
39
|
const parentPermissions = await this.folderLevelPermissions.getFolderLevelPermissions(params.parentId);
|
|
@@ -39,18 +45,60 @@ class UpdateFolderWithFolderLevelPermissionsImpl {
|
|
|
39
45
|
}
|
|
40
46
|
const result = await this.decoretee.execute(id, params);
|
|
41
47
|
if (result.isFail()) return Result.fail(result.error);
|
|
48
|
+
const updatedPermissions = await this.withCodePermissions(result.value, params.permissions ?? []);
|
|
49
|
+
const updatedPermissionsWithDefaults = await this.folderLevelPermissions.getDefaultPermissions(updatedPermissions);
|
|
42
50
|
return Result.ok({
|
|
43
51
|
...result.value,
|
|
44
|
-
permissions
|
|
52
|
+
permissions: updatedPermissionsWithDefaults
|
|
45
53
|
});
|
|
46
54
|
}
|
|
55
|
+
async getTargetFolder(original, params) {
|
|
56
|
+
const slug = params.slug || original.slug;
|
|
57
|
+
const parentId = void 0 !== params.parentId ? params.parentId : original.parentId;
|
|
58
|
+
if (parentId === original.parentId) {
|
|
59
|
+
const parentPath = original.path.slice(0, -(original.slug.length + 1));
|
|
60
|
+
const path = Path.create(slug, parentPath);
|
|
61
|
+
return {
|
|
62
|
+
type: original.type,
|
|
63
|
+
path
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (!parentId) {
|
|
67
|
+
const path = Path.create(slug);
|
|
68
|
+
return {
|
|
69
|
+
type: original.type,
|
|
70
|
+
path
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const parentResult = await this.getFolder.execute(parentId);
|
|
74
|
+
if (parentResult.isFail()) return original;
|
|
75
|
+
const path = Path.create(slug, parentResult.value.path);
|
|
76
|
+
return {
|
|
77
|
+
type: original.type,
|
|
78
|
+
path
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async withCodePermissions(folder, permissions) {
|
|
82
|
+
if (!this.codeFlpsProvider) return permissions;
|
|
83
|
+
const codePermissions = await this.codeFlpsProvider.getPermissions({
|
|
84
|
+
type: folder.type,
|
|
85
|
+
path: folder.path
|
|
86
|
+
});
|
|
87
|
+
return CodeFlpMerger.mergePermissions(permissions, codePermissions);
|
|
88
|
+
}
|
|
47
89
|
}
|
|
48
90
|
const UpdateFolderWithFolderLevelPermissions = createDecorator({
|
|
49
91
|
abstraction: UpdateFolderUseCase,
|
|
50
92
|
decorator: UpdateFolderWithFolderLevelPermissionsImpl,
|
|
51
93
|
dependencies: [
|
|
52
94
|
GetFolderUseCase,
|
|
53
|
-
FolderLevelPermissions
|
|
95
|
+
FolderLevelPermissions,
|
|
96
|
+
[
|
|
97
|
+
CodeFlpsProvider,
|
|
98
|
+
{
|
|
99
|
+
optional: true
|
|
100
|
+
}
|
|
101
|
+
]
|
|
54
102
|
]
|
|
55
103
|
});
|
|
56
104
|
export { UpdateFolderWithFolderLevelPermissions };
|
package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js","sources":["../../../../../src/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.ts"],"sourcesContent":["import { createDecorator, Result } from \"@webiny/feature/api\";\nimport type { UpdateFolderParams } from \"~/folder/folder.types.js\";\nimport { FolderLevelPermissions } from \"~/features/flp/FolderLevelPermissions/index.js\";\nimport { UpdateFolderUseCase } from \"../abstractions.js\";\nimport { GetFolderUseCase } from \"~/features/folder/GetFolder/index.js\";\nimport { FolderCannotMoveToNewParent, FolderValidationError } from \"~/domain/folder/errors.js\";\n\nclass UpdateFolderWithFolderLevelPermissionsImpl implements UpdateFolderUseCase.Interface {\n private folderLevelPermissions: FolderLevelPermissions.Interface;\n private readonly decoretee: UpdateFolderUseCase.Interface;\n\n constructor(\n private getFolder: GetFolderUseCase.Interface,\n folderLevelPermissions: FolderLevelPermissions.Interface,\n decoretee: UpdateFolderUseCase.Interface\n ) {\n this.folderLevelPermissions = folderLevelPermissions;\n this.decoretee = decoretee;\n }\n\n async execute(id: string, params: UpdateFolderParams): UpdateFolderUseCase.Return {\n const originalResult = await this.getFolder.execute(id);\n\n if (originalResult.isFail()) {\n return Result.fail(originalResult.error);\n }\n\n const original = originalResult.value;\n\n const originalPermissions = await this.folderLevelPermissions.getFolderLevelPermissions(id);\n\n // Let's ensure current identity's permission allows the update operation.\n await this.folderLevelPermissions.ensureCanAccessFolder({\n permissions: originalPermissions,\n rwd: \"w\"\n });\n\n const permissions = await this.folderLevelPermissions.getDefaultPermissions(\n params.permissions ?? []\n );\n\n // Check if the user still has access to the folder with the provided permissions.\n const stillHasAccess = await this.folderLevelPermissions.canAccessFolder({\n permissions,\n rwd: \"w\"\n });\n\n if (!stillHasAccess) {\n return Result.fail(\n new FolderValidationError(\n `Cannot continue because you would loose access to this folder.`\n )\n );\n }\n\n // Validate data.\n if (Array.isArray(params.permissions)) {\n for (const permission of params.permissions) {\n const targetIsValid =\n permission.target.startsWith(\"admin:\") || permission.target.startsWith(\"team:\");\n if (!targetIsValid) {\n return Result.fail(\n new FolderValidationError(\n `Permission target \"${permission.target}\" is not valid.`\n )\n );\n }\n\n if (permission.inheritedFrom) {\n return Result.fail(\n new FolderValidationError(\n `Permission \"inheritedFrom\" cannot be set manually.`\n )\n );\n }\n }\n }\n\n // Parent change is not allowed if the user doesn't have access to the new parent.\n if (params.parentId && params.parentId !== original.parentId) {\n // Getting the parent folder permissions will throw an error if the user doesn't have access.\n const parentPermissions = await this.folderLevelPermissions.getFolderLevelPermissions(\n params.parentId\n );\n\n const canAccessFolder = await this.folderLevelPermissions.canAccessFolder({\n permissions: parentPermissions,\n rwd: \"w\"\n });\n\n if (!canAccessFolder) {\n return Result.fail(new FolderCannotMoveToNewParent());\n }\n }\n\n const result = await this.decoretee.execute(id, params);\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n return Result.ok({\n ...result.value,\n permissions\n });\n }\n}\n\nexport const UpdateFolderWithFolderLevelPermissions = createDecorator({\n abstraction: UpdateFolderUseCase,\n decorator: UpdateFolderWithFolderLevelPermissionsImpl,\n dependencies: [GetFolderUseCase, FolderLevelPermissions]\n});\n"],"names":["UpdateFolderWithFolderLevelPermissionsImpl","getFolder","folderLevelPermissions","decoretee","id","params","originalResult","Result","original","originalPermissions","permissions","stillHasAccess","FolderValidationError","Array","permission","targetIsValid","parentPermissions","canAccessFolder","FolderCannotMoveToNewParent","result","UpdateFolderWithFolderLevelPermissions","createDecorator","UpdateFolderUseCase","GetFolderUseCase","FolderLevelPermissions"],"mappings":";;;;;AAOA,MAAMA;IAIF,YACYC,SAAqC,EAC7CC,sBAAwD,EACxDC,SAAwC,CAC1C;aAHUF,SAAS,GAATA;QAIR,IAAI,CAAC,sBAAsB,GAAGC;QAC9B,IAAI,CAAC,SAAS,GAAGC;IACrB;IAEA,MAAM,QAAQC,EAAU,EAAEC,MAA0B,EAA8B;QAC9E,MAAMC,iBAAiB,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAACF;QAEpD,IAAIE,eAAe,MAAM,IACrB,OAAOC,OAAO,IAAI,CAACD,eAAe,KAAK;QAG3C,MAAME,WAAWF,eAAe,KAAK;QAErC,MAAMG,sBAAsB,MAAM,IAAI,CAAC,sBAAsB,CAAC,yBAAyB,CAACL;QAGxF,MAAM,IAAI,CAAC,sBAAsB,CAAC,qBAAqB,CAAC;YACpD,aAAaK;YACb,KAAK;QACT;QAEA,MAAMC,cAAc,MAAM,IAAI,CAAC,sBAAsB,CAAC,qBAAqB,CACvEL,OAAO,WAAW,IAAI,EAAE;QAI5B,MAAMM,iBAAiB,MAAM,IAAI,CAAC,sBAAsB,CAAC,eAAe,CAAC;YACrED;YACA,KAAK;QACT;QAEA,IAAI,CAACC,gBACD,OAAOJ,OAAO,IAAI,CACd,IAAIK,sBACA;QAMZ,IAAIC,MAAM,OAAO,CAACR,OAAO,WAAW,GAChC,KAAK,MAAMS,cAAcT,OAAO,WAAW,CAAE;YACzC,MAAMU,gBACFD,WAAW,MAAM,CAAC,UAAU,CAAC,aAAaA,WAAW,MAAM,CAAC,UAAU,CAAC;YAC3E,IAAI,CAACC,eACD,OAAOR,OAAO,IAAI,CACd,IAAIK,sBACA,CAAC,mBAAmB,EAAEE,WAAW,MAAM,CAAC,eAAe,CAAC;YAKpE,IAAIA,WAAW,aAAa,EACxB,OAAOP,OAAO,IAAI,CACd,IAAIK,sBACA;QAIhB;QAIJ,IAAIP,OAAO,QAAQ,IAAIA,OAAO,QAAQ,KAAKG,SAAS,QAAQ,EAAE;YAE1D,MAAMQ,oBAAoB,MAAM,IAAI,CAAC,sBAAsB,CAAC,yBAAyB,CACjFX,OAAO,QAAQ;YAGnB,MAAMY,kBAAkB,MAAM,IAAI,CAAC,sBAAsB,CAAC,eAAe,CAAC;gBACtE,aAAaD;gBACb,KAAK;YACT;YAEA,IAAI,CAACC,iBACD,OAAOV,OAAO,IAAI,CAAC,IAAIW;QAE/B;QAEA,MAAMC,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAACf,IAAIC;QAEhD,IAAIc,OAAO,MAAM,IACb,OAAOZ,OAAO,IAAI,CAACY,OAAO,KAAK;QAGnC,OAAOZ,OAAO,EAAE,CAAC;YACb,GAAGY,OAAO,KAAK;YACfT;QACJ;IACJ;AACJ;AAEO,MAAMU,yCAAyCC,gBAAgB;IAClE,aAAaC;IACb,WAAWtB;IACX,cAAc;QAACuB;QAAkBC;KAAuB;AAC5D"}
|
|
1
|
+
{"version":3,"file":"features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js","sources":["../../../../../src/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.ts"],"sourcesContent":["import { createDecorator, Result } from \"@webiny/feature/api\";\nimport type { Folder } from \"~/folder/folder.types.js\";\nimport type { UpdateFolderParams } from \"~/folder/folder.types.js\";\nimport type { FolderPermission } from \"~/flp/flp.types.js\";\nimport { FolderLevelPermissions } from \"~/features/flp/FolderLevelPermissions/index.js\";\nimport { UpdateFolderUseCase } from \"../abstractions.js\";\nimport { GetFolderUseCase } from \"~/features/folder/GetFolder/index.js\";\nimport { FolderCannotMoveToNewParent, FolderValidationError } from \"~/domain/folder/errors.js\";\nimport { CodeFlpMerger } from \"~/features/flp/shared/index.js\";\nimport { CodeFlpsProvider } from \"~/features/flp/shared/index.js\";\nimport { Path } from \"~/utils/Path.js\";\n\nclass UpdateFolderWithFolderLevelPermissionsImpl implements UpdateFolderUseCase.Interface {\n private folderLevelPermissions: FolderLevelPermissions.Interface;\n private readonly decoretee: UpdateFolderUseCase.Interface;\n private readonly codeFlpsProvider?: CodeFlpsProvider.Interface;\n\n constructor(\n private getFolder: GetFolderUseCase.Interface,\n folderLevelPermissions: FolderLevelPermissions.Interface,\n codeFlpsProvider: CodeFlpsProvider.Interface | undefined,\n decoretee: UpdateFolderUseCase.Interface\n ) {\n this.folderLevelPermissions = folderLevelPermissions;\n this.codeFlpsProvider = codeFlpsProvider;\n this.decoretee = decoretee;\n }\n\n async execute(id: string, params: UpdateFolderParams): UpdateFolderUseCase.Return {\n const originalResult = await this.getFolder.execute(id);\n\n if (originalResult.isFail()) {\n return Result.fail(originalResult.error);\n }\n\n const original = originalResult.value;\n\n const originalPermissions = await this.folderLevelPermissions.getFolderLevelPermissions(id);\n\n // Let's ensure current identity's permission allows the update operation.\n await this.folderLevelPermissions.ensureCanAccessFolder({\n permissions: originalPermissions,\n rwd: \"w\"\n });\n\n // The guard below asks whether the user keeps access once the update is saved. A new slug or\n // a new parent changes the path, and code-defined rules match on the path, so resolve them\n // against where the folder is going rather than where it is now.\n const targetFolder = await this.getTargetFolder(original, params);\n\n const submittedPermissions = await this.withCodePermissions(\n targetFolder,\n params.permissions ?? []\n );\n\n const permissions =\n await this.folderLevelPermissions.getDefaultPermissions(submittedPermissions);\n\n // Check if the user still has access to the folder with the provided permissions.\n const stillHasAccess = await this.folderLevelPermissions.canAccessFolder({\n permissions,\n rwd: \"w\"\n });\n\n if (!stillHasAccess) {\n return Result.fail(\n new FolderValidationError(\n `Cannot continue because you would loose access to this folder.`\n )\n );\n }\n\n // Validate data.\n if (Array.isArray(params.permissions)) {\n for (const permission of params.permissions) {\n const targetIsValid =\n permission.target.startsWith(\"admin:\") || permission.target.startsWith(\"team:\");\n if (!targetIsValid) {\n return Result.fail(\n new FolderValidationError(\n `Permission target \"${permission.target}\" is not valid.`\n )\n );\n }\n\n if (permission.inheritedFrom) {\n return Result.fail(\n new FolderValidationError(\n `Permission \"inheritedFrom\" cannot be set manually.`\n )\n );\n }\n\n if (permission.plugin) {\n return Result.fail(\n new FolderValidationError(\n `Permission \"plugin\" cannot be set manually. Code-defined permissions are managed via an \"FlpFactory\".`\n )\n );\n }\n }\n }\n\n // Parent change is not allowed if the user doesn't have access to the new parent.\n if (params.parentId && params.parentId !== original.parentId) {\n // Getting the parent folder permissions will throw an error if the user doesn't have access.\n const parentPermissions = await this.folderLevelPermissions.getFolderLevelPermissions(\n params.parentId\n );\n\n const canAccessFolder = await this.folderLevelPermissions.canAccessFolder({\n permissions: parentPermissions,\n rwd: \"w\"\n });\n\n if (!canAccessFolder) {\n return Result.fail(new FolderCannotMoveToNewParent());\n }\n }\n\n const result = await this.decoretee.execute(id, params);\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n // Resolved again against the updated folder: a rename or a move changes the path, and with\n // it which code-defined rules apply.\n const updatedPermissions = await this.withCodePermissions(\n result.value,\n params.permissions ?? []\n );\n\n const updatedPermissionsWithDefaults =\n await this.folderLevelPermissions.getDefaultPermissions(updatedPermissions);\n\n return Result.ok({\n ...result.value,\n permissions: updatedPermissionsWithDefaults\n });\n }\n\n /**\n * The type and path the folder will have after this update, computed the same way\n * `UpdateFolderRepository` computes them: the submitted slug and parent, falling back to the\n * current ones.\n */\n private async getTargetFolder(\n original: Folder,\n params: UpdateFolderParams\n ): Promise<Pick<Folder, \"type\" | \"path\">> {\n const slug = params.slug || original.slug;\n const parentId = params.parentId !== undefined ? params.parentId : original.parentId;\n\n // Same parent: only the last segment of the path can change, so it is derived from the\n // current path. This avoids reading the parent, which the user may not have access to.\n if (parentId === original.parentId) {\n const parentPath = original.path.slice(0, -(original.slug.length + 1));\n const path = Path.create(slug, parentPath);\n\n return { type: original.type, path };\n }\n\n if (!parentId) {\n const path = Path.create(slug);\n\n return { type: original.type, path };\n }\n\n // A move. If the destination cannot be read, keep the current path: the parent check further\n // down rejects the move with its own error.\n const parentResult = await this.getFolder.execute(parentId);\n if (parentResult.isFail()) {\n return original;\n }\n\n const path = Path.create(slug, parentResult.value.path);\n\n return { type: original.type, path };\n }\n\n /**\n * Code-defined permissions are resolved from the folder's own type and path rather than the FLP\n * catalog, so they apply even when the stored record is missing or not yet written.\n */\n private async withCodePermissions(\n folder: Pick<Folder, \"type\" | \"path\">,\n permissions: FolderPermission[]\n ): Promise<FolderPermission[]> {\n if (!this.codeFlpsProvider) {\n return permissions;\n }\n\n const codePermissions = await this.codeFlpsProvider.getPermissions({\n type: folder.type,\n path: folder.path\n });\n\n return CodeFlpMerger.mergePermissions(permissions, codePermissions);\n }\n}\n\nexport const UpdateFolderWithFolderLevelPermissions = createDecorator({\n abstraction: UpdateFolderUseCase,\n decorator: UpdateFolderWithFolderLevelPermissionsImpl,\n // `CodeFlpsProvider` is optional: `CodeFlpsFeature` does not register it unless the project has\n // the folder-level permissions entitlement.\n dependencies: [GetFolderUseCase, FolderLevelPermissions, [CodeFlpsProvider, { optional: true }]]\n});\n"],"names":["UpdateFolderWithFolderLevelPermissionsImpl","getFolder","folderLevelPermissions","codeFlpsProvider","decoretee","id","params","originalResult","Result","original","originalPermissions","targetFolder","submittedPermissions","permissions","stillHasAccess","FolderValidationError","Array","permission","targetIsValid","parentPermissions","canAccessFolder","FolderCannotMoveToNewParent","result","updatedPermissions","updatedPermissionsWithDefaults","slug","parentId","undefined","parentPath","path","Path","parentResult","folder","codePermissions","CodeFlpMerger","UpdateFolderWithFolderLevelPermissions","createDecorator","UpdateFolderUseCase","GetFolderUseCase","FolderLevelPermissions","CodeFlpsProvider"],"mappings":"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"}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import type { AcoStorageOperations as IAcoStorageOperations } from "../../../types.js";
|
|
2
|
+
import type { AcoFilterCrud as IAcoFilterCrud } from "../../../filter/filter.types.js";
|
|
3
|
+
import type { AcoFolderLevelPermissionsCrud } from "../../../flp/flp.types.js";
|
|
2
4
|
/** Storage operations for folder filtering. */
|
|
3
5
|
export declare const FilterStorageOperations: import("@webiny/di").Abstraction<import("~/types.js").AcoFilterStorageOperations>;
|
|
4
6
|
export declare namespace FilterStorageOperations {
|
|
5
7
|
type Interface = IAcoStorageOperations["filter"];
|
|
6
8
|
}
|
|
9
|
+
export declare const FlpStorageOperations: import("@webiny/di").Abstraction<import("~/types.js").AcoFolderLevelPermissionsStorageOperations>;
|
|
10
|
+
export declare namespace FlpStorageOperations {
|
|
11
|
+
type Interface = IAcoStorageOperations["flp"];
|
|
12
|
+
}
|
|
13
|
+
export declare const AcoFlpCrud: import("@webiny/di").Abstraction<AcoFolderLevelPermissionsCrud>;
|
|
14
|
+
export declare namespace AcoFlpCrud {
|
|
15
|
+
type Interface = AcoFolderLevelPermissionsCrud;
|
|
16
|
+
}
|
|
17
|
+
export declare const AcoFilterCrud: import("@webiny/di").Abstraction<IAcoFilterCrud>;
|
|
18
|
+
export declare namespace AcoFilterCrud {
|
|
19
|
+
type Interface = IAcoFilterCrud;
|
|
20
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { createAbstraction } from "@webiny/feature/api";
|
|
2
2
|
const FilterStorageOperations = createAbstraction("FilterStorageOperations");
|
|
3
|
-
|
|
3
|
+
const FlpStorageOperations = createAbstraction("FlpStorageOperations");
|
|
4
|
+
const AcoFlpCrud = createAbstraction("AcoFlpCrud");
|
|
5
|
+
const AcoFilterCrud = createAbstraction("AcoFilterCrud");
|
|
6
|
+
export { AcoFilterCrud, AcoFlpCrud, FilterStorageOperations, FlpStorageOperations };
|
|
4
7
|
|
|
5
8
|
//# sourceMappingURL=abstractions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/folder/shared/abstractions.js","sources":["../../../../src/features/folder/shared/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { AcoStorageOperations as IAcoStorageOperations } from \"~/types.js\";\n\n/** Storage operations for folder filtering. */\nexport const FilterStorageOperations =\n createAbstraction<IAcoStorageOperations[\"filter\"]>(\"FilterStorageOperations\");\n\nexport namespace FilterStorageOperations {\n export type Interface = IAcoStorageOperations[\"filter\"];\n}\n"],"names":["FilterStorageOperations","createAbstraction"],"mappings":";
|
|
1
|
+
{"version":3,"file":"features/folder/shared/abstractions.js","sources":["../../../../src/features/folder/shared/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { AcoStorageOperations as IAcoStorageOperations } from \"~/types.js\";\nimport type { AcoFilterCrud as IAcoFilterCrud } from \"~/filter/filter.types.js\";\nimport type { AcoFolderLevelPermissionsCrud } from \"~/flp/flp.types.js\";\n\n/** Storage operations for folder filtering. */\nexport const FilterStorageOperations =\n createAbstraction<IAcoStorageOperations[\"filter\"]>(\"FilterStorageOperations\");\n\nexport namespace FilterStorageOperations {\n export type Interface = IAcoStorageOperations[\"filter\"];\n}\n\nexport const FlpStorageOperations =\n createAbstraction<IAcoStorageOperations[\"flp\"]>(\"FlpStorageOperations\");\n\nexport namespace FlpStorageOperations {\n export type Interface = IAcoStorageOperations[\"flp\"];\n}\n\nexport const AcoFlpCrud = createAbstraction<AcoFolderLevelPermissionsCrud>(\"AcoFlpCrud\");\n\nexport namespace AcoFlpCrud {\n export type Interface = AcoFolderLevelPermissionsCrud;\n}\n\nexport const AcoFilterCrud = createAbstraction<IAcoFilterCrud>(\"AcoFilterCrud\");\n\nexport namespace AcoFilterCrud {\n export type Interface = IAcoFilterCrud;\n}\n"],"names":["FilterStorageOperations","createAbstraction","FlpStorageOperations","AcoFlpCrud","AcoFilterCrud"],"mappings":";AAMO,MAAMA,0BACTC,kBAAmD;AAMhD,MAAMC,uBACTD,kBAAgD;AAM7C,MAAME,aAAaF,kBAAiD;AAMpE,MAAMG,gBAAgBH,kBAAkC"}
|
package/filter/filter.gql.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare const filterSchema: GraphQLSchemaPlugin<AcoContext>;
|
|
1
|
+
import type { IGraphQLSchemaBuilder } from "@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js";
|
|
2
|
+
export declare const addFilterSchema: (builder: IGraphQLSchemaBuilder) => void;
|