@webiny/api-aco 6.6.0-alpha.0 → 6.6.0-alpha.2
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.js +9 -2
- package/AcoFeature.js.map +1 -1
- package/AcoFolderSchemaFactory.d.ts +30 -0
- package/AcoFolderSchemaFactory.js +64 -0
- package/AcoFolderSchemaFactory.js.map +1 -0
- package/createAcoGraphQL.d.ts +3 -2
- 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/features/ai/CreateFolderTool.d.ts +44 -0
- package/features/ai/CreateFolderTool.js +49 -0
- package/features/ai/CreateFolderTool.js.map +1 -0
- package/features/ai/CreateTeamTool.d.ts +43 -0
- package/features/ai/CreateTeamTool.js +47 -0
- package/features/ai/CreateTeamTool.js.map +1 -0
- package/features/ai/GrantFolderAccessTool.d.ts +72 -0
- package/features/ai/GrantFolderAccessTool.js +71 -0
- package/features/ai/GrantFolderAccessTool.js.map +1 -0
- package/features/ai/ListFoldersTool.d.ts +42 -0
- package/features/ai/ListFoldersTool.js +48 -0
- package/features/ai/ListFoldersTool.js.map +1 -0
- package/features/ai/ListRolesTool.d.ts +34 -0
- package/features/ai/ListRolesTool.js +39 -0
- package/features/ai/ListRolesTool.js.map +1 -0
- package/features/ai/ListTeamsTool.d.ts +34 -0
- package/features/ai/ListTeamsTool.js +39 -0
- package/features/ai/ListTeamsTool.js.map +1 -0
- package/features/ai/RevokeFolderAccessTool.d.ts +58 -0
- package/features/ai/RevokeFolderAccessTool.js +60 -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 +23 -0
- package/features/ai/feature.js.map +1 -0
- package/features/ai/index.d.ts +8 -0
- package/features/ai/index.js +8 -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/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/UpdateFlp/UpdateFlpUseCase.d.ts +3 -3
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js +4 -3
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js.map +1 -1
- package/features/flp/UpdateFlp/feature.js +2 -2
- package/features/flp/UpdateFlp/feature.js.map +1 -1
- 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/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/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/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/UpdateFolder/UpdateFolderRepository.d.ts +3 -3
- package/features/folder/UpdateFolder/UpdateFolderRepository.js +11 -8
- package/features/folder/UpdateFolder/UpdateFolderRepository.js.map +1 -1
- package/folder/folder.gql.js +2 -2
- package/folder/folder.gql.js.map +1 -1
- package/package.json +23 -22
- package/AcoInitializer.d.ts +0 -25
- package/AcoInitializer.js +0 -79
- package/AcoInitializer.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/ai/loadFolderPermissions.js","sources":["../../../src/features/ai/loadFolderPermissions.ts"],"sourcesContent":["import type { GetFolderUseCase } from \"~/features/folder/GetFolder/index.js\";\nimport type { Folder, FolderPermission } from \"~/types.js\";\n\nexport interface LoadedFolderPermissions {\n folder: Folder;\n /** Rules set on this folder. The only ones it may change. */\n direct: FolderPermission[];\n /** Targets granted by an ancestor or a role. Writing these back would detach the inheritance. */\n inheritedTargets: Set<string>;\n}\n\n/**\n * Reads a folder and separates the rules it owns from the ones it merely inherits.\n *\n * Every permission write starts here, because the field holds both kinds and a change has to preserve\n * the direct rules while leaving the inherited ones alone.\n */\nexport const loadFolderPermissions = async (\n getFolder: GetFolderUseCase.Interface,\n folderId: string\n): Promise<LoadedFolderPermissions> => {\n const result = await getFolder.execute(folderId);\n\n if (result.isFail()) {\n throw new Error(\n `Folder \"${folderId}\" not found: ${result.error.message}. Call listFolders for valid ids.`\n );\n }\n\n const folder = result.value;\n const permissions = folder.permissions ?? [];\n\n return {\n folder,\n direct: permissions.filter(permission => !permission.inheritedFrom),\n inheritedTargets: new Set(\n permissions.filter(permission => permission.inheritedFrom).map(p => String(p.target))\n )\n };\n};\n"],"names":["loadFolderPermissions","getFolder","folderId","result","Error","folder","permissions","permission","Set","p","String"],"mappings":"AAiBO,MAAMA,wBAAwB,OACjCC,WACAC;IAEA,MAAMC,SAAS,MAAMF,UAAU,OAAO,CAACC;IAEvC,IAAIC,OAAO,MAAM,IACb,MAAM,IAAIC,MACN,CAAC,QAAQ,EAAEF,SAAS,aAAa,EAAEC,OAAO,KAAK,CAAC,OAAO,CAAC,iCAAiC,CAAC;IAIlG,MAAME,SAASF,OAAO,KAAK;IAC3B,MAAMG,cAAcD,OAAO,WAAW,IAAI,EAAE;IAE5C,OAAO;QACHA;QACA,QAAQC,YAAY,MAAM,CAACC,CAAAA,aAAc,CAACA,WAAW,aAAa;QAClE,kBAAkB,IAAIC,IAClBF,YAAY,MAAM,CAACC,CAAAA,aAAcA,WAAW,aAAa,EAAE,GAAG,CAACE,CAAAA,IAAKC,OAAOD,EAAE,MAAM;IAE3F;AACJ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
3
3
|
import { ListUserTeamsUseCase } from "@webiny/api-core/features/users/ListUserTeams/index.js";
|
|
4
4
|
import { type CanAccessFolderContentParams, type CanAccessFolderParams } from "./useCases/index.js";
|
|
5
5
|
import { FolderLevelPermissions as FolderLevelPermissionsAbstraction } from "./abstractions.js";
|
|
@@ -8,11 +8,11 @@ import { ListFlpsUseCase } from "../../../features/flp/ListFlps/index.js";
|
|
|
8
8
|
import { GetFlpUseCase } from "../../../features/flp/GetFlp/index.js";
|
|
9
9
|
declare class FolderLevelPermissionsImpl implements FolderLevelPermissionsAbstraction.Interface {
|
|
10
10
|
private identityContext;
|
|
11
|
-
private
|
|
11
|
+
private featureFlags;
|
|
12
12
|
private listUserTeamsUseCase;
|
|
13
13
|
private getFlpUseCase;
|
|
14
14
|
private listFlpsUseCase;
|
|
15
|
-
constructor(identityContext: IdentityContext.Interface,
|
|
15
|
+
constructor(identityContext: IdentityContext.Interface, featureFlags: FeatureFlags.Interface, listUserTeamsUseCase: ListUserTeamsUseCase.Interface, getFlpUseCase: GetFlpUseCase.Interface, listFlpsUseCase: ListFlpsUseCase.Interface);
|
|
16
16
|
canUseFolderLevelPermissions(enabled?: boolean): boolean;
|
|
17
17
|
canUseTeams(): boolean;
|
|
18
18
|
canCreateFolderInRoot(): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createImplementation } from "@webiny/di";
|
|
2
2
|
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
4
4
|
import { ListUserTeamsUseCase } from "@webiny/api-core/features/users/ListUserTeams/index.js";
|
|
5
5
|
import { NotAuthorizedError } from "@webiny/api-core/features/security/shared/index.js";
|
|
6
6
|
import { CanAccessFolder, CanAccessFolderContent, CanCreateFolderInRoot, CheckNotInheritedPermissions, GetDefaultPermissions, GetDefaultPermissionsWithTeams } from "./useCases/index.js";
|
|
@@ -8,9 +8,9 @@ import { FolderLevelPermissions } from "./abstractions.js";
|
|
|
8
8
|
import { ListFlpsUseCase } from "../ListFlps/index.js";
|
|
9
9
|
import { GetFlpUseCase } from "../GetFlp/index.js";
|
|
10
10
|
class FolderLevelPermissionsImpl {
|
|
11
|
-
constructor(identityContext,
|
|
11
|
+
constructor(identityContext, featureFlags, listUserTeamsUseCase, getFlpUseCase, listFlpsUseCase){
|
|
12
12
|
this.identityContext = identityContext;
|
|
13
|
-
this.
|
|
13
|
+
this.featureFlags = featureFlags;
|
|
14
14
|
this.listUserTeamsUseCase = listUserTeamsUseCase;
|
|
15
15
|
this.getFlpUseCase = getFlpUseCase;
|
|
16
16
|
this.listFlpsUseCase = listFlpsUseCase;
|
|
@@ -20,10 +20,10 @@ class FolderLevelPermissionsImpl {
|
|
|
20
20
|
const identity = this.identityContext.getIdentity();
|
|
21
21
|
if (!identity) return false;
|
|
22
22
|
if ("admin" !== identity.type) return false;
|
|
23
|
-
return this.
|
|
23
|
+
return this.featureFlags.get().isEnabled("advancedAccessControlLayer.folderLevelPermissions");
|
|
24
24
|
}
|
|
25
25
|
canUseTeams() {
|
|
26
|
-
return this.
|
|
26
|
+
return this.featureFlags.get().isEnabled("advancedAccessControlLayer.teams");
|
|
27
27
|
}
|
|
28
28
|
canCreateFolderInRoot() {
|
|
29
29
|
const canCreateFolderInRootUseCase = new CanCreateFolderInRoot();
|
|
@@ -101,7 +101,7 @@ const FolderLevelPermissions_FolderLevelPermissions = createImplementation({
|
|
|
101
101
|
implementation: FolderLevelPermissionsImpl,
|
|
102
102
|
dependencies: [
|
|
103
103
|
IdentityContext,
|
|
104
|
-
|
|
104
|
+
FeatureFlags,
|
|
105
105
|
ListUserTeamsUseCase,
|
|
106
106
|
GetFlpUseCase,
|
|
107
107
|
ListFlpsUseCase
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/flp/FolderLevelPermissions/FolderLevelPermissions.js","sources":["../../../../src/features/flp/FolderLevelPermissions/FolderLevelPermissions.ts"],"sourcesContent":["import { createImplementation } from \"@webiny/di\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { WcpContext } from \"@webiny/api-core/features/wcp/WcpContext/index.js\";\nimport { ListUserTeamsUseCase } from \"@webiny/api-core/features/users/ListUserTeams/index.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport {\n CanAccessFolder,\n CanAccessFolderContent,\n type CanAccessFolderContentParams,\n type CanAccessFolderParams,\n CanCreateFolderInRoot,\n CheckNotInheritedPermissions,\n GetDefaultPermissions,\n GetDefaultPermissionsWithTeams\n} from \"./useCases/index.js\";\nimport { FolderLevelPermissions as FolderLevelPermissionsAbstraction } from \"./abstractions.js\";\nimport type { FolderLevelPermission, FolderPermission, ListFlpsParams } from \"~/types.js\";\nimport { ListFlpsUseCase } from \"~/features/flp/ListFlps/index.js\";\nimport { GetFlpUseCase } from \"~/features/flp/GetFlp/index.js\";\n\nclass FolderLevelPermissionsImpl implements FolderLevelPermissionsAbstraction.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private wcpContext: WcpContext.Interface,\n private listUserTeamsUseCase: ListUserTeamsUseCase.Interface,\n private getFlpUseCase: GetFlpUseCase.Interface,\n private listFlpsUseCase: ListFlpsUseCase.Interface\n ) {}\n\n public canUseFolderLevelPermissions(enabled?: boolean): boolean {\n if (enabled === false) {\n return false;\n }\n\n const identity = this.identityContext.getIdentity();\n\n // FLPs only work with authenticated identities (logged-in users).\n if (!identity) {\n return false;\n }\n\n // At the moment, we only want FLP to be used with identities of type \"admin\".\n // This temporarily addresses the issue of API keys not being able to access content, because\n // FLPs doesn't work with them. Once we start adding FLPs to API keys, we can remove this check.\n if (identity.type !== \"admin\") {\n return false;\n }\n\n return this.wcpContext.canUseFolderLevelPermissions();\n }\n\n public canUseTeams(): boolean {\n return this.wcpContext.canUseTeams();\n }\n\n public canCreateFolderInRoot(): boolean {\n const canCreateFolderInRootUseCase = new CanCreateFolderInRoot();\n return canCreateFolderInRootUseCase.execute();\n }\n\n public permissionsIncludeNonInheritedPermissions(permissions: FolderPermission[]): boolean {\n const checkNotInheritedPermissionsUseCase = new CheckNotInheritedPermissions();\n return checkNotInheritedPermissionsUseCase.execute(permissions);\n }\n\n public async canAccessFolder(params: CanAccessFolderParams): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n const canAccessFolderUseCase = new CanAccessFolder(this.identityContext);\n return await canAccessFolderUseCase.execute(params);\n }\n\n public async canAccessFolderContent(params: CanAccessFolderContentParams): Promise<boolean> {\n const canUseFlp = this.canUseFolderLevelPermissions();\n const authEnabled = this.identityContext.isAuthorizationEnabled();\n\n if (!canUseFlp || !authEnabled) {\n return true;\n }\n\n const canAccessFolderContentUseCase = new CanAccessFolderContent(this.identityContext);\n return await canAccessFolderContentUseCase.execute(params);\n }\n\n public async ensureCanAccessFolder(params: CanAccessFolderParams): Promise<void> {\n const result = await this.canAccessFolder(params);\n if (!result) {\n throw new NotAuthorizedError();\n }\n }\n\n public async ensureCanAccessFolderContent(params: CanAccessFolderContentParams): Promise<void> {\n const result = await this.canAccessFolderContent(params);\n if (!result) {\n throw new NotAuthorizedError();\n }\n }\n\n public async canManageFolderContent(flp: FolderLevelPermission): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n return await this.canAccessFolderContent({ permissions: flp.permissions, rwd: \"w\" });\n }\n\n public async canManageFolderStructure(flp: FolderLevelPermission): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n return await this.canAccessFolder({ permissions: flp.permissions, rwd: \"w\" });\n }\n\n public async canManageFolderPermissions(flp: FolderLevelPermission): Promise<boolean> {\n if (!this.canUseFolderLevelPermissions()) {\n return false;\n }\n\n if (!this.identityContext.isAuthorizationEnabled()) {\n return true;\n }\n\n return await this.canAccessFolder({\n permissions: flp.permissions,\n rwd: \"w\",\n managePermissions: true\n });\n }\n\n public getDefaultPermissions(permissions: FolderPermission[]): Promise<FolderPermission[]> {\n const getDefaultPermissionsUseCase = new GetDefaultPermissions(this.identityContext);\n\n if (this.canUseTeams()) {\n const getDefaultPermissionsWithTeams = new GetDefaultPermissionsWithTeams(\n this.identityContext,\n this.listUserTeamsUseCase,\n getDefaultPermissionsUseCase\n );\n\n return getDefaultPermissionsWithTeams.execute(permissions);\n }\n\n return getDefaultPermissionsUseCase.execute(permissions);\n }\n\n public async listFolderLevelPermissions(params: ListFlpsParams): Promise<\n Array<{\n id: string;\n permissions: FolderPermission[];\n }>\n > {\n const flps = await this.listFlpsUseCase.execute(params);\n\n return Promise.all(\n flps.map(async flp => ({\n id: flp.id,\n permissions: await this.getDefaultPermissions(flp.permissions)\n }))\n );\n }\n\n public async getFolderLevelPermissions(id: string): Promise<FolderPermission[]> {\n const flp = await this.getFlpUseCase.execute(id);\n return await this.getDefaultPermissions(flp?.permissions ?? []);\n }\n}\n\nexport const FolderLevelPermissions = createImplementation({\n abstraction: FolderLevelPermissionsAbstraction,\n implementation: FolderLevelPermissionsImpl,\n dependencies: [\n IdentityContext,\n WcpContext,\n ListUserTeamsUseCase,\n GetFlpUseCase,\n ListFlpsUseCase\n ]\n});\n"],"names":["FolderLevelPermissionsImpl","identityContext","wcpContext","listUserTeamsUseCase","getFlpUseCase","listFlpsUseCase","enabled","identity","canCreateFolderInRootUseCase","CanCreateFolderInRoot","permissions","checkNotInheritedPermissionsUseCase","CheckNotInheritedPermissions","params","canAccessFolderUseCase","CanAccessFolder","canUseFlp","authEnabled","canAccessFolderContentUseCase","CanAccessFolderContent","result","NotAuthorizedError","flp","getDefaultPermissionsUseCase","GetDefaultPermissions","getDefaultPermissionsWithTeams","GetDefaultPermissionsWithTeams","flps","Promise","id","FolderLevelPermissions","createImplementation","FolderLevelPermissionsAbstraction","IdentityContext","WcpContext","ListUserTeamsUseCase","GetFlpUseCase","ListFlpsUseCase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"features/flp/FolderLevelPermissions/FolderLevelPermissions.js","sources":["../../../../src/features/flp/FolderLevelPermissions/FolderLevelPermissions.ts"],"sourcesContent":["import { createImplementation } from \"@webiny/di\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\nimport { ListUserTeamsUseCase } from \"@webiny/api-core/features/users/ListUserTeams/index.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport {\n CanAccessFolder,\n CanAccessFolderContent,\n type CanAccessFolderContentParams,\n type CanAccessFolderParams,\n CanCreateFolderInRoot,\n CheckNotInheritedPermissions,\n GetDefaultPermissions,\n GetDefaultPermissionsWithTeams\n} from \"./useCases/index.js\";\nimport { FolderLevelPermissions as FolderLevelPermissionsAbstraction } from \"./abstractions.js\";\nimport type { FolderLevelPermission, FolderPermission, ListFlpsParams } from \"~/types.js\";\nimport { ListFlpsUseCase } from \"~/features/flp/ListFlps/index.js\";\nimport { GetFlpUseCase } from \"~/features/flp/GetFlp/index.js\";\n\nclass FolderLevelPermissionsImpl implements FolderLevelPermissionsAbstraction.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private featureFlags: FeatureFlags.Interface,\n private listUserTeamsUseCase: ListUserTeamsUseCase.Interface,\n private getFlpUseCase: GetFlpUseCase.Interface,\n private listFlpsUseCase: ListFlpsUseCase.Interface\n ) {}\n\n public canUseFolderLevelPermissions(enabled?: boolean): boolean {\n if (enabled === false) {\n return false;\n }\n\n const identity = this.identityContext.getIdentity();\n\n // FLPs only work with authenticated identities (logged-in users).\n if (!identity) {\n return false;\n }\n\n // At the moment, we only want FLP to be used with identities of type \"admin\".\n // This temporarily addresses the issue of API keys not being able to access content, because\n // FLPs doesn't work with them. Once we start adding FLPs to API keys, we can remove this check.\n if (identity.type !== \"admin\") {\n return false;\n }\n\n return this.featureFlags\n .get()\n .isEnabled(\"advancedAccessControlLayer.folderLevelPermissions\");\n }\n\n public canUseTeams(): boolean {\n return this.featureFlags.get().isEnabled(\"advancedAccessControlLayer.teams\");\n }\n\n public canCreateFolderInRoot(): boolean {\n const canCreateFolderInRootUseCase = new CanCreateFolderInRoot();\n return canCreateFolderInRootUseCase.execute();\n }\n\n public permissionsIncludeNonInheritedPermissions(permissions: FolderPermission[]): boolean {\n const checkNotInheritedPermissionsUseCase = new CheckNotInheritedPermissions();\n return checkNotInheritedPermissionsUseCase.execute(permissions);\n }\n\n public async canAccessFolder(params: CanAccessFolderParams): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n const canAccessFolderUseCase = new CanAccessFolder(this.identityContext);\n return await canAccessFolderUseCase.execute(params);\n }\n\n public async canAccessFolderContent(params: CanAccessFolderContentParams): Promise<boolean> {\n const canUseFlp = this.canUseFolderLevelPermissions();\n const authEnabled = this.identityContext.isAuthorizationEnabled();\n\n if (!canUseFlp || !authEnabled) {\n return true;\n }\n\n const canAccessFolderContentUseCase = new CanAccessFolderContent(this.identityContext);\n return await canAccessFolderContentUseCase.execute(params);\n }\n\n public async ensureCanAccessFolder(params: CanAccessFolderParams): Promise<void> {\n const result = await this.canAccessFolder(params);\n if (!result) {\n throw new NotAuthorizedError();\n }\n }\n\n public async ensureCanAccessFolderContent(params: CanAccessFolderContentParams): Promise<void> {\n const result = await this.canAccessFolderContent(params);\n if (!result) {\n throw new NotAuthorizedError();\n }\n }\n\n public async canManageFolderContent(flp: FolderLevelPermission): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n return await this.canAccessFolderContent({ permissions: flp.permissions, rwd: \"w\" });\n }\n\n public async canManageFolderStructure(flp: FolderLevelPermission): Promise<boolean> {\n if (\n !this.canUseFolderLevelPermissions() ||\n !this.identityContext.isAuthorizationEnabled()\n ) {\n return true;\n }\n\n return await this.canAccessFolder({ permissions: flp.permissions, rwd: \"w\" });\n }\n\n public async canManageFolderPermissions(flp: FolderLevelPermission): Promise<boolean> {\n if (!this.canUseFolderLevelPermissions()) {\n return false;\n }\n\n if (!this.identityContext.isAuthorizationEnabled()) {\n return true;\n }\n\n return await this.canAccessFolder({\n permissions: flp.permissions,\n rwd: \"w\",\n managePermissions: true\n });\n }\n\n public getDefaultPermissions(permissions: FolderPermission[]): Promise<FolderPermission[]> {\n const getDefaultPermissionsUseCase = new GetDefaultPermissions(this.identityContext);\n\n if (this.canUseTeams()) {\n const getDefaultPermissionsWithTeams = new GetDefaultPermissionsWithTeams(\n this.identityContext,\n this.listUserTeamsUseCase,\n getDefaultPermissionsUseCase\n );\n\n return getDefaultPermissionsWithTeams.execute(permissions);\n }\n\n return getDefaultPermissionsUseCase.execute(permissions);\n }\n\n public async listFolderLevelPermissions(params: ListFlpsParams): Promise<\n Array<{\n id: string;\n permissions: FolderPermission[];\n }>\n > {\n const flps = await this.listFlpsUseCase.execute(params);\n\n return Promise.all(\n flps.map(async flp => ({\n id: flp.id,\n permissions: await this.getDefaultPermissions(flp.permissions)\n }))\n );\n }\n\n public async getFolderLevelPermissions(id: string): Promise<FolderPermission[]> {\n const flp = await this.getFlpUseCase.execute(id);\n return await this.getDefaultPermissions(flp?.permissions ?? []);\n }\n}\n\nexport const FolderLevelPermissions = createImplementation({\n abstraction: FolderLevelPermissionsAbstraction,\n implementation: FolderLevelPermissionsImpl,\n dependencies: [\n IdentityContext,\n FeatureFlags,\n ListUserTeamsUseCase,\n GetFlpUseCase,\n ListFlpsUseCase\n ]\n});\n"],"names":["FolderLevelPermissionsImpl","identityContext","featureFlags","listUserTeamsUseCase","getFlpUseCase","listFlpsUseCase","enabled","identity","canCreateFolderInRootUseCase","CanCreateFolderInRoot","permissions","checkNotInheritedPermissionsUseCase","CheckNotInheritedPermissions","params","canAccessFolderUseCase","CanAccessFolder","canUseFlp","authEnabled","canAccessFolderContentUseCase","CanAccessFolderContent","result","NotAuthorizedError","flp","getDefaultPermissionsUseCase","GetDefaultPermissions","getDefaultPermissionsWithTeams","GetDefaultPermissionsWithTeams","flps","Promise","id","FolderLevelPermissions","createImplementation","FolderLevelPermissionsAbstraction","IdentityContext","FeatureFlags","ListUserTeamsUseCase","GetFlpUseCase","ListFlpsUseCase"],"mappings":"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"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { UpdateFlpParams, UpdateFlpUseCase as UseCaseAbstraction } from "./abstractions.js";
|
|
2
2
|
import type { AcoFlpCrud } from "../../../features/folder/shared/abstractions.js";
|
|
3
3
|
import type { ListFoldersUseCase } from "../../../features/folder/ListFolders/index.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
5
5
|
import type { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js";
|
|
6
6
|
import type { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
7
7
|
export declare class UpdateFlpUseCase implements UseCaseAbstraction.Interface {
|
|
8
8
|
private flpCrud;
|
|
9
9
|
private listFoldersUseCase;
|
|
10
|
-
private
|
|
10
|
+
private folderModelProvider;
|
|
11
11
|
private updateEntryUseCase;
|
|
12
12
|
private identityContext;
|
|
13
13
|
private isCloseToTimeout?;
|
|
14
14
|
private handleTimeout?;
|
|
15
15
|
private readonly queued;
|
|
16
16
|
private readonly flpsToUpdate;
|
|
17
|
-
constructor(flpCrud: AcoFlpCrud.Interface, listFoldersUseCase: ListFoldersUseCase.Interface,
|
|
17
|
+
constructor(flpCrud: AcoFlpCrud.Interface, listFoldersUseCase: ListFoldersUseCase.Interface, folderModelProvider: FolderModelProvider.Interface, updateEntryUseCase: UpdateEntryUseCase.Interface, identityContext: IdentityContext.Interface);
|
|
18
18
|
execute(params: UpdateFlpParams): Promise<void>;
|
|
19
19
|
private collectBranchForUpdate;
|
|
20
20
|
private executeBatchUpdate;
|
|
@@ -3,10 +3,10 @@ import { Path } from "../../../utils/Path.js";
|
|
|
3
3
|
import { Permissions, ROOT_FOLDER } from "@webiny/shared-aco";
|
|
4
4
|
import { EntryId } from "@webiny/api-headless-cms/exports/api/cms/entry.js";
|
|
5
5
|
class UpdateFlpUseCase {
|
|
6
|
-
constructor(flpCrud, listFoldersUseCase,
|
|
6
|
+
constructor(flpCrud, listFoldersUseCase, folderModelProvider, updateEntryUseCase, identityContext){
|
|
7
7
|
this.flpCrud = flpCrud;
|
|
8
8
|
this.listFoldersUseCase = listFoldersUseCase;
|
|
9
|
-
this.
|
|
9
|
+
this.folderModelProvider = folderModelProvider;
|
|
10
10
|
this.updateEntryUseCase = updateEntryUseCase;
|
|
11
11
|
this.identityContext = identityContext;
|
|
12
12
|
this.queued = new Set();
|
|
@@ -76,6 +76,7 @@ class UpdateFlpUseCase {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
async executeBatchUpdate() {
|
|
79
|
+
const folderModel = await this.folderModelProvider.get();
|
|
79
80
|
try {
|
|
80
81
|
const items = Array.from(this.flpsToUpdate.entries()).map(([id, { slug, parentId, path, permissions }])=>({
|
|
81
82
|
id,
|
|
@@ -90,7 +91,7 @@ class UpdateFlpUseCase {
|
|
|
90
91
|
for (const item of items){
|
|
91
92
|
const { id, data } = item;
|
|
92
93
|
const entryId = EntryId.from(id);
|
|
93
|
-
const updateResult = await this.updateEntryUseCase.execute(
|
|
94
|
+
const updateResult = await this.updateEntryUseCase.execute(folderModel, entryId.toString(), {
|
|
94
95
|
values: {
|
|
95
96
|
path: data.path
|
|
96
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/flp/UpdateFlp/UpdateFlpUseCase.js","sources":["../../../../src/features/flp/UpdateFlp/UpdateFlpUseCase.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport { Path } from \"~/utils/Path.js\";\nimport { Permissions, ROOT_FOLDER } from \"@webiny/shared-aco\";\nimport type { UpdateFlpParams, UpdateFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport type { Folder, FolderLevelPermission, FolderPermission } from \"~/types.js\";\nimport type { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\nimport type { ListFoldersUseCase } from \"~/features/folder/ListFolders/index.js\";\nimport type { FolderModel } from \"~/domain/folder/abstractions.js\";\nimport { EntryId } from \"@webiny/api-headless-cms/exports/api/cms/entry.js\";\nimport type { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js\";\nimport type { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\n\ninterface FlpUpdateData {\n parentId: string;\n slug: string;\n path: string;\n permissions: FolderPermission[];\n}\n\nexport class UpdateFlpUseCase implements UseCaseAbstraction.Interface {\n private isCloseToTimeout?: () => boolean;\n private handleTimeout?: (updated: string[]) => void;\n\n private readonly queued: Set<string> = new Set();\n private readonly flpsToUpdate: Map<string, FlpUpdateData> = new Map();\n\n constructor(\n private flpCrud: AcoFlpCrud.Interface,\n private listFoldersUseCase: ListFoldersUseCase.Interface,\n private folderModel: FolderModel.Interface,\n private updateEntryUseCase: UpdateEntryUseCase.Interface,\n private identityContext: IdentityContext.Interface\n ) {}\n\n async execute(params: UpdateFlpParams): Promise<void> {\n this.isCloseToTimeout = params.isCloseToTimeout;\n this.handleTimeout = params.handleTimeout;\n\n if (params.queued) {\n params.queued.forEach(id => this.queued.add(id));\n }\n\n try {\n const { folder } = params;\n\n if (!folder) {\n throw new WebinyError(\n \"Missing `folder`, I can't update the FLP record.\",\n \"ERROR_UPDATING_FLP_USE_CASE_FOLDER_NOT_PROVIDED\",\n { folder }\n );\n }\n\n const flp = await this.getFlp(folder);\n const parentFlp = folder.parentId ? await this.flpCrud.get(folder.parentId) : null;\n\n // Add the root folder to the update collection\n this.flpsToUpdate.set(folder.id, {\n slug: folder.slug,\n parentId: folder.parentId ?? ROOT_FOLDER,\n path: Path.create(folder.slug, parentFlp?.path),\n permissions: Permissions.create(folder.permissions, parentFlp)\n });\n\n // Let's set the FLP as in queue\n this.setQueued(flp.id);\n\n // Get direct children and process each branch completely\n const directChildren = await this.listDirectChildren(flp);\n\n for (const child of directChildren) {\n if (this.isCloseToTimeout?.()) {\n await this.executeBatchUpdate();\n this.handleTimeout?.(this.getQueuedList());\n return;\n }\n await this.collectBranchForUpdate(child, flp);\n }\n\n // Execute batch update\n await this.executeBatchUpdate();\n } catch (error) {\n // Clear the update collection in case of error\n this.flpsToUpdate.clear();\n this.queued.clear();\n throw WebinyError.from(error, {\n message: \"Error while updating FLP\",\n code: \"ERROR_UPDATING_FLP_USE_CASE\"\n });\n }\n }\n\n private async collectBranchForUpdate(\n flp: FolderLevelPermission,\n parentFlp: FolderLevelPermission\n ): Promise<void> {\n if (this.isQueued(flp.id)) {\n return;\n }\n\n // Get the parent's permissions from the update collection if available\n const parentFlpData = this.flpsToUpdate.get(parentFlp.id);\n const currentParentFlp = {\n ...parentFlp,\n ...(parentFlpData && { ...parentFlpData })\n };\n\n // Add the FLP to the update collection with inherited permissions\n this.flpsToUpdate.set(flp.id, {\n slug: flp.slug,\n parentId: flp.parentId,\n path: Path.create(flp.slug, currentParentFlp.path),\n permissions: Permissions.create(flp.permissions, currentParentFlp)\n });\n\n // Add the FLP to the queue list so we don't fetch it again\n this.setQueued(flp.id);\n\n // Process all children of this folder before moving to siblings\n const children = await this.listDirectChildren(flp);\n\n for (const child of children) {\n if (this.isCloseToTimeout?.()) {\n await this.executeBatchUpdate();\n this.handleTimeout?.(this.getQueuedList());\n return;\n }\n // Pass the current FLP as the parent for the child\n await this.collectBranchForUpdate(child, flp);\n }\n }\n\n private async executeBatchUpdate(): Promise<void> {\n try {\n const items = Array.from(this.flpsToUpdate.entries()).map(\n ([id, { slug, parentId, path, permissions }]) => {\n return {\n id,\n data: {\n slug,\n parentId,\n path,\n permissions\n }\n };\n }\n );\n\n await this.flpCrud.batchUpdate(items);\n\n // Update all folders with the new path\n for (const item of items) {\n const { id, data } = item;\n // Directly update the folder in CMS storage to bypass any folder update event triggers.\n const entryId = EntryId.from(id);\n const updateResult = await this.updateEntryUseCase.execute(\n this.folderModel,\n entryId.toString(),\n { values: { path: data.path } }\n );\n if (updateResult.isFail()) {\n throw updateResult.error;\n }\n }\n } catch (error) {\n throw WebinyError.from(error, {\n message: \"Error while executing batch update of FLPs\",\n code: \"BATCH_UPDATE_FLP_ERROR\",\n data: {\n items: Array.from(this.flpsToUpdate.keys())\n }\n });\n } finally {\n // Clear the update collection after the batch update\n this.flpsToUpdate.clear();\n\n //Let's remove all the updated FLPs ids from the queue cache\n this.clearQueuedList();\n }\n }\n\n private getQueuedList(): string[] {\n return Array.from(this.queued);\n }\n\n private setQueued(id: string): void {\n this.queued.add(id);\n }\n\n private isQueued(id: string): boolean {\n return this.queued.has(id);\n }\n\n private clearQueuedList(): void {\n this.queued.clear();\n }\n\n private async listDirectChildren(flp: FolderLevelPermission): Promise<FolderLevelPermission[]> {\n const result = await this.identityContext.withoutAuthorization(() => {\n return this.listFoldersUseCase.execute({\n where: {\n type: flp.type,\n parentId: flp.id\n }\n });\n });\n\n if (result.isFail()) {\n throw result.error;\n }\n\n return await Promise.all(result.value.folders.map(folder => this.getFlp(folder)));\n }\n\n private async getFlp({\n id,\n type,\n parentId,\n slug,\n permissions\n }: Folder): Promise<FolderLevelPermission> {\n const flp = await this.flpCrud.get(id);\n\n if (!flp) {\n const parentFlp = parentId ? await this.flpCrud.get(parentId) : null;\n\n return await this.flpCrud.create({\n id,\n type,\n slug,\n parentId: parentId ?? ROOT_FOLDER,\n path: Path.create(slug, parentFlp?.path),\n permissions: Permissions.create(permissions, parentFlp)\n });\n }\n\n return flp;\n }\n}\n"],"names":["UpdateFlpUseCase","flpCrud","listFoldersUseCase","folderModel","updateEntryUseCase","identityContext","Set","Map","params","id","folder","WebinyError","flp","parentFlp","ROOT_FOLDER","Path","Permissions","directChildren","child","error","parentFlpData","currentParentFlp","children","items","Array","slug","parentId","path","permissions","item","data","entryId","EntryId","updateResult","result","Promise","type"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"features/flp/UpdateFlp/UpdateFlpUseCase.js","sources":["../../../../src/features/flp/UpdateFlp/UpdateFlpUseCase.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport { Path } from \"~/utils/Path.js\";\nimport { Permissions, ROOT_FOLDER } from \"@webiny/shared-aco\";\nimport type { UpdateFlpParams, UpdateFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport type { Folder, FolderLevelPermission, FolderPermission } from \"~/types.js\";\nimport type { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\nimport type { ListFoldersUseCase } from \"~/features/folder/ListFolders/index.js\";\nimport type { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport { EntryId } from \"@webiny/api-headless-cms/exports/api/cms/entry.js\";\nimport type { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js\";\nimport type { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\n\ninterface FlpUpdateData {\n parentId: string;\n slug: string;\n path: string;\n permissions: FolderPermission[];\n}\n\nexport class UpdateFlpUseCase implements UseCaseAbstraction.Interface {\n private isCloseToTimeout?: () => boolean;\n private handleTimeout?: (updated: string[]) => void;\n\n private readonly queued: Set<string> = new Set();\n private readonly flpsToUpdate: Map<string, FlpUpdateData> = new Map();\n\n constructor(\n private flpCrud: AcoFlpCrud.Interface,\n private listFoldersUseCase: ListFoldersUseCase.Interface,\n private folderModelProvider: FolderModelProvider.Interface,\n private updateEntryUseCase: UpdateEntryUseCase.Interface,\n private identityContext: IdentityContext.Interface\n ) {}\n\n async execute(params: UpdateFlpParams): Promise<void> {\n this.isCloseToTimeout = params.isCloseToTimeout;\n this.handleTimeout = params.handleTimeout;\n\n if (params.queued) {\n params.queued.forEach(id => this.queued.add(id));\n }\n\n try {\n const { folder } = params;\n\n if (!folder) {\n throw new WebinyError(\n \"Missing `folder`, I can't update the FLP record.\",\n \"ERROR_UPDATING_FLP_USE_CASE_FOLDER_NOT_PROVIDED\",\n { folder }\n );\n }\n\n const flp = await this.getFlp(folder);\n const parentFlp = folder.parentId ? await this.flpCrud.get(folder.parentId) : null;\n\n // Add the root folder to the update collection\n this.flpsToUpdate.set(folder.id, {\n slug: folder.slug,\n parentId: folder.parentId ?? ROOT_FOLDER,\n path: Path.create(folder.slug, parentFlp?.path),\n permissions: Permissions.create(folder.permissions, parentFlp)\n });\n\n // Let's set the FLP as in queue\n this.setQueued(flp.id);\n\n // Get direct children and process each branch completely\n const directChildren = await this.listDirectChildren(flp);\n\n for (const child of directChildren) {\n if (this.isCloseToTimeout?.()) {\n await this.executeBatchUpdate();\n this.handleTimeout?.(this.getQueuedList());\n return;\n }\n await this.collectBranchForUpdate(child, flp);\n }\n\n // Execute batch update\n await this.executeBatchUpdate();\n } catch (error) {\n // Clear the update collection in case of error\n this.flpsToUpdate.clear();\n this.queued.clear();\n throw WebinyError.from(error, {\n message: \"Error while updating FLP\",\n code: \"ERROR_UPDATING_FLP_USE_CASE\"\n });\n }\n }\n\n private async collectBranchForUpdate(\n flp: FolderLevelPermission,\n parentFlp: FolderLevelPermission\n ): Promise<void> {\n if (this.isQueued(flp.id)) {\n return;\n }\n\n // Get the parent's permissions from the update collection if available\n const parentFlpData = this.flpsToUpdate.get(parentFlp.id);\n const currentParentFlp = {\n ...parentFlp,\n ...(parentFlpData && { ...parentFlpData })\n };\n\n // Add the FLP to the update collection with inherited permissions\n this.flpsToUpdate.set(flp.id, {\n slug: flp.slug,\n parentId: flp.parentId,\n path: Path.create(flp.slug, currentParentFlp.path),\n permissions: Permissions.create(flp.permissions, currentParentFlp)\n });\n\n // Add the FLP to the queue list so we don't fetch it again\n this.setQueued(flp.id);\n\n // Process all children of this folder before moving to siblings\n const children = await this.listDirectChildren(flp);\n\n for (const child of children) {\n if (this.isCloseToTimeout?.()) {\n await this.executeBatchUpdate();\n this.handleTimeout?.(this.getQueuedList());\n return;\n }\n // Pass the current FLP as the parent for the child\n await this.collectBranchForUpdate(child, flp);\n }\n }\n\n private async executeBatchUpdate(): Promise<void> {\n const folderModel = await this.folderModelProvider.get();\n try {\n const items = Array.from(this.flpsToUpdate.entries()).map(\n ([id, { slug, parentId, path, permissions }]) => {\n return {\n id,\n data: {\n slug,\n parentId,\n path,\n permissions\n }\n };\n }\n );\n\n await this.flpCrud.batchUpdate(items);\n\n // Update all folders with the new path\n for (const item of items) {\n const { id, data } = item;\n // Directly update the folder in CMS storage to bypass any folder update event triggers.\n const entryId = EntryId.from(id);\n const updateResult = await this.updateEntryUseCase.execute(\n folderModel,\n entryId.toString(),\n { values: { path: data.path } }\n );\n if (updateResult.isFail()) {\n throw updateResult.error;\n }\n }\n } catch (error) {\n throw WebinyError.from(error, {\n message: \"Error while executing batch update of FLPs\",\n code: \"BATCH_UPDATE_FLP_ERROR\",\n data: {\n items: Array.from(this.flpsToUpdate.keys())\n }\n });\n } finally {\n // Clear the update collection after the batch update\n this.flpsToUpdate.clear();\n\n //Let's remove all the updated FLPs ids from the queue cache\n this.clearQueuedList();\n }\n }\n\n private getQueuedList(): string[] {\n return Array.from(this.queued);\n }\n\n private setQueued(id: string): void {\n this.queued.add(id);\n }\n\n private isQueued(id: string): boolean {\n return this.queued.has(id);\n }\n\n private clearQueuedList(): void {\n this.queued.clear();\n }\n\n private async listDirectChildren(flp: FolderLevelPermission): Promise<FolderLevelPermission[]> {\n const result = await this.identityContext.withoutAuthorization(() => {\n return this.listFoldersUseCase.execute({\n where: {\n type: flp.type,\n parentId: flp.id\n }\n });\n });\n\n if (result.isFail()) {\n throw result.error;\n }\n\n return await Promise.all(result.value.folders.map(folder => this.getFlp(folder)));\n }\n\n private async getFlp({\n id,\n type,\n parentId,\n slug,\n permissions\n }: Folder): Promise<FolderLevelPermission> {\n const flp = await this.flpCrud.get(id);\n\n if (!flp) {\n const parentFlp = parentId ? await this.flpCrud.get(parentId) : null;\n\n return await this.flpCrud.create({\n id,\n type,\n slug,\n parentId: parentId ?? ROOT_FOLDER,\n path: Path.create(slug, parentFlp?.path),\n permissions: Permissions.create(permissions, parentFlp)\n });\n }\n\n return flp;\n }\n}\n"],"names":["UpdateFlpUseCase","flpCrud","listFoldersUseCase","folderModelProvider","updateEntryUseCase","identityContext","Set","Map","params","id","folder","WebinyError","flp","parentFlp","ROOT_FOLDER","Path","Permissions","directChildren","child","error","parentFlpData","currentParentFlp","children","folderModel","items","Array","slug","parentId","path","permissions","item","data","entryId","EntryId","updateResult","result","Promise","type"],"mappings":"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"}
|
|
@@ -3,13 +3,13 @@ import { UpdateFlpUseCase } from "./UpdateFlpUseCase.js";
|
|
|
3
3
|
import { UpdateFlpUseCase as external_abstractions_js_UpdateFlpUseCase } from "./abstractions.js";
|
|
4
4
|
import { AcoFlpCrud } from "../../folder/shared/abstractions.js";
|
|
5
5
|
import { ListFoldersUseCase } from "../../folder/ListFolders/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
7
7
|
import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js";
|
|
8
8
|
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
9
9
|
const UpdateFlpFeature = createFeature({
|
|
10
10
|
name: "UpdateFlp",
|
|
11
11
|
register (container) {
|
|
12
|
-
container.registerFactory(external_abstractions_js_UpdateFlpUseCase, ()=>new UpdateFlpUseCase(container.resolve(AcoFlpCrud), container.resolve(ListFoldersUseCase), container.resolve(
|
|
12
|
+
container.registerFactory(external_abstractions_js_UpdateFlpUseCase, ()=>new UpdateFlpUseCase(container.resolve(AcoFlpCrud), container.resolve(ListFoldersUseCase), container.resolve(FolderModelProvider), container.resolve(UpdateEntryUseCase), container.resolve(IdentityContext)));
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
15
|
export { UpdateFlpFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/flp/UpdateFlp/feature.js","sources":["../../../../src/features/flp/UpdateFlp/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport type { Container } from \"@webiny/di\";\nimport { UpdateFlpUseCase } from \"./UpdateFlpUseCase.js\";\nimport { UpdateFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folder/ListFolders/index.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/flp/UpdateFlp/feature.js","sources":["../../../../src/features/flp/UpdateFlp/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport type { Container } from \"@webiny/di\";\nimport { UpdateFlpUseCase } from \"./UpdateFlpUseCase.js\";\nimport { UpdateFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\nimport { ListFoldersUseCase } from \"~/features/folder/ListFolders/index.js\";\nimport { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\n\nexport const UpdateFlpFeature = createFeature({\n name: \"UpdateFlp\",\n register(container: Container) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new UpdateFlpUseCase(\n container.resolve(AcoFlpCrud),\n container.resolve(ListFoldersUseCase),\n container.resolve(FolderModelProvider),\n container.resolve(UpdateEntryUseCase),\n container.resolve(IdentityContext)\n );\n });\n }\n});\n"],"names":["UpdateFlpFeature","createFeature","container","UseCaseAbstraction","UpdateFlpUseCase","AcoFlpCrud","ListFoldersUseCase","FolderModelProvider","UpdateEntryUseCase","IdentityContext"],"mappings":";;;;;;;;AAUO,MAAMA,mBAAmBC,cAAc;IAC1C,MAAM;IACN,UAASC,SAAoB;QACzBA,UAAU,eAAe,CAACC,2CAAoB,IACnC,IAAIC,iBACPF,UAAU,OAAO,CAACG,aAClBH,UAAU,OAAO,CAACI,qBAClBJ,UAAU,OAAO,CAACK,sBAClBL,UAAU,OAAO,CAACM,qBAClBN,UAAU,OAAO,CAACO;IAG9B;AACJ"}
|
|
@@ -3,14 +3,14 @@ import { CreateFolderRepository as RepositoryAbstraction, type ICreateFolderRepo
|
|
|
3
3
|
import { CreateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/CreateEntry";
|
|
4
4
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
5
5
|
import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEntry/GetEntryById";
|
|
6
|
-
import {
|
|
6
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
7
7
|
import type { CreateFolderParams, Folder } from "../../../folder/folder.types.js";
|
|
8
8
|
declare class CreateFolderRepositoryImpl implements ICreateFolderRepository {
|
|
9
9
|
private createEntry;
|
|
10
10
|
private listLatestEntries;
|
|
11
11
|
private getEntryById;
|
|
12
|
-
private
|
|
13
|
-
constructor(createEntry: CreateEntryUseCase.Interface, listLatestEntries: ListLatestEntriesUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface,
|
|
12
|
+
private folderModelProvider;
|
|
13
|
+
constructor(createEntry: CreateEntryUseCase.Interface, listLatestEntries: ListLatestEntriesUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface, folderModelProvider: FolderModelProvider.Interface);
|
|
14
14
|
execute(data: CreateFolderParams): Promise<Result<Folder, RepositoryAbstraction.Error>>;
|
|
15
15
|
private checkExistingFolder;
|
|
16
16
|
private createFolderPath;
|
|
@@ -3,19 +3,20 @@ import { CreateFolderRepository } from "./abstractions.js";
|
|
|
3
3
|
import { CreateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/CreateEntry";
|
|
4
4
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
5
5
|
import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEntry/GetEntryById";
|
|
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 CreateFolderRepositoryImpl {
|
|
12
|
-
constructor(createEntry, listLatestEntries, getEntryById,
|
|
12
|
+
constructor(createEntry, listLatestEntries, getEntryById, folderModelProvider){
|
|
13
13
|
this.createEntry = createEntry;
|
|
14
14
|
this.listLatestEntries = listLatestEntries;
|
|
15
15
|
this.getEntryById = getEntryById;
|
|
16
|
-
this.
|
|
16
|
+
this.folderModelProvider = folderModelProvider;
|
|
17
17
|
}
|
|
18
18
|
async execute(data) {
|
|
19
|
+
const folderModel = await this.folderModelProvider.get();
|
|
19
20
|
const checkResult = await this.checkExistingFolder({
|
|
20
21
|
type: data.type,
|
|
21
22
|
slug: data.slug,
|
|
@@ -27,7 +28,7 @@ class CreateFolderRepositoryImpl {
|
|
|
27
28
|
parentId: data.parentId
|
|
28
29
|
});
|
|
29
30
|
if (pathResult.isFail()) return Result.fail(pathResult.error);
|
|
30
|
-
const result = await this.createEntry.execute(
|
|
31
|
+
const result = await this.createEntry.execute(folderModel, {
|
|
31
32
|
values: {
|
|
32
33
|
...data,
|
|
33
34
|
parentId: data.parentId || null,
|
|
@@ -42,8 +43,9 @@ class CreateFolderRepositoryImpl {
|
|
|
42
43
|
return Result.ok(folder);
|
|
43
44
|
}
|
|
44
45
|
async checkExistingFolder(params) {
|
|
46
|
+
const folderModel = await this.folderModelProvider.get();
|
|
45
47
|
const { type, slug, parentId, excludeId } = params;
|
|
46
|
-
const result = await this.listLatestEntries.execute(
|
|
48
|
+
const result = await this.listLatestEntries.execute(folderModel, {
|
|
47
49
|
where: {
|
|
48
50
|
latest: true,
|
|
49
51
|
values: {
|
|
@@ -63,9 +65,10 @@ class CreateFolderRepositoryImpl {
|
|
|
63
65
|
return Result.ok();
|
|
64
66
|
}
|
|
65
67
|
async createFolderPath(params) {
|
|
68
|
+
const folderModel = await this.folderModelProvider.get();
|
|
66
69
|
const { slug, parentId } = params;
|
|
67
70
|
if (!parentId) return Result.ok(Path.create(slug));
|
|
68
|
-
const parentResult = await this.getEntryById.execute(
|
|
71
|
+
const parentResult = await this.getEntryById.execute(folderModel, EntryId.from(parentId).toString());
|
|
69
72
|
if (parentResult.isFail()) return Result.fail(new FolderPersistenceError(new Error("Parent folder not found. Unable to create the folder path")));
|
|
70
73
|
const parentFolder = EntryToFolderMapper.toFolder(parentResult.value);
|
|
71
74
|
return Result.ok(Path.create(slug, parentFolder.path));
|
|
@@ -77,7 +80,7 @@ const CreateFolderRepository_CreateFolderRepository = CreateFolderRepository.cre
|
|
|
77
80
|
CreateEntryUseCase,
|
|
78
81
|
ListLatestEntriesUseCase,
|
|
79
82
|
GetEntryByIdUseCase,
|
|
80
|
-
|
|
83
|
+
FolderModelProvider
|
|
81
84
|
]
|
|
82
85
|
});
|
|
83
86
|
export { CreateFolderRepository_CreateFolderRepository as CreateFolderRepository };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/folder/CreateFolder/CreateFolderRepository.js","sources":["../../../../src/features/folder/CreateFolder/CreateFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n CreateFolderRepository as RepositoryAbstraction,\n type ICreateFolderRepository\n} from \"./abstractions.js\";\nimport { CreateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/CreateEntry\";\nimport { ListLatestEntriesUseCase } from \"@webiny/api-headless-cms/features/contentEntry/ListEntries\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/folder/CreateFolder/CreateFolderRepository.js","sources":["../../../../src/features/folder/CreateFolder/CreateFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n CreateFolderRepository as RepositoryAbstraction,\n type ICreateFolderRepository\n} from \"./abstractions.js\";\nimport { CreateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/CreateEntry\";\nimport { ListLatestEntriesUseCase } from \"@webiny/api-headless-cms/features/contentEntry/ListEntries\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport type { CmsEntryFolder, CreateFolderParams, Folder } 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 CreateFolderRepositoryImpl implements ICreateFolderRepository {\n constructor(\n private createEntry: CreateEntryUseCase.Interface,\n private listLatestEntries: ListLatestEntriesUseCase.Interface,\n private getEntryById: GetEntryByIdUseCase.Interface,\n private folderModelProvider: FolderModelProvider.Interface\n ) {}\n\n async execute(data: CreateFolderParams): Promise<Result<Folder, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n // Check if folder already exists\n const checkResult = await this.checkExistingFolder({\n type: data.type,\n slug: data.slug,\n parentId: data.parentId\n });\n\n if (checkResult.isFail()) {\n return Result.fail(checkResult.error);\n }\n\n // Create folder path\n const pathResult = await this.createFolderPath({\n slug: data.slug,\n parentId: data.parentId\n });\n\n if (pathResult.isFail()) {\n return Result.fail(pathResult.error);\n }\n\n // Create the entry\n const result = await this.createEntry.execute<CmsEntryFolder>(folderModel, {\n values: {\n ...data,\n parentId: data.parentId || null,\n path: pathResult.value\n }\n });\n\n if (result.isFail()) {\n if (result.error.code === \"Cms/Entry/ValidationError\") {\n return Result.fail(new FolderValidationError(result.error.message));\n }\n return Result.fail(new FolderPersistenceError(result.error));\n }\n\n const folder = EntryToFolderMapper.toFolder(result.value);\n return Result.ok(folder);\n }\n\n private async checkExistingFolder(params: {\n type: string;\n slug: string;\n parentId?: string | null;\n excludeId?: string;\n }): Promise<Result<void, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n const { type, slug, parentId, excludeId } = params;\n\n const result = await this.listLatestEntries.execute<CmsEntryFolder>(folderModel, {\n where: {\n latest: true,\n values: {\n type,\n slug,\n parentId\n },\n ...(excludeId ? { entryId_not: excludeId } : {})\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 CreateFolderRepository = RepositoryAbstraction.createImplementation({\n implementation: CreateFolderRepositoryImpl,\n dependencies: [\n CreateEntryUseCase,\n ListLatestEntriesUseCase,\n GetEntryByIdUseCase,\n FolderModelProvider\n ]\n});\n"],"names":["CreateFolderRepositoryImpl","createEntry","listLatestEntries","getEntryById","folderModelProvider","data","folderModel","checkResult","Result","pathResult","result","FolderValidationError","FolderPersistenceError","folder","EntryToFolderMapper","params","type","slug","parentId","excludeId","entries","Path","parentResult","EntryId","Error","parentFolder","CreateFolderRepository","RepositoryAbstraction","CreateEntryUseCase","ListLatestEntriesUseCase","GetEntryByIdUseCase","FolderModelProvider"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Result } from "@webiny/feature/api";
|
|
2
2
|
import { DeleteFolderRepository as RepositoryAbstraction, type IDeleteFolderRepository } from "./abstractions.js";
|
|
3
3
|
import { DeleteEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/DeleteEntry";
|
|
4
|
-
import {
|
|
4
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
5
5
|
import type { Folder } from "../../../folder/folder.types.js";
|
|
6
6
|
declare class DeleteFolderRepositoryImpl implements IDeleteFolderRepository {
|
|
7
7
|
private deleteEntry;
|
|
8
|
-
private
|
|
9
|
-
constructor(deleteEntry: DeleteEntryUseCase.Interface,
|
|
8
|
+
private folderModelProvider;
|
|
9
|
+
constructor(deleteEntry: DeleteEntryUseCase.Interface, folderModelProvider: FolderModelProvider.Interface);
|
|
10
10
|
execute(folder: Folder): Promise<Result<void, RepositoryAbstraction.Error>>;
|
|
11
11
|
}
|
|
12
12
|
export declare const DeleteFolderRepository: typeof DeleteFolderRepositoryImpl & {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Result } from "@webiny/feature/api";
|
|
2
2
|
import { DeleteFolderRepository } from "./abstractions.js";
|
|
3
3
|
import { DeleteEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/DeleteEntry";
|
|
4
|
-
import {
|
|
4
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
5
5
|
import { FolderNotAuthorizedError, FolderPersistenceError } from "../../../domain/folder/errors.js";
|
|
6
6
|
class DeleteFolderRepositoryImpl {
|
|
7
|
-
constructor(deleteEntry,
|
|
7
|
+
constructor(deleteEntry, folderModelProvider){
|
|
8
8
|
this.deleteEntry = deleteEntry;
|
|
9
|
-
this.
|
|
9
|
+
this.folderModelProvider = folderModelProvider;
|
|
10
10
|
}
|
|
11
11
|
async execute(folder) {
|
|
12
|
-
const
|
|
12
|
+
const folderModel = await this.folderModelProvider.get();
|
|
13
|
+
const result = await this.deleteEntry.execute(folderModel, folder.id, {
|
|
13
14
|
permanently: true,
|
|
14
15
|
force: true
|
|
15
16
|
});
|
|
@@ -24,7 +25,7 @@ const DeleteFolderRepository_DeleteFolderRepository = DeleteFolderRepository.cre
|
|
|
24
25
|
implementation: DeleteFolderRepositoryImpl,
|
|
25
26
|
dependencies: [
|
|
26
27
|
DeleteEntryUseCase,
|
|
27
|
-
|
|
28
|
+
FolderModelProvider
|
|
28
29
|
]
|
|
29
30
|
});
|
|
30
31
|
export { DeleteFolderRepository_DeleteFolderRepository as DeleteFolderRepository };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/folder/DeleteFolder/DeleteFolderRepository.js","sources":["../../../../src/features/folder/DeleteFolder/DeleteFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n DeleteFolderRepository as RepositoryAbstraction,\n type IDeleteFolderRepository\n} from \"./abstractions.js\";\nimport { DeleteEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/DeleteEntry\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/folder/DeleteFolder/DeleteFolderRepository.js","sources":["../../../../src/features/folder/DeleteFolder/DeleteFolderRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport {\n DeleteFolderRepository as RepositoryAbstraction,\n type IDeleteFolderRepository\n} from \"./abstractions.js\";\nimport { DeleteEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/DeleteEntry\";\nimport { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport type { Folder } from \"~/folder/folder.types.js\";\nimport { FolderNotAuthorizedError, FolderPersistenceError } from \"~/domain/folder/errors.js\";\n\nclass DeleteFolderRepositoryImpl implements IDeleteFolderRepository {\n constructor(\n private deleteEntry: DeleteEntryUseCase.Interface,\n private folderModelProvider: FolderModelProvider.Interface\n ) {}\n\n async execute(folder: Folder): Promise<Result<void, RepositoryAbstraction.Error>> {\n const folderModel = await this.folderModelProvider.get();\n const result = await this.deleteEntry.execute(folderModel, folder.id, {\n permanently: true,\n force: true\n });\n\n if (result.isFail()) {\n if (result.error.code === \"Cms/Entry/NotAuthorized\") {\n return Result.fail(new FolderNotAuthorizedError());\n }\n return Result.fail(new FolderPersistenceError(result.error));\n }\n\n return Result.ok();\n }\n}\n\nexport const DeleteFolderRepository = RepositoryAbstraction.createImplementation({\n implementation: DeleteFolderRepositoryImpl,\n dependencies: [DeleteEntryUseCase, FolderModelProvider]\n});\n"],"names":["DeleteFolderRepositoryImpl","deleteEntry","folderModelProvider","folder","folderModel","result","Result","FolderNotAuthorizedError","FolderPersistenceError","DeleteFolderRepository","RepositoryAbstraction","DeleteEntryUseCase","FolderModelProvider"],"mappings":";;;;;AAUA,MAAMA;IACF,YACYC,WAAyC,EACzCC,mBAAkD,CAC5D;aAFUD,WAAW,GAAXA;aACAC,mBAAmB,GAAnBA;IACT;IAEH,MAAM,QAAQC,MAAc,EAAsD;QAC9E,MAAMC,cAAc,MAAM,IAAI,CAAC,mBAAmB,CAAC,GAAG;QACtD,MAAMC,SAAS,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAACD,aAAaD,OAAO,EAAE,EAAE;YAClE,aAAa;YACb,OAAO;QACX;QAEA,IAAIE,OAAO,MAAM,IAAI;YACjB,IAAIA,AAAsB,8BAAtBA,OAAO,KAAK,CAAC,IAAI,EACjB,OAAOC,OAAO,IAAI,CAAC,IAAIC;YAE3B,OAAOD,OAAO,IAAI,CAAC,IAAIE,uBAAuBH,OAAO,KAAK;QAC9D;QAEA,OAAOC,OAAO,EAAE;IACpB;AACJ;AAEO,MAAMG,gDAAyBC,uBAAAA,oBAA0C,CAAC;IAC7E,gBAAgBV;IAChB,cAAc;QAACW;QAAoBC;KAAoB;AAC3D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CmsModel } from "@webiny/api-headless-cms/types";
|
|
2
|
+
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
3
|
+
import { FolderModelProvider as Abstraction } from "../../domain/folder/abstractions.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the tenant's ACO folder model on demand, replacing the per-request hook
|
|
6
|
+
* (`AcoInitializer`) that used to push an already-resolved model into the container.
|
|
7
|
+
*
|
|
8
|
+
* No memoization: `ModelsFetcher` already caches the model list per request (`ModelCache` is a
|
|
9
|
+
* per-request `createMemoryCache()`). No `withoutAuthorization` either — the folder model is
|
|
10
|
+
* private, and `PrivateModelBuilder` sets `authorization: false`, which short-circuits
|
|
11
|
+
* `canAccessModel()` to true for every identity, so the wrapper the initializer used changed
|
|
12
|
+
* nothing.
|
|
13
|
+
*
|
|
14
|
+
* `GetModelUseCase` is an ordinary constructor dependency: this provider is only constructed when a
|
|
15
|
+
* consumer first awaits `get()`, during request handling — after the CMS has registered everything
|
|
16
|
+
* the use case needs. That timing is what forced the initializer's lazy `container.resolve()`.
|
|
17
|
+
*/
|
|
18
|
+
declare class FolderModelProviderImpl implements Abstraction.Interface {
|
|
19
|
+
private getModel;
|
|
20
|
+
constructor(getModel: GetModelUseCase.Interface);
|
|
21
|
+
get(): Promise<CmsModel>;
|
|
22
|
+
}
|
|
23
|
+
export declare const FolderModelProvider: typeof FolderModelProviderImpl & {
|
|
24
|
+
__abstraction: import("@webiny/di").Abstraction<import("~/domain/folder/abstractions.js").IFolderModelProvider>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
2
|
+
import { FolderModelProvider } from "../../domain/folder/abstractions.js";
|
|
3
|
+
import { FOLDER_MODEL_ID } from "../../domain/folder/folder.model.js";
|
|
4
|
+
class FolderModelProviderImpl {
|
|
5
|
+
constructor(getModel){
|
|
6
|
+
this.getModel = getModel;
|
|
7
|
+
}
|
|
8
|
+
async get() {
|
|
9
|
+
const result = await this.getModel.execute(FOLDER_MODEL_ID);
|
|
10
|
+
if (result.isFail()) throw result.error;
|
|
11
|
+
return result.value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const FolderModelProvider_FolderModelProvider = FolderModelProvider.createImplementation({
|
|
15
|
+
implementation: FolderModelProviderImpl,
|
|
16
|
+
dependencies: [
|
|
17
|
+
GetModelUseCase
|
|
18
|
+
]
|
|
19
|
+
});
|
|
20
|
+
export { FolderModelProvider_FolderModelProvider as FolderModelProvider };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=FolderModelProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/folder/FolderModelProvider.js","sources":["../../../src/features/folder/FolderModelProvider.ts"],"sourcesContent":["import type { CmsModel } from \"@webiny/api-headless-cms/types\";\nimport { GetModelUseCase } from \"@webiny/api-headless-cms/features/contentModel/GetModel/index.js\";\nimport { FolderModelProvider as Abstraction } from \"~/domain/folder/abstractions.js\";\nimport { FOLDER_MODEL_ID } from \"~/domain/folder/folder.model.js\";\n\n/**\n * Resolves the tenant's ACO folder model on demand, replacing the per-request hook\n * (`AcoInitializer`) that used to push an already-resolved model into the container.\n *\n * No memoization: `ModelsFetcher` already caches the model list per request (`ModelCache` is a\n * per-request `createMemoryCache()`). No `withoutAuthorization` either — the folder model is\n * private, and `PrivateModelBuilder` sets `authorization: false`, which short-circuits\n * `canAccessModel()` to true for every identity, so the wrapper the initializer used changed\n * nothing.\n *\n * `GetModelUseCase` is an ordinary constructor dependency: this provider is only constructed when a\n * consumer first awaits `get()`, during request handling — after the CMS has registered everything\n * the use case needs. That timing is what forced the initializer's lazy `container.resolve()`.\n */\nclass FolderModelProviderImpl implements Abstraction.Interface {\n constructor(private getModel: GetModelUseCase.Interface) {}\n\n async get(): Promise<CmsModel> {\n const result = await this.getModel.execute(FOLDER_MODEL_ID);\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n }\n}\n\nexport const FolderModelProvider = Abstraction.createImplementation({\n implementation: FolderModelProviderImpl,\n dependencies: [GetModelUseCase]\n});\n"],"names":["FolderModelProviderImpl","getModel","result","FOLDER_MODEL_ID","FolderModelProvider","Abstraction","GetModelUseCase"],"mappings":";;;AAmBA,MAAMA;IACF,YAAoBC,QAAmC,CAAE;aAArCA,QAAQ,GAARA;IAAsC;IAE1D,MAAM,MAAyB;QAC3B,MAAMC,SAAS,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAACC;QAC3C,IAAID,OAAO,MAAM,IACb,MAAMA,OAAO,KAAK;QAEtB,OAAOA,OAAO,KAAK;IACvB;AACJ;AAEO,MAAME,0CAAsBC,oBAAAA,oBAAgC,CAAC;IAChE,gBAAgBL;IAChB,cAAc;QAACM;KAAgB;AACnC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Result } from "@webiny/feature/api";
|
|
2
2
|
import { type GetAncestorsParams, GetAncestorsRepository as RepositoryAbstraction, type IGetAncestorsRepository } from "./abstractions.js";
|
|
3
3
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
4
|
-
import {
|
|
4
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
5
5
|
import type { Folder } from "../../../folder/folder.types.js";
|
|
6
6
|
declare class GetAncestorsRepositoryImpl implements IGetAncestorsRepository {
|
|
7
7
|
private listLatestEntries;
|
|
8
|
-
private
|
|
9
|
-
constructor(listLatestEntries: ListLatestEntriesUseCase.Interface,
|
|
8
|
+
private folderModelProvider;
|
|
9
|
+
constructor(listLatestEntries: ListLatestEntriesUseCase.Interface, folderModelProvider: FolderModelProvider.Interface);
|
|
10
10
|
execute(params: GetAncestorsParams): Promise<Result<Folder[], RepositoryAbstraction.Error>>;
|
|
11
11
|
}
|
|
12
12
|
export declare const GetAncestorsRepository: typeof GetAncestorsRepositoryImpl & {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { Result } from "@webiny/feature/api";
|
|
2
2
|
import { GetAncestorsRepository } from "./abstractions.js";
|
|
3
3
|
import { ListLatestEntriesUseCase } from "@webiny/api-headless-cms/features/contentEntry/ListEntries";
|
|
4
|
-
import {
|
|
4
|
+
import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
|
|
5
5
|
import { EntryToFolderMapper } from "../shared/EntryToFolderMapper.js";
|
|
6
6
|
import { FolderPersistenceError } from "../../../domain/folder/errors.js";
|
|
7
7
|
import { ROOT_FOLDER } from "../../../constants.js";
|
|
8
8
|
class GetAncestorsRepositoryImpl {
|
|
9
|
-
constructor(listLatestEntries,
|
|
9
|
+
constructor(listLatestEntries, folderModelProvider){
|
|
10
10
|
this.listLatestEntries = listLatestEntries;
|
|
11
|
-
this.
|
|
11
|
+
this.folderModelProvider = folderModelProvider;
|
|
12
12
|
}
|
|
13
13
|
async execute(params) {
|
|
14
|
+
const folderModel = await this.folderModelProvider.get();
|
|
14
15
|
const { folder } = params;
|
|
15
16
|
if (!folder) return Result.ok([]);
|
|
16
17
|
if (!folder.parentId) return Result.ok([
|
|
@@ -21,7 +22,7 @@ class GetAncestorsRepositoryImpl {
|
|
|
21
22
|
ROOT_FOLDER,
|
|
22
23
|
...parts.slice(0, index + 1)
|
|
23
24
|
].join("/"));
|
|
24
|
-
const result = await this.listLatestEntries.execute(
|
|
25
|
+
const result = await this.listLatestEntries.execute(folderModel, {
|
|
25
26
|
where: {
|
|
26
27
|
values: {
|
|
27
28
|
type: folder.type,
|
|
@@ -50,7 +51,7 @@ const GetAncestorsRepository_GetAncestorsRepository = GetAncestorsRepository.cre
|
|
|
50
51
|
implementation: GetAncestorsRepositoryImpl,
|
|
51
52
|
dependencies: [
|
|
52
53
|
ListLatestEntriesUseCase,
|
|
53
|
-
|
|
54
|
+
FolderModelProvider
|
|
54
55
|
]
|
|
55
56
|
});
|
|
56
57
|
export { GetAncestorsRepository_GetAncestorsRepository as GetAncestorsRepository };
|