@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.
Files changed (241) hide show
  1. package/AcoFeature.d.ts +5 -0
  2. package/AcoFeature.js +134 -0
  3. package/AcoFeature.js.map +1 -0
  4. package/AcoFolderSchemaFactory.d.ts +32 -0
  5. package/AcoFolderSchemaFactory.js +82 -0
  6. package/AcoFolderSchemaFactory.js.map +1 -0
  7. package/createAcoGraphQL.d.ts +8 -4
  8. package/createAcoGraphQL.js +56 -96
  9. package/createAcoGraphQL.js.map +1 -1
  10. package/domain/folder/abstractions.d.ts +12 -5
  11. package/domain/folder/abstractions.js +2 -2
  12. package/domain/folder/abstractions.js.map +1 -1
  13. package/domain/folder/folder.model.js +2 -1
  14. package/domain/folder/folder.model.js.map +1 -1
  15. package/exports/api/aco/flp.d.ts +1 -0
  16. package/exports/api/aco/flp.js +1 -0
  17. package/exports/api/aco/folder.d.ts +2 -1
  18. package/exports/api/aco/folder.js +1 -1
  19. package/features/ai/CreateFolderTool.d.ts +49 -0
  20. package/features/ai/CreateFolderTool.js +58 -0
  21. package/features/ai/CreateFolderTool.js.map +1 -0
  22. package/features/ai/CreateTeamTool.d.ts +48 -0
  23. package/features/ai/CreateTeamTool.js +56 -0
  24. package/features/ai/CreateTeamTool.js.map +1 -0
  25. package/features/ai/DeleteFolderTool.d.ts +48 -0
  26. package/features/ai/DeleteFolderTool.js +55 -0
  27. package/features/ai/DeleteFolderTool.js.map +1 -0
  28. package/features/ai/GrantFolderAccessTool.d.ts +77 -0
  29. package/features/ai/GrantFolderAccessTool.js +80 -0
  30. package/features/ai/GrantFolderAccessTool.js.map +1 -0
  31. package/features/ai/ListFoldersTool.d.ts +47 -0
  32. package/features/ai/ListFoldersTool.js +57 -0
  33. package/features/ai/ListFoldersTool.js.map +1 -0
  34. package/features/ai/ListRolesTool.d.ts +39 -0
  35. package/features/ai/ListRolesTool.js +48 -0
  36. package/features/ai/ListRolesTool.js.map +1 -0
  37. package/features/ai/ListTeamsTool.d.ts +39 -0
  38. package/features/ai/ListTeamsTool.js +48 -0
  39. package/features/ai/ListTeamsTool.js.map +1 -0
  40. package/features/ai/RevokeFolderAccessTool.d.ts +63 -0
  41. package/features/ai/RevokeFolderAccessTool.js +69 -0
  42. package/features/ai/RevokeFolderAccessTool.js.map +1 -0
  43. package/features/ai/assertTargetIsUsable.d.ts +10 -0
  44. package/features/ai/assertTargetIsUsable.js +14 -0
  45. package/features/ai/assertTargetIsUsable.js.map +1 -0
  46. package/features/ai/feature.d.ts +12 -0
  47. package/features/ai/feature.js +25 -0
  48. package/features/ai/feature.js.map +1 -0
  49. package/features/ai/index.d.ts +9 -0
  50. package/features/ai/index.js +9 -0
  51. package/features/ai/loadFolderPermissions.d.ts +16 -0
  52. package/features/ai/loadFolderPermissions.js +14 -0
  53. package/features/ai/loadFolderPermissions.js.map +1 -0
  54. package/features/cms/decorators/ListDeletedEntriesWithFlpDecorator.js +1 -0
  55. package/features/cms/decorators/ListDeletedEntriesWithFlpDecorator.js.map +1 -1
  56. package/features/cms/decorators/ListEntriesWithFlpDecorator.js +1 -0
  57. package/features/cms/decorators/ListEntriesWithFlpDecorator.js.map +1 -1
  58. package/features/cms/decorators/ListLatestEntriesWithFlpDecorator.js +1 -0
  59. package/features/cms/decorators/ListLatestEntriesWithFlpDecorator.js.map +1 -1
  60. package/features/cms/decorators/ListPublishedEntriesWithFlpDecorator.js +1 -0
  61. package/features/cms/decorators/ListPublishedEntriesWithFlpDecorator.js.map +1 -1
  62. package/features/cms/decorators/MoveEntryWithFlpDecorator.d.ts +1 -1
  63. package/features/flp/CreateFlp/CreateFlpUseCase.d.ts +3 -3
  64. package/features/flp/CreateFlp/CreateFlpUseCase.js +4 -4
  65. package/features/flp/CreateFlp/CreateFlpUseCase.js.map +1 -1
  66. package/features/flp/CreateFlp/feature.d.ts +1 -6
  67. package/features/flp/CreateFlp/feature.js +3 -2
  68. package/features/flp/CreateFlp/feature.js.map +1 -1
  69. package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.d.ts +8 -5
  70. package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.js +21 -14
  71. package/features/flp/CreateFlpOnFolderCreated/CreateFlpOnFolderCreatedHandler.js.map +1 -1
  72. package/features/flp/DeleteFlp/DeleteFlpUseCase.d.ts +3 -3
  73. package/features/flp/DeleteFlp/DeleteFlpUseCase.js +3 -3
  74. package/features/flp/DeleteFlp/DeleteFlpUseCase.js.map +1 -1
  75. package/features/flp/DeleteFlp/feature.d.ts +1 -6
  76. package/features/flp/DeleteFlp/feature.js +3 -2
  77. package/features/flp/DeleteFlp/feature.js.map +1 -1
  78. package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.d.ts +6 -5
  79. package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.js +16 -13
  80. package/features/flp/DeleteFlpOnFolderDeleted/DeleteFlpOnFolderDeletedHandler.js.map +1 -1
  81. package/features/flp/FolderLevelPermissions/FolderLevelPermissions.d.ts +3 -3
  82. package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js +6 -6
  83. package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js.map +1 -1
  84. package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.d.ts +25 -0
  85. package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.js +48 -0
  86. package/features/flp/FolderLevelPermissions/NoopFolderLevelPermissions.js.map +1 -0
  87. package/features/flp/FolderLevelPermissions/index.d.ts +1 -0
  88. package/features/flp/FolderLevelPermissions/index.js +1 -0
  89. package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.d.ts +13 -0
  90. package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.js +26 -0
  91. package/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.js.map +1 -0
  92. package/features/flp/GetFlp/feature.d.ts +1 -1
  93. package/features/flp/GetFlp/feature.js +3 -2
  94. package/features/flp/GetFlp/feature.js.map +1 -1
  95. package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.d.ts +13 -0
  96. package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.js +27 -0
  97. package/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.js.map +1 -0
  98. package/features/flp/ListFlps/feature.d.ts +1 -1
  99. package/features/flp/ListFlps/feature.js +3 -2
  100. package/features/flp/ListFlps/feature.js.map +1 -1
  101. package/features/flp/UpdateFlp/UpdateFlpUseCase.d.ts +15 -8
  102. package/features/flp/UpdateFlp/UpdateFlpUseCase.js +37 -42
  103. package/features/flp/UpdateFlp/UpdateFlpUseCase.js.map +1 -1
  104. package/features/flp/UpdateFlp/abstractions.d.ts +6 -2
  105. package/features/flp/UpdateFlp/abstractions.js.map +1 -1
  106. package/features/flp/UpdateFlp/feature.d.ts +1 -6
  107. package/features/flp/UpdateFlp/feature.js +7 -2
  108. package/features/flp/UpdateFlp/feature.js.map +1 -1
  109. package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.d.ts +8 -5
  110. package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js +21 -16
  111. package/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js.map +1 -1
  112. package/features/flp/shared/CodeFlpMerger.d.ts +26 -0
  113. package/features/flp/shared/CodeFlpMerger.js +20 -0
  114. package/features/flp/shared/CodeFlpMerger.js.map +1 -0
  115. package/features/flp/shared/CodeFlpPath.d.ts +15 -0
  116. package/features/flp/shared/CodeFlpPath.js +29 -0
  117. package/features/flp/shared/CodeFlpPath.js.map +1 -0
  118. package/features/flp/shared/CodeFlpTarget.d.ts +10 -0
  119. package/features/flp/shared/CodeFlpTarget.js +26 -0
  120. package/features/flp/shared/CodeFlpTarget.js.map +1 -0
  121. package/features/flp/shared/CodeFlpsProvider.d.ts +14 -0
  122. package/features/flp/shared/CodeFlpsProvider.js +33 -0
  123. package/features/flp/shared/CodeFlpsProvider.js.map +1 -0
  124. package/features/flp/shared/abstractions.d.ts +77 -0
  125. package/features/flp/shared/abstractions.js +19 -0
  126. package/features/flp/shared/abstractions.js.map +1 -0
  127. package/features/flp/shared/feature.d.ts +5 -0
  128. package/features/flp/shared/feature.js +17 -0
  129. package/features/flp/shared/feature.js.map +1 -0
  130. package/features/flp/shared/index.d.ts +4 -0
  131. package/features/flp/shared/index.js +4 -0
  132. package/features/folder/CreateFolder/CreateFolderRepository.d.ts +3 -3
  133. package/features/folder/CreateFolder/CreateFolderRepository.js +10 -7
  134. package/features/folder/CreateFolder/CreateFolderRepository.js.map +1 -1
  135. package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.d.ts +9 -1
  136. package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.js +20 -3
  137. package/features/folder/CreateFolder/decorators/CreateFolderWithFolderLevelPermissions.js.map +1 -1
  138. package/features/folder/DeleteFolder/DeleteFolderRepository.d.ts +3 -3
  139. package/features/folder/DeleteFolder/DeleteFolderRepository.js +6 -5
  140. package/features/folder/DeleteFolder/DeleteFolderRepository.js.map +1 -1
  141. package/features/folder/DeleteFolder/decorators/DeleteFolderWithFolderLevelPermissions.d.ts +1 -1
  142. package/features/folder/EnsureFolderIsEmpty/EnsureFolderIsEmpty.js +4 -0
  143. package/features/folder/EnsureFolderIsEmpty/EnsureFolderIsEmpty.js.map +1 -1
  144. package/features/folder/EnsureHcmsFolderIsEmptyOnDelete/ModelFolderBeforeDeleteHandler.js +4 -0
  145. package/features/folder/EnsureHcmsFolderIsEmptyOnDelete/ModelFolderBeforeDeleteHandler.js.map +1 -1
  146. package/features/folder/FolderModelProvider.d.ts +26 -0
  147. package/features/folder/FolderModelProvider.js +22 -0
  148. package/features/folder/FolderModelProvider.js.map +1 -0
  149. package/features/folder/GetAncestors/GetAncestorsRepository.d.ts +3 -3
  150. package/features/folder/GetAncestors/GetAncestorsRepository.js +6 -5
  151. package/features/folder/GetAncestors/GetAncestorsRepository.js.map +1 -1
  152. package/features/folder/GetFolder/GetFolderRepository.d.ts +3 -3
  153. package/features/folder/GetFolder/GetFolderRepository.js +6 -5
  154. package/features/folder/GetFolder/GetFolderRepository.js.map +1 -1
  155. package/features/folder/GetFolder/decorators/GetFolderWithFolderLevelPermissions.d.ts +8 -8
  156. package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.d.ts +3 -3
  157. package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js +10 -8
  158. package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js.map +1 -1
  159. package/features/folder/ListFolders/ListFoldersRepository.d.ts +3 -3
  160. package/features/folder/ListFolders/ListFoldersRepository.js +8 -7
  161. package/features/folder/ListFolders/ListFoldersRepository.js.map +1 -1
  162. package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.d.ts +11 -0
  163. package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.js +38 -0
  164. package/features/folder/NotifyFolderChange/NotifyFolderChangeUseCase.js.map +1 -0
  165. package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.d.ts +12 -0
  166. package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.js +24 -0
  167. package/features/folder/NotifyFolderChange/NotifyOnFolderDeletedHandler.js.map +1 -0
  168. package/features/folder/NotifyFolderChange/abstractions.d.ts +28 -0
  169. package/features/folder/NotifyFolderChange/abstractions.js +8 -0
  170. package/features/folder/NotifyFolderChange/abstractions.js.map +1 -0
  171. package/features/folder/NotifyFolderChange/feature.d.ts +9 -0
  172. package/features/folder/NotifyFolderChange/feature.js +13 -0
  173. package/features/folder/NotifyFolderChange/feature.js.map +1 -0
  174. package/features/folder/NotifyFolderChange/index.d.ts +2 -0
  175. package/features/folder/NotifyFolderChange/index.js +2 -0
  176. package/features/folder/UpdateFolder/UpdateFolderRepository.d.ts +3 -3
  177. package/features/folder/UpdateFolder/UpdateFolderRepository.js +11 -8
  178. package/features/folder/UpdateFolder/UpdateFolderRepository.js.map +1 -1
  179. package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.d.ts +14 -1
  180. package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js +52 -4
  181. package/features/folder/UpdateFolder/decorators/UpdateFolderWithFolderLevelPermissions.js.map +1 -1
  182. package/features/folder/shared/abstractions.d.ts +14 -0
  183. package/features/folder/shared/abstractions.js +4 -1
  184. package/features/folder/shared/abstractions.js.map +1 -1
  185. package/filter/filter.gql.d.ts +2 -3
  186. package/filter/filter.gql.js +61 -27
  187. package/filter/filter.gql.js.map +1 -1
  188. package/filter/filter.model.js +2 -1
  189. package/filter/filter.model.js.map +1 -1
  190. package/filter/filter.so.d.ts +8 -2
  191. package/filter/filter.so.js +21 -9
  192. package/filter/filter.so.js.map +1 -1
  193. package/flp/flp.types.d.ts +6 -1
  194. package/flp/index.d.ts +0 -1
  195. package/flp/index.js +0 -1
  196. package/flp/tasks/createFlp.task.d.ts +12 -5
  197. package/flp/tasks/createFlp.task.js +32 -15
  198. package/flp/tasks/createFlp.task.js.map +1 -1
  199. package/flp/tasks/deleteFlp.task.d.ts +10 -5
  200. package/flp/tasks/deleteFlp.task.js +22 -13
  201. package/flp/tasks/deleteFlp.task.js.map +1 -1
  202. package/flp/tasks/index.d.ts +0 -1
  203. package/flp/tasks/index.js +1 -14
  204. package/flp/tasks/index.js.map +1 -1
  205. package/flp/tasks/syncFlp.task.d.ts +10 -5
  206. package/flp/tasks/syncFlp.task.js +34 -13
  207. package/flp/tasks/syncFlp.task.js.map +1 -1
  208. package/flp/tasks/updateFlp.task.d.ts +12 -5
  209. package/flp/tasks/updateFlp.task.js +40 -19
  210. package/flp/tasks/updateFlp.task.js.map +1 -1
  211. package/folder/createFolderTypeDefs.js +4 -1
  212. package/folder/createFolderTypeDefs.js.map +1 -1
  213. package/folder/folder.gql.d.ts +1 -1
  214. package/folder/folder.gql.js +10 -4
  215. package/folder/folder.gql.js.map +1 -1
  216. package/index.d.ts +1 -6
  217. package/index.js +1 -11
  218. package/package.json +25 -26
  219. package/types.d.ts +1 -2
  220. package/types.js.map +1 -1
  221. package/utils/createOperationsWrapper.d.ts +5 -2
  222. package/utils/createOperationsWrapper.js +5 -5
  223. package/utils/createOperationsWrapper.js.map +1 -1
  224. package/utils/decorators/CmsEntriesCrudDecorators.js +9 -5
  225. package/utils/decorators/CmsEntriesCrudDecorators.js.map +1 -1
  226. package/utils/resolve.d.ts +2 -2
  227. package/utils/resolve.js +1 -1
  228. package/utils/resolve.js.map +1 -1
  229. package/createAcoContext.d.ts +0 -9
  230. package/createAcoContext.js +0 -109
  231. package/createAcoContext.js.map +0 -1
  232. package/createAcoStorageOperations.d.ts +0 -12
  233. package/createAcoStorageOperations.js +0 -9
  234. package/createAcoStorageOperations.js.map +0 -1
  235. package/createAcoTasks.d.ts +0 -1
  236. package/createAcoTasks.js +0 -14
  237. package/createAcoTasks.js.map +0 -1
  238. package/flp/flp.so.d.ts +0 -20
  239. package/flp/flp.so.js +0 -183
  240. package/flp/flp.so.js.map +0 -1
  241. package/index.js.map +0 -1
@@ -0,0 +1,26 @@
1
+ import { GetFlpUseCase } from "../abstractions.js";
2
+ import { CodeFlpMerger, CodeFlpsProvider } from "../../shared/index.js";
3
+ class GetFlpWithCodeFlpsImpl {
4
+ constructor(codeFlpsProvider, decoratee){
5
+ this.codeFlpsProvider = codeFlpsProvider;
6
+ this.decoratee = decoratee;
7
+ }
8
+ async execute(id) {
9
+ const flp = await this.decoratee.execute(id);
10
+ if (!flp) return null;
11
+ const codePermissions = await this.codeFlpsProvider.getPermissions({
12
+ type: flp.type,
13
+ path: flp.path
14
+ });
15
+ return CodeFlpMerger.merge(flp, codePermissions);
16
+ }
17
+ }
18
+ const GetFlpWithCodeFlps = GetFlpUseCase.createDecorator({
19
+ decorator: GetFlpWithCodeFlpsImpl,
20
+ dependencies: [
21
+ CodeFlpsProvider
22
+ ]
23
+ });
24
+ export { GetFlpWithCodeFlps };
25
+
26
+ //# sourceMappingURL=GetFlpWithCodeFlps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/flp/GetFlp/decorators/GetFlpWithCodeFlps.js","sources":["../../../../../src/features/flp/GetFlp/decorators/GetFlpWithCodeFlps.ts"],"sourcesContent":["import { GetFlpUseCase } from \"../abstractions.js\";\nimport { CodeFlpMerger, CodeFlpsProvider } from \"~/features/flp/shared/index.js\";\nimport type { FolderLevelPermission } from \"~/flp/flp.types.js\";\n\nclass GetFlpWithCodeFlpsImpl implements GetFlpUseCase.Interface {\n constructor(\n private codeFlpsProvider: CodeFlpsProvider.Interface,\n private decoratee: GetFlpUseCase.Interface\n ) {}\n\n async execute(id: string): Promise<FolderLevelPermission | null> {\n const flp = await this.decoratee.execute(id);\n\n if (!flp) {\n return null;\n }\n\n const codePermissions = await this.codeFlpsProvider.getPermissions({\n type: flp.type,\n path: flp.path\n });\n\n return CodeFlpMerger.merge(flp, codePermissions);\n }\n}\n\nexport const GetFlpWithCodeFlps = GetFlpUseCase.createDecorator({\n decorator: GetFlpWithCodeFlpsImpl,\n dependencies: [CodeFlpsProvider]\n});\n"],"names":["GetFlpWithCodeFlpsImpl","codeFlpsProvider","decoratee","id","flp","codePermissions","CodeFlpMerger","GetFlpWithCodeFlps","GetFlpUseCase","CodeFlpsProvider"],"mappings":";;AAIA,MAAMA;IACF,YACYC,gBAA4C,EAC5CC,SAAkC,CAC5C;aAFUD,gBAAgB,GAAhBA;aACAC,SAAS,GAATA;IACT;IAEH,MAAM,QAAQC,EAAU,EAAyC;QAC7D,MAAMC,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAACD;QAEzC,IAAI,CAACC,KACD,OAAO;QAGX,MAAMC,kBAAkB,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC;YAC/D,MAAMD,IAAI,IAAI;YACd,MAAMA,IAAI,IAAI;QAClB;QAEA,OAAOE,cAAc,KAAK,CAACF,KAAKC;IACpC;AACJ;AAEO,MAAME,qBAAqBC,cAAc,eAAe,CAAC;IAC5D,WAAWR;IACX,cAAc;QAACS;KAAiB;AACpC"}
@@ -1,4 +1,4 @@
1
1
  export declare const GetFlpFeature: {
2
2
  name: string;
3
- register(container: import("@webiny/di").Container, context: import("~/types.js").AcoFolderLevelPermissionsCrud): void;
3
+ register(container: import("@webiny/di").Container): void;
4
4
  };
@@ -1,10 +1,11 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
2
  import { GetFlpUseCase } from "./GetFlpUseCase.js";
3
3
  import { GetFlpUseCase as external_abstractions_js_GetFlpUseCase } from "./abstractions.js";
4
+ import { AcoFlpCrud } from "../../folder/shared/abstractions.js";
4
5
  const GetFlpFeature = createFeature({
5
6
  name: "GetFlpFeature",
6
- register (container, context) {
7
- container.registerFactory(external_abstractions_js_GetFlpUseCase, ()=>new GetFlpUseCase(context.get));
7
+ register (container) {
8
+ container.registerFactory(external_abstractions_js_GetFlpUseCase, ()=>new GetFlpUseCase(container.resolve(AcoFlpCrud).get));
8
9
  }
9
10
  });
10
11
  export { GetFlpFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"features/flp/GetFlp/feature.js","sources":["../../../../src/features/flp/GetFlp/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GetFlpUseCase } from \"./GetFlpUseCase.js\";\nimport { GetFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport type { AcoContext } from \"~/types.js\";\n\nexport const GetFlpFeature = createFeature<AcoContext[\"aco\"][\"flp\"]>({\n name: \"GetFlpFeature\",\n register(container, context) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new GetFlpUseCase(context.get);\n });\n }\n});\n"],"names":["GetFlpFeature","createFeature","container","context","UseCaseAbstraction","GetFlpUseCase"],"mappings":";;;AAKO,MAAMA,gBAAgBC,cAAwC;IACjE,MAAM;IACN,UAASC,SAAS,EAAEC,OAAO;QACvBD,UAAU,eAAe,CAACE,wCAAoB,IACnC,IAAIC,cAAcF,QAAQ,GAAG;IAE5C;AACJ"}
1
+ {"version":3,"file":"features/flp/GetFlp/feature.js","sources":["../../../../src/features/flp/GetFlp/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GetFlpUseCase } from \"./GetFlpUseCase.js\";\nimport { GetFlpUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\n\nexport const GetFlpFeature = createFeature({\n name: \"GetFlpFeature\",\n register(container) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new GetFlpUseCase(container.resolve(AcoFlpCrud).get);\n });\n }\n});\n"],"names":["GetFlpFeature","createFeature","container","UseCaseAbstraction","GetFlpUseCase","AcoFlpCrud"],"mappings":";;;;AAKO,MAAMA,gBAAgBC,cAAc;IACvC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,eAAe,CAACC,wCAAoB,IACnC,IAAIC,cAAcF,UAAU,OAAO,CAACG,YAAY,GAAG;IAElE;AACJ"}
@@ -0,0 +1,13 @@
1
+ import { ListFlpsUseCase } from "../abstractions.js";
2
+ import { CodeFlpsProvider } from "../../../../features/flp/shared/index.js";
3
+ import type { FolderLevelPermission, ListFlpsParams } from "../../../../flp/flp.types.js";
4
+ declare class ListFlpsWithCodeFlpsImpl implements ListFlpsUseCase.Interface {
5
+ private codeFlpsProvider;
6
+ private decoratee;
7
+ constructor(codeFlpsProvider: CodeFlpsProvider.Interface, decoratee: ListFlpsUseCase.Interface);
8
+ execute(params: ListFlpsParams): Promise<FolderLevelPermission[]>;
9
+ }
10
+ export declare const ListFlpsWithCodeFlps: typeof ListFlpsWithCodeFlpsImpl & {
11
+ __abstraction: import("@webiny/di").Abstraction<import("../abstractions.js").IListFlps>;
12
+ };
13
+ export {};
@@ -0,0 +1,27 @@
1
+ import { ListFlpsUseCase } from "../abstractions.js";
2
+ import { CodeFlpMerger, CodeFlpsProvider } from "../../shared/index.js";
3
+ class ListFlpsWithCodeFlpsImpl {
4
+ constructor(codeFlpsProvider, decoratee){
5
+ this.codeFlpsProvider = codeFlpsProvider;
6
+ this.decoratee = decoratee;
7
+ }
8
+ async execute(params) {
9
+ const flps = await this.decoratee.execute(params);
10
+ return Promise.all(flps.map(async (flp)=>{
11
+ const codePermissions = await this.codeFlpsProvider.getPermissions({
12
+ type: flp.type,
13
+ path: flp.path
14
+ });
15
+ return CodeFlpMerger.merge(flp, codePermissions);
16
+ }));
17
+ }
18
+ }
19
+ const ListFlpsWithCodeFlps = ListFlpsUseCase.createDecorator({
20
+ decorator: ListFlpsWithCodeFlpsImpl,
21
+ dependencies: [
22
+ CodeFlpsProvider
23
+ ]
24
+ });
25
+ export { ListFlpsWithCodeFlps };
26
+
27
+ //# sourceMappingURL=ListFlpsWithCodeFlps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.js","sources":["../../../../../src/features/flp/ListFlps/decorators/ListFlpsWithCodeFlps.ts"],"sourcesContent":["import { ListFlpsUseCase } from \"../abstractions.js\";\nimport { CodeFlpMerger, CodeFlpsProvider } from \"~/features/flp/shared/index.js\";\nimport type { FolderLevelPermission, ListFlpsParams } from \"~/flp/flp.types.js\";\n\nclass ListFlpsWithCodeFlpsImpl implements ListFlpsUseCase.Interface {\n constructor(\n private codeFlpsProvider: CodeFlpsProvider.Interface,\n private decoratee: ListFlpsUseCase.Interface\n ) {}\n\n async execute(params: ListFlpsParams): Promise<FolderLevelPermission[]> {\n const flps = await this.decoratee.execute(params);\n\n return Promise.all(\n flps.map(async flp => {\n const codePermissions = await this.codeFlpsProvider.getPermissions({\n type: flp.type,\n path: flp.path\n });\n\n return CodeFlpMerger.merge(flp, codePermissions);\n })\n );\n }\n}\n\nexport const ListFlpsWithCodeFlps = ListFlpsUseCase.createDecorator({\n decorator: ListFlpsWithCodeFlpsImpl,\n dependencies: [CodeFlpsProvider]\n});\n"],"names":["ListFlpsWithCodeFlpsImpl","codeFlpsProvider","decoratee","params","flps","Promise","flp","codePermissions","CodeFlpMerger","ListFlpsWithCodeFlps","ListFlpsUseCase","CodeFlpsProvider"],"mappings":";;AAIA,MAAMA;IACF,YACYC,gBAA4C,EAC5CC,SAAoC,CAC9C;aAFUD,gBAAgB,GAAhBA;aACAC,SAAS,GAATA;IACT;IAEH,MAAM,QAAQC,MAAsB,EAAoC;QACpE,MAAMC,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAACD;QAE1C,OAAOE,QAAQ,GAAG,CACdD,KAAK,GAAG,CAAC,OAAME;YACX,MAAMC,kBAAkB,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC;gBAC/D,MAAMD,IAAI,IAAI;gBACd,MAAMA,IAAI,IAAI;YAClB;YAEA,OAAOE,cAAc,KAAK,CAACF,KAAKC;QACpC;IAER;AACJ;AAEO,MAAME,uBAAuBC,gBAAgB,eAAe,CAAC;IAChE,WAAWV;IACX,cAAc;QAACW;KAAiB;AACpC"}
@@ -1,4 +1,4 @@
1
1
  export declare const ListFlpsFeature: {
2
2
  name: string;
3
- register(container: import("@webiny/di").Container, context: import("~/types.js").AcoFolderLevelPermissionsCrud): void;
3
+ register(container: import("@webiny/di").Container): void;
4
4
  };
@@ -1,10 +1,11 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
2
  import { ListFlpsUseCase } from "./ListFlpsUseCase.js";
3
3
  import { ListFlpsUseCase as external_abstractions_js_ListFlpsUseCase } from "./abstractions.js";
4
+ import { AcoFlpCrud } from "../../folder/shared/abstractions.js";
4
5
  const ListFlpsFeature = createFeature({
5
6
  name: "ListFlpsFeature",
6
- register (container, context) {
7
- container.registerFactory(external_abstractions_js_ListFlpsUseCase, ()=>new ListFlpsUseCase(context.list));
7
+ register (container) {
8
+ container.registerFactory(external_abstractions_js_ListFlpsUseCase, ()=>new ListFlpsUseCase(container.resolve(AcoFlpCrud).list));
8
9
  }
9
10
  });
10
11
  export { ListFlpsFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"features/flp/ListFlps/feature.js","sources":["../../../../src/features/flp/ListFlps/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { ListFlpsUseCase } from \"./ListFlpsUseCase.js\";\nimport { ListFlpsUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport type { AcoContext } from \"~/types.js\";\n\nexport const ListFlpsFeature = createFeature<AcoContext[\"aco\"][\"flp\"]>({\n name: \"ListFlpsFeature\",\n register(container, context) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new ListFlpsUseCase(context.list);\n });\n }\n});\n"],"names":["ListFlpsFeature","createFeature","container","context","UseCaseAbstraction","ListFlpsUseCase"],"mappings":";;;AAKO,MAAMA,kBAAkBC,cAAwC;IACnE,MAAM;IACN,UAASC,SAAS,EAAEC,OAAO;QACvBD,UAAU,eAAe,CAACE,0CAAoB,IACnC,IAAIC,gBAAgBF,QAAQ,IAAI;IAE/C;AACJ"}
1
+ {"version":3,"file":"features/flp/ListFlps/feature.js","sources":["../../../../src/features/flp/ListFlps/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { ListFlpsUseCase } from \"./ListFlpsUseCase.js\";\nimport { ListFlpsUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { AcoFlpCrud } from \"~/features/folder/shared/abstractions.js\";\n\nexport const ListFlpsFeature = createFeature({\n name: \"ListFlpsFeature\",\n register(container) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new ListFlpsUseCase(container.resolve(AcoFlpCrud).list);\n });\n }\n});\n"],"names":["ListFlpsFeature","createFeature","container","UseCaseAbstraction","ListFlpsUseCase","AcoFlpCrud"],"mappings":";;;;AAKO,MAAMA,kBAAkBC,cAAc;IACzC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,eAAe,CAACC,0CAAoB,IACnC,IAAIC,gBAAgBF,UAAU,OAAO,CAACG,YAAY,IAAI;IAErE;AACJ"}
@@ -1,19 +1,26 @@
1
1
  import type { UpdateFlpParams, UpdateFlpUseCase as UseCaseAbstraction } from "./abstractions.js";
2
- import type { AcoContext } from "../../../types.js";
2
+ import type { AcoFlpCrud } from "../../../features/folder/shared/abstractions.js";
3
+ import type { ListFoldersUseCase } from "../../../features/folder/ListFolders/index.js";
4
+ import type { FolderModelProvider } from "../../../domain/folder/abstractions.js";
5
+ import type { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js";
6
+ import type { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
3
7
  export declare class UpdateFlpUseCase implements UseCaseAbstraction.Interface {
4
- private context;
8
+ private flpCrud;
9
+ private listFoldersUseCase;
10
+ private folderModelProvider;
11
+ private updateEntryUseCase;
12
+ private identityContext;
5
13
  private isCloseToTimeout?;
6
14
  private handleTimeout?;
7
- private readonly queued;
15
+ private readonly completed;
8
16
  private readonly flpsToUpdate;
9
- constructor(context: AcoContext);
17
+ private timedOut;
18
+ private completedThisRun;
19
+ constructor(flpCrud: AcoFlpCrud.Interface, listFoldersUseCase: ListFoldersUseCase.Interface, folderModelProvider: FolderModelProvider.Interface, updateEntryUseCase: UpdateEntryUseCase.Interface, identityContext: IdentityContext.Interface);
10
20
  execute(params: UpdateFlpParams): Promise<void>;
11
21
  private collectBranchForUpdate;
22
+ private stopForTimeout;
12
23
  private executeBatchUpdate;
13
- private getQueuedList;
14
- private setQueued;
15
- private isQueued;
16
- private clearQueuedList;
17
24
  private listDirectChildren;
18
25
  private getFlp;
19
26
  }
@@ -1,46 +1,48 @@
1
1
  import { WebinyError } from "@webiny/error";
2
2
  import { Path } from "../../../utils/Path.js";
3
3
  import { Permissions, ROOT_FOLDER } from "@webiny/shared-aco";
4
- import { ListFoldersUseCase } from "../../folder/ListFolders/index.js";
5
- import { FolderModel } from "../../../domain/folder/abstractions.js";
6
4
  import { EntryId } from "@webiny/api-headless-cms/exports/api/cms/entry.js";
7
5
  class UpdateFlpUseCase {
8
- constructor(context){
9
- this.queued = new Set();
6
+ constructor(flpCrud, listFoldersUseCase, folderModelProvider, updateEntryUseCase, identityContext){
7
+ this.flpCrud = flpCrud;
8
+ this.listFoldersUseCase = listFoldersUseCase;
9
+ this.folderModelProvider = folderModelProvider;
10
+ this.updateEntryUseCase = updateEntryUseCase;
11
+ this.identityContext = identityContext;
12
+ this.completed = new Set();
10
13
  this.flpsToUpdate = new Map();
11
- this.context = context;
14
+ this.timedOut = false;
15
+ this.completedThisRun = 0;
12
16
  }
13
17
  async execute(params) {
14
18
  this.isCloseToTimeout = params.isCloseToTimeout;
15
19
  this.handleTimeout = params.handleTimeout;
16
- if (params.queued) params.queued.forEach((id)=>this.queued.add(id));
20
+ this.completed.clear();
21
+ this.timedOut = false;
22
+ this.completedThisRun = 0;
23
+ if (params.completed) params.completed.forEach((id)=>this.completed.add(id));
17
24
  try {
18
25
  const { folder } = params;
19
26
  if (!folder) throw new WebinyError("Missing `folder`, I can't update the FLP record.", "ERROR_UPDATING_FLP_USE_CASE_FOLDER_NOT_PROVIDED", {
20
27
  folder
21
28
  });
22
29
  const flp = await this.getFlp(folder);
23
- const parentFlp = folder.parentId ? await this.context.aco.flp.get(folder.parentId) : null;
30
+ const parentFlp = folder.parentId ? await this.flpCrud.get(folder.parentId) : null;
24
31
  this.flpsToUpdate.set(folder.id, {
25
32
  slug: folder.slug,
26
33
  parentId: folder.parentId ?? ROOT_FOLDER,
27
34
  path: Path.create(folder.slug, parentFlp?.path),
28
35
  permissions: Permissions.create(folder.permissions, parentFlp)
29
36
  });
30
- this.setQueued(flp.id);
31
37
  const directChildren = await this.listDirectChildren(flp);
32
38
  for (const child of directChildren){
33
- if (this.isCloseToTimeout?.()) {
34
- await this.executeBatchUpdate();
35
- this.handleTimeout?.(this.getQueuedList());
36
- return;
37
- }
38
39
  await this.collectBranchForUpdate(child, flp);
40
+ if (this.timedOut) return;
39
41
  }
40
42
  await this.executeBatchUpdate();
41
43
  } catch (error) {
42
44
  this.flpsToUpdate.clear();
43
- this.queued.clear();
45
+ this.completed.clear();
44
46
  throw WebinyError.from(error, {
45
47
  message: "Error while updating FLP",
46
48
  code: "ERROR_UPDATING_FLP_USE_CASE"
@@ -48,7 +50,8 @@ class UpdateFlpUseCase {
48
50
  }
49
51
  }
50
52
  async collectBranchForUpdate(flp, parentFlp) {
51
- if (this.isQueued(flp.id)) return;
53
+ if (this.completed.has(flp.id)) return;
54
+ if (this.isCloseToTimeout?.()) return void await this.stopForTimeout();
52
55
  const parentFlpData = this.flpsToUpdate.get(parentFlp.id);
53
56
  const currentParentFlp = {
54
57
  ...parentFlp,
@@ -62,18 +65,24 @@ class UpdateFlpUseCase {
62
65
  path: Path.create(flp.slug, currentParentFlp.path),
63
66
  permissions: Permissions.create(flp.permissions, currentParentFlp)
64
67
  });
65
- this.setQueued(flp.id);
66
68
  const children = await this.listDirectChildren(flp);
67
69
  for (const child of children){
68
- if (this.isCloseToTimeout?.()) {
69
- await this.executeBatchUpdate();
70
- this.handleTimeout?.(this.getQueuedList());
71
- return;
72
- }
73
70
  await this.collectBranchForUpdate(child, flp);
71
+ if (this.timedOut) return;
74
72
  }
73
+ for (const child of children)this.completed.delete(child.id);
74
+ this.completed.add(flp.id);
75
+ this.completedThisRun++;
76
+ }
77
+ async stopForTimeout() {
78
+ this.timedOut = true;
79
+ await this.executeBatchUpdate();
80
+ if (0 === this.completedThisRun) throw new WebinyError("The FLP update ran out of time before finishing any folder, so continuing would repeat the same work.", "UPDATE_FLP_NO_PROGRESS");
81
+ const completed = Array.from(this.completed);
82
+ this.handleTimeout?.(completed);
75
83
  }
76
84
  async executeBatchUpdate() {
85
+ const folderModel = await this.folderModelProvider.get();
77
86
  try {
78
87
  const items = Array.from(this.flpsToUpdate.entries()).map(([id, { slug, parentId, path, permissions }])=>({
79
88
  id,
@@ -84,16 +93,16 @@ class UpdateFlpUseCase {
84
93
  permissions
85
94
  }
86
95
  }));
87
- await this.context.aco.flp.batchUpdate(items);
88
- const folderModel = this.context.container.resolve(FolderModel);
96
+ await this.flpCrud.batchUpdate(items);
89
97
  for (const item of items){
90
98
  const { id, data } = item;
91
99
  const entryId = EntryId.from(id);
92
- await this.context.cms.updateEntry(folderModel, entryId.toString(), {
100
+ const updateResult = await this.updateEntryUseCase.execute(folderModel, entryId.toString(), {
93
101
  values: {
94
102
  path: data.path
95
103
  }
96
104
  });
105
+ if (updateResult.isFail()) throw updateResult.error;
97
106
  }
98
107
  } catch (error) {
99
108
  throw WebinyError.from(error, {
@@ -105,24 +114,10 @@ class UpdateFlpUseCase {
105
114
  });
106
115
  } finally{
107
116
  this.flpsToUpdate.clear();
108
- this.clearQueuedList();
109
117
  }
110
118
  }
111
- getQueuedList() {
112
- return Array.from(this.queued);
113
- }
114
- setQueued(id) {
115
- this.queued.add(id);
116
- }
117
- isQueued(id) {
118
- return this.queued.has(id);
119
- }
120
- clearQueuedList() {
121
- this.queued.clear();
122
- }
123
119
  async listDirectChildren(flp) {
124
- const listFolders = this.context.container.resolve(ListFoldersUseCase);
125
- const result = await this.context.security.withoutAuthorization(()=>listFolders.execute({
120
+ const result = await this.identityContext.withoutAuthorization(()=>this.listFoldersUseCase.execute({
126
121
  where: {
127
122
  type: flp.type,
128
123
  parentId: flp.id
@@ -132,10 +127,10 @@ class UpdateFlpUseCase {
132
127
  return await Promise.all(result.value.folders.map((folder)=>this.getFlp(folder)));
133
128
  }
134
129
  async getFlp({ id, type, parentId, slug, permissions }) {
135
- const flp = await this.context.aco.flp.get(id);
130
+ const flp = await this.flpCrud.get(id);
136
131
  if (!flp) {
137
- const parentFlp = parentId ? await this.context.aco.flp.get(parentId) : null;
138
- return await this.context.aco.flp.create({
132
+ const parentFlp = parentId ? await this.flpCrud.get(parentId) : null;
133
+ return await this.flpCrud.create({
139
134
  id,
140
135
  type,
141
136
  slug,
@@ -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 { AcoContext, Folder, FolderLevelPermission, FolderPermission } from \"~/types.js\";\nimport { ListFoldersUseCase } from \"~/features/folder/ListFolders/index.js\";\nimport { FolderModel } from \"~/domain/folder/abstractions.js\";\nimport { EntryId } from \"@webiny/api-headless-cms/exports/api/cms/entry.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 context: AcoContext;\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(context: AcoContext) {\n this.context = context;\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\n ? await this.context.aco.flp.get(folder.parentId)\n : 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.context.aco.flp.batchUpdate(items);\n\n // Update all folders with the new path\n const folderModel = this.context.container.resolve(FolderModel);\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 await this.context.cms.updateEntry(folderModel, entryId.toString(), {\n values: {\n path: data.path\n }\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 listFolders = this.context.container.resolve(ListFoldersUseCase);\n\n const result = await this.context.security.withoutAuthorization(() => {\n return listFolders.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.context.aco.flp.get(id);\n\n if (!flp) {\n const parentFlp = parentId ? await this.context.aco.flp.get(parentId) : null;\n\n return await this.context.aco.flp.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","context","Set","Map","params","id","folder","WebinyError","flp","parentFlp","ROOT_FOLDER","Path","Permissions","directChildren","child","error","parentFlpData","currentParentFlp","children","items","Array","slug","parentId","path","permissions","folderModel","FolderModel","item","data","entryId","EntryId","listFolders","ListFoldersUseCase","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 /*\n * Folders whose whole subtree has been written, carried across task runs as `completed` so a\n * continued run skips them. A folder is added only after all of its descendants are written: one\n * entered but not finished when time ran out has to be walked again, or the rest of its subtree\n * would never be updated.\n *\n * Only the topmost finished folders are kept. When a folder completes, its children leave the\n * set, since skipping the folder already skips them. The set travels in the task input on every\n * continuation, and listing every finished folder would outgrow it on exactly the large trees\n * that need continuing.\n */\n private readonly completed: Set<string> = new Set();\n private readonly flpsToUpdate: Map<string, FlpUpdateData> = new Map();\n private timedOut = false;\n // How many folders this run finished, so a run that finished none can refuse to hand over.\n private completedThisRun = 0;\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 // Fresh per run, so an instance that ever gets reused does not carry the last run's state.\n this.completed.clear();\n this.timedOut = false;\n this.completedThisRun = 0;\n\n if (params.completed) {\n params.completed.forEach(id => this.completed.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 // Get direct children and process each branch completely\n const directChildren = await this.listDirectChildren(flp);\n\n for (const child of directChildren) {\n await this.collectBranchForUpdate(child, flp);\n if (this.timedOut) {\n return;\n }\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.completed.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.completed.has(flp.id)) {\n return;\n }\n\n if (this.isCloseToTimeout?.()) {\n await this.stopForTimeout();\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 // 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 // Pass the current FLP as the parent for the child\n await this.collectBranchForUpdate(child, flp);\n if (this.timedOut) {\n return;\n }\n }\n\n // Only now is everything below this folder collected.\n for (const child of children) {\n this.completed.delete(child.id);\n }\n this.completed.add(flp.id);\n this.completedThisRun++;\n }\n\n /*\n * Writes what has been collected and hands over to a continued run. Every level of the walk\n * checks `timedOut` and stops, rather than carrying on with its remaining children.\n *\n * A run that finished no folder would hand the next run the same input, which would do the same\n * work and hand over again, forever. That fails the task instead.\n */\n private async stopForTimeout(): Promise<void> {\n this.timedOut = true;\n await this.executeBatchUpdate();\n\n if (this.completedThisRun === 0) {\n throw new WebinyError(\n \"The FLP update ran out of time before finishing any folder, so continuing would repeat the same work.\",\n \"UPDATE_FLP_NO_PROGRESS\"\n );\n }\n\n const completed = Array.from(this.completed);\n this.handleTimeout?.(completed);\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 /*\n * Clear the update collection after the batch update. `completed` is kept: it is what a\n * continued run needs to know.\n */\n this.flpsToUpdate.clear();\n }\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","completed","Array","folderModel","items","slug","parentId","path","permissions","item","data","entryId","EntryId","updateResult","result","Promise","type"],"mappings":";;;;AAmBO,MAAMA;IAqBT,YACYC,OAA6B,EAC7BC,kBAAgD,EAChDC,mBAAkD,EAClDC,kBAAgD,EAChDC,eAA0C,CACpD;aALUJ,OAAO,GAAPA;aACAC,kBAAkB,GAAlBA;aACAC,mBAAmB,GAAnBA;aACAC,kBAAkB,GAAlBA;aACAC,eAAe,GAAfA;QAZX,KACgB,SAAS,GAAgB,IAAIC;aAC7B,YAAY,GAA+B,IAAIC;aACxD,QAAQ,GAAG;aAEX,gBAAgB,GAAG;IAQxB;IAEH,MAAM,QAAQC,MAAuB,EAAiB;QAClD,IAAI,CAAC,gBAAgB,GAAGA,OAAO,gBAAgB;QAC/C,IAAI,CAAC,aAAa,GAAGA,OAAO,aAAa;QAGzC,IAAI,CAAC,SAAS,CAAC,KAAK;QACpB,IAAI,CAAC,QAAQ,GAAG;QAChB,IAAI,CAAC,gBAAgB,GAAG;QAExB,IAAIA,OAAO,SAAS,EAChBA,OAAO,SAAS,CAAC,OAAO,CAACC,CAAAA,KAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA;QAGtD,IAAI;YACA,MAAM,EAAEC,MAAM,EAAE,GAAGF;YAEnB,IAAI,CAACE,QACD,MAAM,IAAIC,YACN,oDACA,mDACA;gBAAED;YAAO;YAIjB,MAAME,MAAM,MAAM,IAAI,CAAC,MAAM,CAACF;YAC9B,MAAMG,YAAYH,OAAO,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAACA,OAAO,QAAQ,IAAI;YAG9E,IAAI,CAAC,YAAY,CAAC,GAAG,CAACA,OAAO,EAAE,EAAE;gBAC7B,MAAMA,OAAO,IAAI;gBACjB,UAAUA,OAAO,QAAQ,IAAII;gBAC7B,MAAMC,KAAK,MAAM,CAACL,OAAO,IAAI,EAAEG,WAAW;gBAC1C,aAAaG,YAAY,MAAM,CAACN,OAAO,WAAW,EAAEG;YACxD;YAGA,MAAMI,iBAAiB,MAAM,IAAI,CAAC,kBAAkB,CAACL;YAErD,KAAK,MAAMM,SAASD,eAAgB;gBAChC,MAAM,IAAI,CAAC,sBAAsB,CAACC,OAAON;gBACzC,IAAI,IAAI,CAAC,QAAQ,EACb;YAER;YAGA,MAAM,IAAI,CAAC,kBAAkB;QACjC,EAAE,OAAOO,OAAO;YAEZ,IAAI,CAAC,YAAY,CAAC,KAAK;YACvB,IAAI,CAAC,SAAS,CAAC,KAAK;YACpB,MAAMR,YAAY,IAAI,CAACQ,OAAO;gBAC1B,SAAS;gBACT,MAAM;YACV;QACJ;IACJ;IAEA,MAAc,uBACVP,GAA0B,EAC1BC,SAAgC,EACnB;QACb,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,IAAI,EAAE,GACzB;QAGJ,IAAI,IAAI,CAAC,gBAAgB,MAAM,YAC3B,MAAM,IAAI,CAAC,cAAc;QAK7B,MAAMQ,gBAAgB,IAAI,CAAC,YAAY,CAAC,GAAG,CAACP,UAAU,EAAE;QACxD,MAAMQ,mBAAmB;YACrB,GAAGR,SAAS;YACZ,GAAIO,iBAAiB;gBAAE,GAAGA,aAAa;YAAC,CAAC;QAC7C;QAGA,IAAI,CAAC,YAAY,CAAC,GAAG,CAACR,IAAI,EAAE,EAAE;YAC1B,MAAMA,IAAI,IAAI;YACd,UAAUA,IAAI,QAAQ;YACtB,MAAMG,KAAK,MAAM,CAACH,IAAI,IAAI,EAAES,iBAAiB,IAAI;YACjD,aAAaL,YAAY,MAAM,CAACJ,IAAI,WAAW,EAAES;QACrD;QAGA,MAAMC,WAAW,MAAM,IAAI,CAAC,kBAAkB,CAACV;QAE/C,KAAK,MAAMM,SAASI,SAAU;YAE1B,MAAM,IAAI,CAAC,sBAAsB,CAACJ,OAAON;YACzC,IAAI,IAAI,CAAC,QAAQ,EACb;QAER;QAGA,KAAK,MAAMM,SAASI,SAChB,IAAI,CAAC,SAAS,CAAC,MAAM,CAACJ,MAAM,EAAE;QAElC,IAAI,CAAC,SAAS,CAAC,GAAG,CAACN,IAAI,EAAE;QACzB,IAAI,CAAC,gBAAgB;IACzB;IASA,MAAc,iBAAgC;QAC1C,IAAI,CAAC,QAAQ,GAAG;QAChB,MAAM,IAAI,CAAC,kBAAkB;QAE7B,IAAI,AAA0B,MAA1B,IAAI,CAAC,gBAAgB,EACrB,MAAM,IAAID,YACN,yGACA;QAIR,MAAMY,YAAYC,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS;QAC3C,IAAI,CAAC,aAAa,GAAGD;IACzB;IAEA,MAAc,qBAAoC;QAC9C,MAAME,cAAc,MAAM,IAAI,CAAC,mBAAmB,CAAC,GAAG;QACtD,IAAI;YACA,MAAMC,QAAQF,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,GAAG,CACrD,CAAC,CAACf,IAAI,EAAEkB,IAAI,EAAEC,QAAQ,EAAEC,IAAI,EAAEC,WAAW,EAAE,CAAC,GACjC;oBACHrB;oBACA,MAAM;wBACFkB;wBACAC;wBACAC;wBACAC;oBACJ;gBACJ;YAIR,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAACJ;YAG/B,KAAK,MAAMK,QAAQL,MAAO;gBACtB,MAAM,EAAEjB,EAAE,EAAEuB,IAAI,EAAE,GAAGD;gBAErB,MAAME,UAAUC,QAAQ,IAAI,CAACzB;gBAC7B,MAAM0B,eAAe,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CACtDV,aACAQ,QAAQ,QAAQ,IAChB;oBAAE,QAAQ;wBAAE,MAAMD,KAAK,IAAI;oBAAC;gBAAE;gBAElC,IAAIG,aAAa,MAAM,IACnB,MAAMA,aAAa,KAAK;YAEhC;QACJ,EAAE,OAAOhB,OAAO;YACZ,MAAMR,YAAY,IAAI,CAACQ,OAAO;gBAC1B,SAAS;gBACT,MAAM;gBACN,MAAM;oBACF,OAAOK,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI;gBAC5C;YACJ;QACJ,SAAU;YAKN,IAAI,CAAC,YAAY,CAAC,KAAK;QAC3B;IACJ;IAEA,MAAc,mBAAmBZ,GAA0B,EAAoC;QAC3F,MAAMwB,SAAS,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,IACpD,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;gBACnC,OAAO;oBACH,MAAMxB,IAAI,IAAI;oBACd,UAAUA,IAAI,EAAE;gBACpB;YACJ;QAGJ,IAAIwB,OAAO,MAAM,IACb,MAAMA,OAAO,KAAK;QAGtB,OAAO,MAAMC,QAAQ,GAAG,CAACD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC1B,CAAAA,SAAU,IAAI,CAAC,MAAM,CAACA;IAC5E;IAEA,MAAc,OAAO,EACjBD,EAAE,EACF6B,IAAI,EACJV,QAAQ,EACRD,IAAI,EACJG,WAAW,EACN,EAAkC;QACvC,MAAMlB,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAACH;QAEnC,IAAI,CAACG,KAAK;YACN,MAAMC,YAAYe,WAAW,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAACA,YAAY;YAEhE,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;gBAC7BnB;gBACA6B;gBACAX;gBACA,UAAUC,YAAYd;gBACtB,MAAMC,KAAK,MAAM,CAACY,MAAMd,WAAW;gBACnC,aAAaG,YAAY,MAAM,CAACc,aAAajB;YACjD;QACJ;QAEA,OAAOD;IACX;AACJ"}
@@ -1,9 +1,13 @@
1
1
  import type { Folder } from "../../../folder/folder.types.js";
2
2
  export interface UpdateFlpParams {
3
3
  folder: Folder;
4
- queued?: string[];
4
+ /**
5
+ * Folders whose whole subtree an earlier run of the same update already wrote. Passed back
6
+ * through `handleTimeout`, so a continued run skips them.
7
+ */
8
+ completed?: string[];
5
9
  isCloseToTimeout?: () => boolean;
6
- handleTimeout?: (queued: string[]) => void;
10
+ handleTimeout?: (completed: string[]) => void;
7
11
  }
8
12
  export interface IUpdateFlpUseCase {
9
13
  execute: (params: UpdateFlpParams) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"features/flp/UpdateFlp/abstractions.js","sources":["../../../../src/features/flp/UpdateFlp/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { Folder } from \"~/folder/folder.types.js\";\n\nexport interface UpdateFlpParams {\n folder: Folder;\n queued?: string[];\n isCloseToTimeout?: () => boolean;\n handleTimeout?: (queued: string[]) => void;\n}\n\n// Use Case Abstraction\nexport interface IUpdateFlpUseCase {\n execute: (params: UpdateFlpParams) => Promise<void>;\n}\n\n/** Update a folder-level permission. */\nexport const UpdateFlpUseCase = createAbstraction<IUpdateFlpUseCase>(\"UpdateFlpUseCase\");\n\nexport namespace UpdateFlpUseCase {\n export type Interface = IUpdateFlpUseCase;\n}\n"],"names":["UpdateFlpUseCase","createAbstraction"],"mappings":";AAgBO,MAAMA,mBAAmBC,kBAAqC"}
1
+ {"version":3,"file":"features/flp/UpdateFlp/abstractions.js","sources":["../../../../src/features/flp/UpdateFlp/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { Folder } from \"~/folder/folder.types.js\";\n\nexport interface UpdateFlpParams {\n folder: Folder;\n /**\n * Folders whose whole subtree an earlier run of the same update already wrote. Passed back\n * through `handleTimeout`, so a continued run skips them.\n */\n completed?: string[];\n isCloseToTimeout?: () => boolean;\n handleTimeout?: (completed: string[]) => void;\n}\n\n// Use Case Abstraction\nexport interface IUpdateFlpUseCase {\n execute: (params: UpdateFlpParams) => Promise<void>;\n}\n\n/** Update a folder-level permission. */\nexport const UpdateFlpUseCase = createAbstraction<IUpdateFlpUseCase>(\"UpdateFlpUseCase\");\n\nexport namespace UpdateFlpUseCase {\n export type Interface = IUpdateFlpUseCase;\n}\n"],"names":["UpdateFlpUseCase","createAbstraction"],"mappings":";AAoBO,MAAMA,mBAAmBC,kBAAqC"}
@@ -1,10 +1,5 @@
1
1
  import type { Container } from "@webiny/di";
2
- import type { AcoContext } from "../../../types.js";
3
- interface LegacyDeps {
4
- context: AcoContext;
5
- }
6
2
  export declare const UpdateFlpFeature: {
7
3
  name: string;
8
- register(container: Container, context: LegacyDeps): void;
4
+ register(container: Container): void;
9
5
  };
10
- export {};
@@ -1,10 +1,15 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
2
  import { UpdateFlpUseCase } from "./UpdateFlpUseCase.js";
3
3
  import { UpdateFlpUseCase as external_abstractions_js_UpdateFlpUseCase } from "./abstractions.js";
4
+ import { AcoFlpCrud } from "../../folder/shared/abstractions.js";
5
+ import { ListFoldersUseCase } from "../../folder/ListFolders/index.js";
6
+ import { FolderModelProvider } from "../../../domain/folder/abstractions.js";
7
+ import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry/index.js";
8
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
4
9
  const UpdateFlpFeature = createFeature({
5
10
  name: "UpdateFlp",
6
- register (container, deps) {
7
- container.registerFactory(external_abstractions_js_UpdateFlpUseCase, ()=>new UpdateFlpUseCase(deps.context));
11
+ register (container) {
12
+ container.registerFactory(external_abstractions_js_UpdateFlpUseCase, ()=>new UpdateFlpUseCase(container.resolve(AcoFlpCrud), container.resolve(ListFoldersUseCase), container.resolve(FolderModelProvider), container.resolve(UpdateEntryUseCase), container.resolve(IdentityContext)));
8
13
  }
9
14
  });
10
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 type { AcoContext } from \"~/types.js\";\n\ninterface LegacyDeps {\n context: AcoContext;\n}\n\nexport const UpdateFlpFeature = createFeature({\n name: \"UpdateFlp\",\n register(container: Container, deps: LegacyDeps) {\n container.registerFactory(UseCaseAbstraction, () => {\n return new UpdateFlpUseCase(deps.context);\n });\n }\n});\n"],"names":["UpdateFlpFeature","createFeature","container","deps","UseCaseAbstraction","UpdateFlpUseCase"],"mappings":";;;AAUO,MAAMA,mBAAmBC,cAAc;IAC1C,MAAM;IACN,UAASC,SAAoB,EAAEC,IAAgB;QAC3CD,UAAU,eAAe,CAACE,2CAAoB,IACnC,IAAIC,iBAAiBF,KAAK,OAAO;IAEhD;AACJ"}
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"}
@@ -1,14 +1,17 @@
1
1
  import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
2
- import { UpdateFlpUseCase } from "../UpdateFlp/abstractions.js";
2
+ import { Logger } from "@webiny/api-core/features/logger/index.js";
3
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
3
4
  import type { FolderAfterUpdateEvent } from "../../../features/folder/UpdateFolder/events.js";
4
5
  import { FolderAfterUpdateEventHandler } from "../../../features/folder/UpdateFolder/index.js";
5
6
  declare class UpdateFlpOnFolderUpdatedHandlerImpl implements FolderAfterUpdateEventHandler.Interface {
6
- private updateFlpUseCase;
7
- private tasks?;
8
- constructor(updateFlpUseCase: UpdateFlpUseCase.Interface, tasks?: TaskService.Interface | undefined);
7
+ private identityContext;
8
+ private tasks;
9
+ private logger;
10
+ constructor(identityContext: IdentityContext.Interface, tasks: TaskService.Interface, logger: Logger.Interface);
9
11
  handle(event: FolderAfterUpdateEvent): Promise<void>;
12
+ private logFailure;
10
13
  }
11
14
  export declare const UpdateFlpOnFolderUpdatedHandler: typeof UpdateFlpOnFolderUpdatedHandlerImpl & {
12
- __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher/abstractions.js").IEventHandler<import("@webiny/api-core/features/eventPublisher/abstractions.js").DomainEvent<import("../../folder/UpdateFolder/abstractions.js").FolderAfterUpdatePayload>>>;
15
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher").IEventHandler<import("@webiny/api-core/features/eventPublisher").DomainEvent<import("../../folder/UpdateFolder/abstractions").FolderAfterUpdatePayload>>>;
13
16
  };
14
17
  export {};
@@ -1,37 +1,42 @@
1
1
  import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
2
- import { UpdateFlpUseCase } from "../UpdateFlp/abstractions.js";
2
+ import { Logger } from "@webiny/api-core/features/logger/index.js";
3
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
3
4
  import { UPDATE_FLP_TASK_ID } from "../../../flp/tasks/index.js";
4
5
  import { FolderAfterUpdateEventHandler } from "../../folder/UpdateFolder/index.js";
5
6
  class UpdateFlpOnFolderUpdatedHandlerImpl {
6
- constructor(updateFlpUseCase, tasks){
7
- this.updateFlpUseCase = updateFlpUseCase;
7
+ constructor(identityContext, tasks, logger){
8
+ this.identityContext = identityContext;
8
9
  this.tasks = tasks;
10
+ this.logger = logger;
9
11
  }
10
12
  async handle(event) {
11
13
  const { folder } = event.payload;
12
14
  try {
13
- if (this.tasks) await this.tasks.trigger({
15
+ const result = await this.tasks.trigger({
14
16
  definition: UPDATE_FLP_TASK_ID,
15
17
  input: {
16
- folder
18
+ folder,
19
+ notifyIdentityId: this.identityContext.getIdentity()?.id
17
20
  }
18
21
  });
19
- else await this.updateFlpUseCase.execute({
20
- folder
21
- });
22
- } catch {}
22
+ if (result.isFail()) this.logFailure(folder.id, result.error);
23
+ } catch (error) {
24
+ this.logFailure(folder.id, error);
25
+ }
26
+ }
27
+ logFailure(folderId, error) {
28
+ this.logger.error({
29
+ error,
30
+ folderId
31
+ }, "Could not trigger the task that updates the FLP records of the folder and its subtree.");
23
32
  }
24
33
  }
25
34
  const UpdateFlpOnFolderUpdatedHandler = FolderAfterUpdateEventHandler.createImplementation({
26
35
  implementation: UpdateFlpOnFolderUpdatedHandlerImpl,
27
36
  dependencies: [
28
- UpdateFlpUseCase,
29
- [
30
- TaskService,
31
- {
32
- optional: true
33
- }
34
- ]
37
+ IdentityContext,
38
+ TaskService,
39
+ Logger
35
40
  ]
36
41
  });
37
42
  export { UpdateFlpOnFolderUpdatedHandler };
@@ -1 +1 @@
1
- {"version":3,"file":"features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js","sources":["../../../../src/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.ts"],"sourcesContent":["import { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { UpdateFlpUseCase } from \"../UpdateFlp/abstractions.js\";\nimport type { FolderAfterUpdateEvent } from \"~/features/folder/UpdateFolder/events.js\";\nimport type { IUpdateFlpTaskInput } from \"~/types.js\";\nimport { UPDATE_FLP_TASK_ID } from \"~/flp/tasks/index.js\";\nimport { FolderAfterUpdateEventHandler } from \"~/features/folder/UpdateFolder/index.js\";\n\nclass UpdateFlpOnFolderUpdatedHandlerImpl implements FolderAfterUpdateEventHandler.Interface {\n constructor(\n private updateFlpUseCase: UpdateFlpUseCase.Interface,\n private tasks?: TaskService.Interface\n ) {}\n\n async handle(event: FolderAfterUpdateEvent): Promise<void> {\n const { folder } = event.payload;\n\n try {\n if (this.tasks) {\n await this.tasks.trigger<IUpdateFlpTaskInput>({\n definition: UPDATE_FLP_TASK_ID,\n input: { folder }\n });\n } else {\n await this.updateFlpUseCase.execute({ folder });\n }\n } catch {\n // Ignore errors\n }\n }\n}\n\nexport const UpdateFlpOnFolderUpdatedHandler = FolderAfterUpdateEventHandler.createImplementation({\n implementation: UpdateFlpOnFolderUpdatedHandlerImpl,\n dependencies: [UpdateFlpUseCase, [TaskService, { optional: true }]]\n});\n"],"names":["UpdateFlpOnFolderUpdatedHandlerImpl","updateFlpUseCase","tasks","event","folder","UPDATE_FLP_TASK_ID","UpdateFlpOnFolderUpdatedHandler","FolderAfterUpdateEventHandler","UpdateFlpUseCase","TaskService"],"mappings":";;;;AAOA,MAAMA;IACF,YACYC,gBAA4C,EAC5CC,KAA6B,CACvC;aAFUD,gBAAgB,GAAhBA;aACAC,KAAK,GAALA;IACT;IAEH,MAAM,OAAOC,KAA6B,EAAiB;QACvD,MAAM,EAAEC,MAAM,EAAE,GAAGD,MAAM,OAAO;QAEhC,IAAI;YACA,IAAI,IAAI,CAAC,KAAK,EACV,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB;gBAC1C,YAAYE;gBACZ,OAAO;oBAAED;gBAAO;YACpB;iBAEA,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBAAEA;YAAO;QAErD,EAAE,OAAM,CAER;IACJ;AACJ;AAEO,MAAME,kCAAkCC,8BAA8B,oBAAoB,CAAC;IAC9F,gBAAgBP;IAChB,cAAc;QAACQ;QAAkB;YAACC;YAAa;gBAAE,UAAU;YAAK;SAAE;KAAC;AACvE"}
1
+ {"version":3,"file":"features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.js","sources":["../../../../src/features/flp/UpdateFlpOnFolderUpdated/UpdateFlpOnFolderUpdatedHandler.ts"],"sourcesContent":["import { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { Logger } from \"@webiny/api-core/features/logger/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport type { FolderAfterUpdateEvent } from \"~/features/folder/UpdateFolder/events.js\";\nimport type { IUpdateFlpTaskInput } from \"~/types.js\";\nimport { UPDATE_FLP_TASK_ID } from \"~/flp/tasks/index.js\";\nimport { FolderAfterUpdateEventHandler } from \"~/features/folder/UpdateFolder/index.js\";\n\n/*\n * Folder reads report permissions from the FLP records, and a change rewrites the folder's record\n * and every descendant's. The task does that later, so it also tells the admin once all of them are\n * written, and it needs to know whom to tell.\n */\nclass UpdateFlpOnFolderUpdatedHandlerImpl implements FolderAfterUpdateEventHandler.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private tasks: TaskService.Interface,\n private logger: Logger.Interface\n ) {}\n\n async handle(event: FolderAfterUpdateEvent): Promise<void> {\n const { folder } = event.payload;\n\n try {\n const result = await this.tasks.trigger<IUpdateFlpTaskInput>({\n definition: UPDATE_FLP_TASK_ID,\n // Nobody to tell when there is no identity, as in some system calls.\n input: { folder, notifyIdentityId: this.identityContext.getIdentity()?.id }\n });\n if (result.isFail()) {\n this.logFailure(folder.id, result.error);\n }\n } catch (error) {\n this.logFailure(folder.id, error);\n }\n }\n\n /*\n * The folder change is already saved, so it stands. But the FLP records of the folder and its\n * subtree keep the old permissions, and this log is the only trace of why.\n */\n private logFailure(folderId: string, error: unknown): void {\n this.logger.error(\n { error, folderId },\n \"Could not trigger the task that updates the FLP records of the folder and its subtree.\"\n );\n }\n}\n\nexport const UpdateFlpOnFolderUpdatedHandler = FolderAfterUpdateEventHandler.createImplementation({\n implementation: UpdateFlpOnFolderUpdatedHandlerImpl,\n dependencies: [IdentityContext, TaskService, Logger]\n});\n"],"names":["UpdateFlpOnFolderUpdatedHandlerImpl","identityContext","tasks","logger","event","folder","result","UPDATE_FLP_TASK_ID","error","folderId","UpdateFlpOnFolderUpdatedHandler","FolderAfterUpdateEventHandler","IdentityContext","TaskService","Logger"],"mappings":";;;;;AAaA,MAAMA;IACF,YACYC,eAA0C,EAC1CC,KAA4B,EAC5BC,MAAwB,CAClC;aAHUF,eAAe,GAAfA;aACAC,KAAK,GAALA;aACAC,MAAM,GAANA;IACT;IAEH,MAAM,OAAOC,KAA6B,EAAiB;QACvD,MAAM,EAAEC,MAAM,EAAE,GAAGD,MAAM,OAAO;QAEhC,IAAI;YACA,MAAME,SAAS,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB;gBACzD,YAAYC;gBAEZ,OAAO;oBAAEF;oBAAQ,kBAAkB,IAAI,CAAC,eAAe,CAAC,WAAW,IAAI;gBAAG;YAC9E;YACA,IAAIC,OAAO,MAAM,IACb,IAAI,CAAC,UAAU,CAACD,OAAO,EAAE,EAAEC,OAAO,KAAK;QAE/C,EAAE,OAAOE,OAAO;YACZ,IAAI,CAAC,UAAU,CAACH,OAAO,EAAE,EAAEG;QAC/B;IACJ;IAMQ,WAAWC,QAAgB,EAAED,KAAc,EAAQ;QACvD,IAAI,CAAC,MAAM,CAAC,KAAK,CACb;YAAEA;YAAOC;QAAS,GAClB;IAER;AACJ;AAEO,MAAMC,kCAAkCC,8BAA8B,oBAAoB,CAAC;IAC9F,gBAAgBX;IAChB,cAAc;QAACY;QAAiBC;QAAaC;KAAO;AACxD"}
@@ -0,0 +1,26 @@
1
+ import type { FolderLevelPermission, FolderPermission } from "../../../flp/flp.types.js";
2
+ export declare class CodeFlpMerger {
3
+ /**
4
+ * Merge code-defined permissions into a stored FLP record.
5
+ *
6
+ * A code-defined permission always wins over a stored one for the same target, and that takes
7
+ * both steps below — ordering alone is not enough, because the two downstream consumers pick a
8
+ * target's permission in different ways:
9
+ *
10
+ * - `CanAccessFolder` takes the first match (`permissions.find(p => p.target === ...)`), so code
11
+ * permissions go first.
12
+ * - `DefaultPermissionsMerger` instead collects *every* permission for the identity and reduces
13
+ * them by access level, preferring `no-access` and then `owner`. A leftover duplicate would
14
+ * join that reduce and could outrank the code-defined entry — a stored `owner` would beat a
15
+ * code-defined `viewer`. Dropping the stored permission for a code-defined target is what
16
+ * prevents it.
17
+ *
18
+ * So: exactly one permission per target, and for code-defined targets it is the code one.
19
+ */
20
+ static merge(flp: FolderLevelPermission, codePermissions: FolderPermission[]): FolderLevelPermission;
21
+ /**
22
+ * The same merge, for callers that hold a plain permission list rather than a stored FLP record
23
+ * — the write paths, which resolve code permissions from the folder's own type and path.
24
+ */
25
+ static mergePermissions(permissions: FolderPermission[], codePermissions: FolderPermission[]): FolderPermission[];
26
+ }