@webiny/api-headless-cms-tasks 6.6.0-alpha.0 → 6.6.0-alpha.1
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/HcmsTasksFeature.js +6 -5
- package/HcmsTasksFeature.js.map +1 -1
- package/features/DisableModel/BlockActionIfModelDisabled.d.ts +17 -4
- package/features/DisableModel/BlockActionIfModelDisabled.js +13 -5
- package/features/DisableModel/BlockActionIfModelDisabled.js.map +1 -1
- package/features/DisableModel/feature.js +2 -5
- package/features/DisableModel/feature.js.map +1 -1
- package/graphql/deleteModel/DeleteModelOperationsImpl.d.ts +43 -0
- package/graphql/deleteModel/DeleteModelOperationsImpl.js +91 -0
- package/graphql/deleteModel/DeleteModelOperationsImpl.js.map +1 -0
- package/graphql/deleteModel/assertModelDeletable.d.ts +11 -0
- package/graphql/deleteModel/assertModelDeletable.js +17 -0
- package/graphql/deleteModel/assertModelDeletable.js.map +1 -0
- package/graphql/deleteModel/cancelDeleteModel.d.ts +9 -2
- package/graphql/deleteModel/cancelDeleteModel.js +9 -20
- package/graphql/deleteModel/cancelDeleteModel.js.map +1 -1
- package/graphql/deleteModel/fullyDeleteModel.d.ts +10 -2
- package/graphql/deleteModel/fullyDeleteModel.js +9 -22
- package/graphql/deleteModel/fullyDeleteModel.js.map +1 -1
- package/graphql/deleteModel/getDeleteModelProgress.d.ts +8 -2
- package/graphql/deleteModel/getDeleteModelProgress.js +8 -19
- package/graphql/deleteModel/getDeleteModelProgress.js.map +1 -1
- package/graphql/deleteModel/index.d.ts +21 -2
- package/graphql/deleteModel/index.js +79 -64
- package/graphql/deleteModel/index.js.map +1 -1
- package/package.json +18 -18
- package/graphql/deleteModel/crud.d.ts +0 -2
- package/graphql/deleteModel/crud.js +0 -56
- package/graphql/deleteModel/crud.js.map +0 -1
package/HcmsTasksFeature.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import { RequestContextInitializer } from "@webiny/event-handler-core";
|
|
3
2
|
import { HcmsBulkActionsFeature } from "@webiny/api-headless-cms-bulk-actions";
|
|
4
3
|
import { DeleteModelTaskFeature } from "./features/DeleteModelTask/feature.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { DisableModelFeature } from "./features/DisableModel/feature.js";
|
|
5
|
+
import { DeleteModelOperationsImplementation } from "./graphql/deleteModel/DeleteModelOperationsImpl.js";
|
|
6
|
+
import { DeleteModelGraphQLSchemaFactoryImpl } from "./graphql/deleteModel/index.js";
|
|
7
7
|
const HcmsTasksFeature = createFeature({
|
|
8
8
|
name: "HcmsTasks",
|
|
9
9
|
register (container) {
|
|
@@ -11,8 +11,9 @@ const HcmsTasksFeature = createFeature({
|
|
|
11
11
|
batchSize: 100
|
|
12
12
|
});
|
|
13
13
|
DeleteModelTaskFeature.register(container);
|
|
14
|
-
container.
|
|
15
|
-
|
|
14
|
+
container.register(DeleteModelOperationsImplementation);
|
|
15
|
+
DisableModelFeature.register(container);
|
|
16
|
+
container.register(DeleteModelGraphQLSchemaFactoryImpl);
|
|
16
17
|
}
|
|
17
18
|
});
|
|
18
19
|
export { HcmsTasksFeature };
|
package/HcmsTasksFeature.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HcmsTasksFeature.js","sources":["../src/HcmsTasksFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"HcmsTasksFeature.js","sources":["../src/HcmsTasksFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { HcmsBulkActionsFeature } from \"@webiny/api-headless-cms-bulk-actions\";\nimport { DeleteModelTaskFeature } from \"./features/DeleteModelTask/feature.js\";\nimport { DisableModelFeature } from \"./features/DisableModel/feature.js\";\nimport { DeleteModelOperationsImplementation } from \"./graphql/deleteModel/DeleteModelOperationsImpl.js\";\nimport { DeleteModelGraphQLSchemaFactoryImpl } from \"./graphql/deleteModel/index.js\";\n\nexport const HcmsTasksFeature = createFeature({\n name: \"HcmsTasks\",\n register(container) {\n // Bulk actions (entries) + the empty-trash-bin task.\n HcmsBulkActionsFeature.register(container, { batchSize: 100 });\n\n DeleteModelTaskFeature.register(container);\n\n container.register(DeleteModelOperationsImplementation);\n DisableModelFeature.register(container);\n\n container.register(DeleteModelGraphQLSchemaFactoryImpl);\n }\n});\n"],"names":["HcmsTasksFeature","createFeature","container","HcmsBulkActionsFeature","DeleteModelTaskFeature","DeleteModelOperationsImplementation","DisableModelFeature","DeleteModelGraphQLSchemaFactoryImpl"],"mappings":";;;;;;AAOO,MAAMA,mBAAmBC,cAAc;IAC1C,MAAM;IACN,UAASC,SAAS;QAEdC,uBAAuB,QAAQ,CAACD,WAAW;YAAE,WAAW;QAAI;QAE5DE,uBAAuB,QAAQ,CAACF;QAEhCA,UAAU,QAAQ,CAACG;QACnBC,oBAAoB,QAAQ,CAACJ;QAE7BA,UAAU,QAAQ,CAACK;IACvB;AACJ"}
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import type { CmsModel } from "@webiny/api-headless-cms/types/index.js";
|
|
2
2
|
import { BlockActionIfModelDisabled as Abstraction } from "./abstractions.js";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
private
|
|
6
|
-
constructor(
|
|
3
|
+
import { DeleteModelOperations } from "../../graphql/deleteModel/abstractions.js";
|
|
4
|
+
declare class BlockActionIfModelDisabledImpl implements Abstraction.Interface {
|
|
5
|
+
private readonly deleteModelOperations;
|
|
6
|
+
constructor(deleteModelOperations: DeleteModelOperations.Interface);
|
|
7
7
|
execute(model: CmsModel): Promise<void>;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Takes `DeleteModelOperations` itself, not a pre-bound `isModelBeingDeleted`.
|
|
11
|
+
*
|
|
12
|
+
* Binding the method meant the feature had to `container.resolve(DeleteModelOperations)` while
|
|
13
|
+
* registering, which constructs it — and therefore everything it depends on — at register time.
|
|
14
|
+
* `HcmsTasksFeature` registers before `BackgroundTasksFeature`, so the moment the operations class
|
|
15
|
+
* declared its own task use cases that resolve threw "No registration found for
|
|
16
|
+
* Tasks/TriggerTaskUseCase". Depending on the abstraction defers construction to first use.
|
|
17
|
+
*/
|
|
18
|
+
export declare const BlockActionIfModelDisabledImplementation: typeof BlockActionIfModelDisabledImpl & {
|
|
19
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IBlockActionIfModelDisabled>;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { WebinyError } from "@webiny/error";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { BlockActionIfModelDisabled } from "./abstractions.js";
|
|
3
|
+
import { DeleteModelOperations } from "../../graphql/deleteModel/abstractions.js";
|
|
4
|
+
class BlockActionIfModelDisabledImpl {
|
|
5
|
+
constructor(deleteModelOperations){
|
|
6
|
+
this.deleteModelOperations = deleteModelOperations;
|
|
5
7
|
}
|
|
6
8
|
async execute(model) {
|
|
7
|
-
const isBeingDeleted = await this.isModelBeingDeleted(model.modelId);
|
|
9
|
+
const isBeingDeleted = await this.deleteModelOperations.isModelBeingDeleted(model.modelId);
|
|
8
10
|
if (!isBeingDeleted) return;
|
|
9
11
|
throw new WebinyError(`Model "${model.name}" is being deleted and you cannot create, update or delete any entries of this model.`);
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
const BlockActionIfModelDisabledImplementation = BlockActionIfModelDisabled.createImplementation({
|
|
15
|
+
implementation: BlockActionIfModelDisabledImpl,
|
|
16
|
+
dependencies: [
|
|
17
|
+
DeleteModelOperations
|
|
18
|
+
]
|
|
19
|
+
});
|
|
20
|
+
export { BlockActionIfModelDisabledImplementation };
|
|
13
21
|
|
|
14
22
|
//# sourceMappingURL=BlockActionIfModelDisabled.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/DisableModel/BlockActionIfModelDisabled.js","sources":["../../../src/features/DisableModel/BlockActionIfModelDisabled.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport { BlockActionIfModelDisabled as Abstraction } from \"./abstractions.js\";\nimport
|
|
1
|
+
{"version":3,"file":"features/DisableModel/BlockActionIfModelDisabled.js","sources":["../../../src/features/DisableModel/BlockActionIfModelDisabled.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport { BlockActionIfModelDisabled as Abstraction } from \"./abstractions.js\";\nimport { DeleteModelOperations } from \"~/graphql/deleteModel/abstractions.js\";\n\nclass BlockActionIfModelDisabledImpl implements Abstraction.Interface {\n constructor(private readonly deleteModelOperations: DeleteModelOperations.Interface) {}\n\n async execute(model: CmsModel): Promise<void> {\n const isBeingDeleted = await this.deleteModelOperations.isModelBeingDeleted(model.modelId);\n if (!isBeingDeleted) {\n return;\n }\n\n throw new WebinyError(\n `Model \"${model.name}\" is being deleted and you cannot create, update or delete any entries of this model.`\n );\n }\n}\n\n/**\n * Takes `DeleteModelOperations` itself, not a pre-bound `isModelBeingDeleted`.\n *\n * Binding the method meant the feature had to `container.resolve(DeleteModelOperations)` while\n * registering, which constructs it — and therefore everything it depends on — at register time.\n * `HcmsTasksFeature` registers before `BackgroundTasksFeature`, so the moment the operations class\n * declared its own task use cases that resolve threw \"No registration found for\n * Tasks/TriggerTaskUseCase\". Depending on the abstraction defers construction to first use.\n */\nexport const BlockActionIfModelDisabledImplementation = Abstraction.createImplementation({\n implementation: BlockActionIfModelDisabledImpl,\n dependencies: [DeleteModelOperations]\n});\n"],"names":["BlockActionIfModelDisabledImpl","deleteModelOperations","model","isBeingDeleted","WebinyError","BlockActionIfModelDisabledImplementation","Abstraction","DeleteModelOperations"],"mappings":";;;AAKA,MAAMA;IACF,YAA6BC,qBAAsD,CAAE;aAAxDA,qBAAqB,GAArBA;IAAyD;IAEtF,MAAM,QAAQC,KAAe,EAAiB;QAC1C,MAAMC,iBAAiB,MAAM,IAAI,CAAC,qBAAqB,CAAC,mBAAmB,CAACD,MAAM,OAAO;QACzF,IAAI,CAACC,gBACD;QAGJ,MAAM,IAAIC,YACN,CAAC,OAAO,EAAEF,MAAM,IAAI,CAAC,qFAAqF,CAAC;IAEnH;AACJ;AAWO,MAAMG,2CAA2CC,2BAAAA,oBAAgC,CAAC;IACrF,gBAAgBN;IAChB,cAAc;QAACO;KAAsB;AACzC"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import {
|
|
3
|
-
import { BlockActionIfModelDisabled as external_BlockActionIfModelDisabled_js_BlockActionIfModelDisabled } from "./BlockActionIfModelDisabled.js";
|
|
4
|
-
import { DeleteModelOperations } from "../../graphql/deleteModel/abstractions.js";
|
|
2
|
+
import { BlockActionIfModelDisabledImplementation } from "./BlockActionIfModelDisabled.js";
|
|
5
3
|
import { BlockModelActionOnEntryBeforeCreate } from "./handlers/BlockModelActionOnEntryBeforeCreate.js";
|
|
6
4
|
import { BlockModelActionOnEntryRevisionBeforeCreate } from "./handlers/BlockModelActionOnEntryRevisionBeforeCreate.js";
|
|
7
5
|
import { BlockModelActionOnEntryBeforeUpdate } from "./handlers/BlockModelActionOnEntryBeforeUpdate.js";
|
|
@@ -15,8 +13,7 @@ import { BlockModelActionOnModelBeforeCreateFrom } from "./handlers/BlockModelAc
|
|
|
15
13
|
const DisableModelFeature = createFeature({
|
|
16
14
|
name: "DisableModel",
|
|
17
15
|
register (container) {
|
|
18
|
-
|
|
19
|
-
container.registerInstance(BlockActionIfModelDisabled, new external_BlockActionIfModelDisabled_js_BlockActionIfModelDisabled(ops.isModelBeingDeleted.bind(ops)));
|
|
16
|
+
container.register(BlockActionIfModelDisabledImplementation);
|
|
20
17
|
container.register(BlockModelActionOnEntryBeforeCreate);
|
|
21
18
|
container.register(BlockModelActionOnEntryRevisionBeforeCreate);
|
|
22
19
|
container.register(BlockModelActionOnEntryBeforeUpdate);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/DisableModel/feature.js","sources":["../../../src/features/DisableModel/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/DisableModel/feature.js","sources":["../../../src/features/DisableModel/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { BlockActionIfModelDisabledImplementation } from \"./BlockActionIfModelDisabled.js\";\nimport { BlockModelActionOnEntryBeforeCreate } from \"./handlers/BlockModelActionOnEntryBeforeCreate.js\";\nimport { BlockModelActionOnEntryRevisionBeforeCreate } from \"./handlers/BlockModelActionOnEntryRevisionBeforeCreate.js\";\nimport { BlockModelActionOnEntryBeforeUpdate } from \"./handlers/BlockModelActionOnEntryBeforeUpdate.js\";\nimport { BlockModelActionOnEntryBeforeUnpublish } from \"./handlers/BlockModelActionOnEntryBeforeUnpublish.js\";\nimport { BlockModelActionOnEntryBeforePublish } from \"./handlers/BlockModelActionOnEntryBeforePublish.js\";\nimport { BlockModelActionOnEntryBeforeRepublish } from \"./handlers/BlockModelActionOnEntryBeforeRepublish.js\";\nimport { BlockModelActionOnEntryBeforeRestoreFromBin } from \"./handlers/BlockModelActionOnEntryBeforeRestoreFromBin.js\";\nimport { BlockModelActionOnEntryBeforeMove } from \"./handlers/BlockModelActionOnEntryBeforeMove.js\";\nimport { BlockModelActionOnModelBeforeUpdate } from \"./handlers/BlockModelActionOnModelBeforeUpdate.js\";\nimport { BlockModelActionOnModelBeforeCreateFrom } from \"./handlers/BlockModelActionOnModelBeforeCreateFrom.js\";\n\nexport const DisableModelFeature = createFeature({\n name: \"DisableModel\",\n register(container) {\n container.register(BlockActionIfModelDisabledImplementation);\n\n container.register(BlockModelActionOnEntryBeforeCreate);\n container.register(BlockModelActionOnEntryRevisionBeforeCreate);\n container.register(BlockModelActionOnEntryBeforeUpdate);\n container.register(BlockModelActionOnEntryBeforeUnpublish);\n container.register(BlockModelActionOnEntryBeforePublish);\n container.register(BlockModelActionOnEntryBeforeRepublish);\n container.register(BlockModelActionOnEntryBeforeRestoreFromBin);\n container.register(BlockModelActionOnEntryBeforeMove);\n\n container.register(BlockModelActionOnModelBeforeUpdate);\n container.register(BlockModelActionOnModelBeforeCreateFrom);\n }\n});\n"],"names":["DisableModelFeature","createFeature","container","BlockActionIfModelDisabledImplementation","BlockModelActionOnEntryBeforeCreate","BlockModelActionOnEntryRevisionBeforeCreate","BlockModelActionOnEntryBeforeUpdate","BlockModelActionOnEntryBeforeUnpublish","BlockModelActionOnEntryBeforePublish","BlockModelActionOnEntryBeforeRepublish","BlockModelActionOnEntryBeforeRestoreFromBin","BlockModelActionOnEntryBeforeMove","BlockModelActionOnModelBeforeUpdate","BlockModelActionOnModelBeforeCreateFrom"],"mappings":";;;;;;;;;;;;AAaO,MAAMA,sBAAsBC,cAAc;IAC7C,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QAEnBD,UAAU,QAAQ,CAACE;QACnBF,UAAU,QAAQ,CAACG;QACnBH,UAAU,QAAQ,CAACI;QACnBJ,UAAU,QAAQ,CAACK;QACnBL,UAAU,QAAQ,CAACM;QACnBN,UAAU,QAAQ,CAACO;QACnBP,UAAU,QAAQ,CAACQ;QACnBR,UAAU,QAAQ,CAACS;QAEnBT,UAAU,QAAQ,CAACU;QACnBV,UAAU,QAAQ,CAACW;IACvB;AACJ"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
2
|
+
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
3
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
4
|
+
import { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
5
|
+
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
6
|
+
import { AbortTaskUseCase, GetTaskUseCase, TriggerTaskUseCase } from "@webiny/background-tasks/api";
|
|
7
|
+
import type { IStoreValue } from "../../features/DeleteModelTask/types.js";
|
|
8
|
+
import { DeleteModelOperations } from "../../graphql/deleteModel/abstractions.js";
|
|
9
|
+
/**
|
|
10
|
+
* Delete-model operations, previously assembled inside a `RequestContextInitializer`
|
|
11
|
+
* (`createDeleteModelCrud`) from closures over the request context.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here needed a per-request hook: every member is already async, and the tenant is read
|
|
14
|
+
* lazily at call time rather than at construction. As an ordinary DI implementation it is
|
|
15
|
+
* sync-constructible, which also lets `DisableModelFeature` keep resolving it at register time.
|
|
16
|
+
*
|
|
17
|
+
* The in-memory cache is KEPT. Unlike the CMS model providers — where `ModelsFetcher`/`ModelCache`
|
|
18
|
+
* already cached a layer down — nothing caches these key-value reads, so without it every
|
|
19
|
+
* `isModelBeingDeleted()` check would hit the store. It is cleared on mutation, as before.
|
|
20
|
+
*/
|
|
21
|
+
declare class DeleteModelOperationsImpl implements DeleteModelOperations.Interface {
|
|
22
|
+
private readonly tenantContext;
|
|
23
|
+
private readonly keyValueStore;
|
|
24
|
+
private readonly identityContext;
|
|
25
|
+
private readonly getModel;
|
|
26
|
+
private readonly accessControl;
|
|
27
|
+
private readonly triggerTask;
|
|
28
|
+
private readonly getTask;
|
|
29
|
+
private readonly abortTask;
|
|
30
|
+
private readonly cache;
|
|
31
|
+
constructor(tenantContext: TenantContext.Interface, keyValueStore: GlobalKeyValueStore.Interface, identityContext: IdentityContext.Interface, getModel: GetModelUseCase.Interface, accessControl: AccessControl.Interface, triggerTask: TriggerTaskUseCase.Interface, getTask: GetTaskUseCase.Interface, abortTask: AbortTaskUseCase.Interface);
|
|
32
|
+
listModelsBeingDeleted(): Promise<IStoreValue[]>;
|
|
33
|
+
isModelBeingDeleted(modelId: string): Promise<boolean>;
|
|
34
|
+
fullyDeleteModel(modelId: string): Promise<import("~/features/DeleteModelTask/types.js").IDeleteCmsModelTask>;
|
|
35
|
+
cancelFullyDeleteModel(modelId: string): Promise<import("~/features/DeleteModelTask/types.js").IDeleteCmsModelTask>;
|
|
36
|
+
getDeleteModelProgress(modelId: string): Promise<import("~/features/DeleteModelTask/types.js").IDeleteCmsModelTask>;
|
|
37
|
+
private getTenant;
|
|
38
|
+
private getStore;
|
|
39
|
+
}
|
|
40
|
+
export declare const DeleteModelOperationsImplementation: typeof DeleteModelOperationsImpl & {
|
|
41
|
+
__abstraction: import("@webiny/di").Abstraction<import("~/graphql/deleteModel/abstractions.js").IDeleteModelOperations>;
|
|
42
|
+
};
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
2
|
+
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
3
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
4
|
+
import { createCacheKey, createMemoryCache } from "@webiny/api-headless-cms/utils/index.js";
|
|
5
|
+
import { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
6
|
+
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
7
|
+
import { AbortTaskUseCase, GetTaskUseCase, TriggerTaskUseCase } from "@webiny/background-tasks/api";
|
|
8
|
+
import { createDeleteModelStore } from "../../helpers/store.js";
|
|
9
|
+
import { fullyDeleteModel } from "./fullyDeleteModel.js";
|
|
10
|
+
import { cancelDeleteModel } from "./cancelDeleteModel.js";
|
|
11
|
+
import { getDeleteModelProgress } from "./getDeleteModelProgress.js";
|
|
12
|
+
import { DeleteModelOperations } from "./abstractions.js";
|
|
13
|
+
class DeleteModelOperationsImpl {
|
|
14
|
+
constructor(tenantContext, keyValueStore, identityContext, getModel, accessControl, triggerTask, getTask, abortTask){
|
|
15
|
+
this.tenantContext = tenantContext;
|
|
16
|
+
this.keyValueStore = keyValueStore;
|
|
17
|
+
this.identityContext = identityContext;
|
|
18
|
+
this.getModel = getModel;
|
|
19
|
+
this.accessControl = accessControl;
|
|
20
|
+
this.triggerTask = triggerTask;
|
|
21
|
+
this.getTask = getTask;
|
|
22
|
+
this.abortTask = abortTask;
|
|
23
|
+
this.cache = createMemoryCache();
|
|
24
|
+
}
|
|
25
|
+
async listModelsBeingDeleted() {
|
|
26
|
+
const cacheKey = createCacheKey({
|
|
27
|
+
tenant: this.getTenant(),
|
|
28
|
+
type: "deleteModel"
|
|
29
|
+
});
|
|
30
|
+
return this.cache.getOrSet(cacheKey, ()=>this.getStore().list());
|
|
31
|
+
}
|
|
32
|
+
async isModelBeingDeleted(modelId) {
|
|
33
|
+
const items = await this.listModelsBeingDeleted();
|
|
34
|
+
return items.some((item)=>item.modelId === modelId);
|
|
35
|
+
}
|
|
36
|
+
async fullyDeleteModel(modelId) {
|
|
37
|
+
const result = await fullyDeleteModel({
|
|
38
|
+
getModel: this.getModel,
|
|
39
|
+
accessControl: this.accessControl,
|
|
40
|
+
keyValueStore: this.keyValueStore,
|
|
41
|
+
triggerTask: this.triggerTask,
|
|
42
|
+
identityContext: this.identityContext,
|
|
43
|
+
modelId
|
|
44
|
+
});
|
|
45
|
+
this.cache.clear();
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
async cancelFullyDeleteModel(modelId) {
|
|
49
|
+
const result = await cancelDeleteModel({
|
|
50
|
+
getModel: this.getModel,
|
|
51
|
+
accessControl: this.accessControl,
|
|
52
|
+
keyValueStore: this.keyValueStore,
|
|
53
|
+
getTask: this.getTask,
|
|
54
|
+
abortTask: this.abortTask,
|
|
55
|
+
modelId
|
|
56
|
+
});
|
|
57
|
+
this.cache.clear();
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
async getDeleteModelProgress(modelId) {
|
|
61
|
+
return getDeleteModelProgress({
|
|
62
|
+
getModel: this.getModel,
|
|
63
|
+
accessControl: this.accessControl,
|
|
64
|
+
keyValueStore: this.keyValueStore,
|
|
65
|
+
getTask: this.getTask,
|
|
66
|
+
modelId
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
getTenant() {
|
|
70
|
+
return this.tenantContext.getTenant().id;
|
|
71
|
+
}
|
|
72
|
+
getStore() {
|
|
73
|
+
return createDeleteModelStore(this.keyValueStore, this.getTenant());
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const DeleteModelOperationsImplementation = DeleteModelOperations.createImplementation({
|
|
77
|
+
implementation: DeleteModelOperationsImpl,
|
|
78
|
+
dependencies: [
|
|
79
|
+
TenantContext,
|
|
80
|
+
GlobalKeyValueStore,
|
|
81
|
+
IdentityContext,
|
|
82
|
+
GetModelUseCase,
|
|
83
|
+
AccessControl,
|
|
84
|
+
TriggerTaskUseCase,
|
|
85
|
+
GetTaskUseCase,
|
|
86
|
+
AbortTaskUseCase
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
export { DeleteModelOperationsImplementation };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=DeleteModelOperationsImpl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/DeleteModelOperationsImpl.js","sources":["../../../src/graphql/deleteModel/DeleteModelOperationsImpl.ts"],"sourcesContent":["import { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/abstractions.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport { createCacheKey, createMemoryCache } from \"@webiny/api-headless-cms/utils/index.js\";\nimport { AccessControl } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport { GetModelUseCase } from \"@webiny/api-headless-cms/features/contentModel/GetModel/index.js\";\nimport { AbortTaskUseCase, GetTaskUseCase, TriggerTaskUseCase } from \"@webiny/background-tasks/api\";\nimport type { IStoreValue } from \"~/features/DeleteModelTask/types.js\";\nimport { createDeleteModelStore } from \"~/helpers/store.js\";\nimport { fullyDeleteModel } from \"~/graphql/deleteModel/fullyDeleteModel.js\";\nimport { cancelDeleteModel } from \"~/graphql/deleteModel/cancelDeleteModel.js\";\nimport { getDeleteModelProgress } from \"~/graphql/deleteModel/getDeleteModelProgress.js\";\nimport { DeleteModelOperations } from \"~/graphql/deleteModel/abstractions.js\";\n\n/**\n * Delete-model operations, previously assembled inside a `RequestContextInitializer`\n * (`createDeleteModelCrud`) from closures over the request context.\n *\n * Nothing here needed a per-request hook: every member is already async, and the tenant is read\n * lazily at call time rather than at construction. As an ordinary DI implementation it is\n * sync-constructible, which also lets `DisableModelFeature` keep resolving it at register time.\n *\n * The in-memory cache is KEPT. Unlike the CMS model providers — where `ModelsFetcher`/`ModelCache`\n * already cached a layer down — nothing caches these key-value reads, so without it every\n * `isModelBeingDeleted()` check would hit the store. It is cleared on mutation, as before.\n */\nclass DeleteModelOperationsImpl implements DeleteModelOperations.Interface {\n private readonly cache = createMemoryCache<Promise<IStoreValue[]>>();\n\n constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly keyValueStore: GlobalKeyValueStore.Interface,\n private readonly identityContext: IdentityContext.Interface,\n private readonly getModel: GetModelUseCase.Interface,\n private readonly accessControl: AccessControl.Interface,\n private readonly triggerTask: TriggerTaskUseCase.Interface,\n private readonly getTask: GetTaskUseCase.Interface,\n private readonly abortTask: AbortTaskUseCase.Interface\n ) {}\n\n async listModelsBeingDeleted(): Promise<IStoreValue[]> {\n const cacheKey = createCacheKey({ tenant: this.getTenant(), type: \"deleteModel\" });\n return this.cache.getOrSet(cacheKey, () => this.getStore().list());\n }\n\n async isModelBeingDeleted(modelId: string): Promise<boolean> {\n const items = await this.listModelsBeingDeleted();\n return items.some(item => item.modelId === modelId);\n }\n\n async fullyDeleteModel(modelId: string) {\n const result = await fullyDeleteModel({\n getModel: this.getModel,\n accessControl: this.accessControl,\n keyValueStore: this.keyValueStore,\n triggerTask: this.triggerTask,\n identityContext: this.identityContext,\n modelId\n });\n this.cache.clear();\n return result;\n }\n\n async cancelFullyDeleteModel(modelId: string) {\n const result = await cancelDeleteModel({\n getModel: this.getModel,\n accessControl: this.accessControl,\n keyValueStore: this.keyValueStore,\n getTask: this.getTask,\n abortTask: this.abortTask,\n modelId\n });\n this.cache.clear();\n return result;\n }\n\n async getDeleteModelProgress(modelId: string) {\n return getDeleteModelProgress({\n getModel: this.getModel,\n accessControl: this.accessControl,\n keyValueStore: this.keyValueStore,\n getTask: this.getTask,\n modelId\n });\n }\n\n private getTenant(): string {\n return this.tenantContext.getTenant().id;\n }\n\n private getStore() {\n return createDeleteModelStore(this.keyValueStore, this.getTenant());\n }\n}\n\nexport const DeleteModelOperationsImplementation = DeleteModelOperations.createImplementation({\n implementation: DeleteModelOperationsImpl,\n dependencies: [\n TenantContext,\n GlobalKeyValueStore,\n IdentityContext,\n GetModelUseCase,\n AccessControl,\n TriggerTaskUseCase,\n GetTaskUseCase,\n AbortTaskUseCase\n ]\n});\n"],"names":["DeleteModelOperationsImpl","tenantContext","keyValueStore","identityContext","getModel","accessControl","triggerTask","getTask","abortTask","createMemoryCache","cacheKey","createCacheKey","modelId","items","item","result","fullyDeleteModel","cancelDeleteModel","getDeleteModelProgress","createDeleteModelStore","DeleteModelOperationsImplementation","DeleteModelOperations","TenantContext","GlobalKeyValueStore","IdentityContext","GetModelUseCase","AccessControl","TriggerTaskUseCase","GetTaskUseCase","AbortTaskUseCase"],"mappings":";;;;;;;;;;;;AA0BA,MAAMA;IAGF,YACqBC,aAAsC,EACtCC,aAA4C,EAC5CC,eAA0C,EAC1CC,QAAmC,EACnCC,aAAsC,EACtCC,WAAyC,EACzCC,OAAiC,EACjCC,SAAqC,CACxD;aARmBP,aAAa,GAAbA;aACAC,aAAa,GAAbA;aACAC,eAAe,GAAfA;aACAC,QAAQ,GAARA;aACAC,aAAa,GAAbA;aACAC,WAAW,GAAXA;aACAC,OAAO,GAAPA;aACAC,SAAS,GAATA;aAVJ,KAAK,GAAGC;IAWtB;IAEH,MAAM,yBAAiD;QACnD,MAAMC,WAAWC,eAAe;YAAE,QAAQ,IAAI,CAAC,SAAS;YAAI,MAAM;QAAc;QAChF,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAACD,UAAU,IAAM,IAAI,CAAC,QAAQ,GAAG,IAAI;IACnE;IAEA,MAAM,oBAAoBE,OAAe,EAAoB;QACzD,MAAMC,QAAQ,MAAM,IAAI,CAAC,sBAAsB;QAC/C,OAAOA,MAAM,IAAI,CAACC,CAAAA,OAAQA,KAAK,OAAO,KAAKF;IAC/C;IAEA,MAAM,iBAAiBA,OAAe,EAAE;QACpC,MAAMG,SAAS,MAAMC,iBAAiB;YAClC,UAAU,IAAI,CAAC,QAAQ;YACvB,eAAe,IAAI,CAAC,aAAa;YACjC,eAAe,IAAI,CAAC,aAAa;YACjC,aAAa,IAAI,CAAC,WAAW;YAC7B,iBAAiB,IAAI,CAAC,eAAe;YACrCJ;QACJ;QACA,IAAI,CAAC,KAAK,CAAC,KAAK;QAChB,OAAOG;IACX;IAEA,MAAM,uBAAuBH,OAAe,EAAE;QAC1C,MAAMG,SAAS,MAAME,kBAAkB;YACnC,UAAU,IAAI,CAAC,QAAQ;YACvB,eAAe,IAAI,CAAC,aAAa;YACjC,eAAe,IAAI,CAAC,aAAa;YACjC,SAAS,IAAI,CAAC,OAAO;YACrB,WAAW,IAAI,CAAC,SAAS;YACzBL;QACJ;QACA,IAAI,CAAC,KAAK,CAAC,KAAK;QAChB,OAAOG;IACX;IAEA,MAAM,uBAAuBH,OAAe,EAAE;QAC1C,OAAOM,uBAAuB;YAC1B,UAAU,IAAI,CAAC,QAAQ;YACvB,eAAe,IAAI,CAAC,aAAa;YACjC,eAAe,IAAI,CAAC,aAAa;YACjC,SAAS,IAAI,CAAC,OAAO;YACrBN;QACJ;IACJ;IAEQ,YAAoB;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,GAAG,EAAE;IAC5C;IAEQ,WAAW;QACf,OAAOO,uBAAuB,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS;IACpE;AACJ;AAEO,MAAMC,sCAAsCC,sBAAsB,oBAAoB,CAAC;IAC1F,gBAAgBrB;IAChB,cAAc;QACVsB;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CmsModel } from "@webiny/api-headless-cms/types/index.js";
|
|
2
|
+
import type { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
3
|
+
export interface IAssertModelDeletableParams {
|
|
4
|
+
readonly accessControl: AccessControl.Interface;
|
|
5
|
+
readonly model: CmsModel;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The access checks every delete-model operation makes: delete on the model, write on its entries.
|
|
9
|
+
* All three operations ran this same pair inline.
|
|
10
|
+
*/
|
|
11
|
+
export declare const assertModelDeletable: (params: IAssertModelDeletableParams) => Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NotAuthorizedError } from "@webiny/api-headless-cms/utils/errors.js";
|
|
2
|
+
const assertModelDeletable = async (params)=>{
|
|
3
|
+
const { accessControl, model } = params;
|
|
4
|
+
const canAccessModel = await accessControl.canAccessModel({
|
|
5
|
+
model,
|
|
6
|
+
rwd: "d"
|
|
7
|
+
});
|
|
8
|
+
if (!canAccessModel) throw new NotAuthorizedError(`Not allowed to access content model "${model.name}".`);
|
|
9
|
+
const canAccessEntry = await accessControl.canAccessEntry({
|
|
10
|
+
model,
|
|
11
|
+
rwd: "w"
|
|
12
|
+
});
|
|
13
|
+
if (!canAccessEntry) throw new NotAuthorizedError(`Not allowed to access "${model.modelId}" entries.`);
|
|
14
|
+
};
|
|
15
|
+
export { assertModelDeletable };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=assertModelDeletable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/assertModelDeletable.js","sources":["../../../src/graphql/deleteModel/assertModelDeletable.ts"],"sourcesContent":["import type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport { NotAuthorizedError } from \"@webiny/api-headless-cms/utils/errors.js\";\nimport type { AccessControl } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\n\nexport interface IAssertModelDeletableParams {\n readonly accessControl: AccessControl.Interface;\n readonly model: CmsModel;\n}\n\n/**\n * The access checks every delete-model operation makes: delete on the model, write on its entries.\n * All three operations ran this same pair inline.\n */\nexport const assertModelDeletable = async (params: IAssertModelDeletableParams): Promise<void> => {\n const { accessControl, model } = params;\n\n const canAccessModel = await accessControl.canAccessModel({ model, rwd: \"d\" });\n if (!canAccessModel) {\n throw new NotAuthorizedError(`Not allowed to access content model \"${model.name}\".`);\n }\n\n const canAccessEntry = await accessControl.canAccessEntry({ model, rwd: \"w\" });\n if (!canAccessEntry) {\n throw new NotAuthorizedError(`Not allowed to access \"${model.modelId}\" entries.`);\n }\n};\n"],"names":["assertModelDeletable","params","accessControl","model","canAccessModel","NotAuthorizedError","canAccessEntry"],"mappings":";AAaO,MAAMA,uBAAuB,OAAOC;IACvC,MAAM,EAAEC,aAAa,EAAEC,KAAK,EAAE,GAAGF;IAEjC,MAAMG,iBAAiB,MAAMF,cAAc,cAAc,CAAC;QAAEC;QAAO,KAAK;IAAI;IAC5E,IAAI,CAACC,gBACD,MAAM,IAAIC,mBAAmB,CAAC,qCAAqC,EAAEF,MAAM,IAAI,CAAC,EAAE,CAAC;IAGvF,MAAMG,iBAAiB,MAAMJ,cAAc,cAAc,CAAC;QAAEC;QAAO,KAAK;IAAI;IAC5E,IAAI,CAACG,gBACD,MAAM,IAAID,mBAAmB,CAAC,uBAAuB,EAAEF,MAAM,OAAO,CAAC,UAAU,CAAC;AAExF"}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import type { HcmsTasksContext } from "../../types.js";
|
|
2
1
|
import type { IDeleteCmsModelTask } from "../../features/DeleteModelTask/types.js";
|
|
2
|
+
import type { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
3
|
+
import type { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
4
|
+
import type { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
5
|
+
import type { GetTaskUseCase, AbortTaskUseCase } from "@webiny/background-tasks/api";
|
|
3
6
|
export interface ICancelDeleteModelParams {
|
|
4
|
-
readonly
|
|
7
|
+
readonly getModel: GetModelUseCase.Interface;
|
|
8
|
+
readonly accessControl: AccessControl.Interface;
|
|
9
|
+
readonly keyValueStore: GlobalKeyValueStore.Interface;
|
|
10
|
+
readonly getTask: GetTaskUseCase.Interface;
|
|
11
|
+
readonly abortTask: AbortTaskUseCase.Interface;
|
|
5
12
|
readonly modelId: string;
|
|
6
13
|
}
|
|
7
14
|
export declare const cancelDeleteModel: (params: ICancelDeleteModelParams) => Promise<IDeleteCmsModelTask>;
|
|
@@ -2,28 +2,17 @@ import { WebinyError } from "@webiny/error";
|
|
|
2
2
|
import { createDeleteModelStore } from "../../helpers/store.js";
|
|
3
3
|
import { DELETE_MODEL_TASK } from "../../constants.js";
|
|
4
4
|
import { getStatus } from "./status.js";
|
|
5
|
-
import {
|
|
6
|
-
import { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
7
|
-
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
8
|
-
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
9
|
-
import { AbortTaskUseCase, GetTaskUseCase } from "@webiny/background-tasks/api";
|
|
5
|
+
import { assertModelDeletable } from "./assertModelDeletable.js";
|
|
10
6
|
const cancelDeleteModel = async (params)=>{
|
|
11
|
-
const {
|
|
12
|
-
const modelResult = await
|
|
7
|
+
const { getModel, accessControl, keyValueStore, getTask, abortTask, modelId } = params;
|
|
8
|
+
const modelResult = await getModel.execute(modelId);
|
|
13
9
|
if (modelResult.isFail()) throw modelResult.error;
|
|
14
10
|
const model = modelResult.value;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
model
|
|
18
|
-
rwd: "d"
|
|
11
|
+
await assertModelDeletable({
|
|
12
|
+
accessControl,
|
|
13
|
+
model
|
|
19
14
|
});
|
|
20
|
-
|
|
21
|
-
const canAccessEntry = await accessControl.canAccessEntry({
|
|
22
|
-
model,
|
|
23
|
-
rwd: "w"
|
|
24
|
-
});
|
|
25
|
-
if (!canAccessEntry) throw new NotAuthorizedError(`Not allowed to access "${model.modelId}" entries.`);
|
|
26
|
-
const store = createDeleteModelStore(context.container.resolve(GlobalKeyValueStore), model.tenant);
|
|
15
|
+
const store = createDeleteModelStore(keyValueStore, model.tenant);
|
|
27
16
|
const existing = await store.get(model.modelId);
|
|
28
17
|
const taskId = existing?.task;
|
|
29
18
|
await store.remove(model.modelId);
|
|
@@ -31,7 +20,7 @@ const cancelDeleteModel = async (params)=>{
|
|
|
31
20
|
message: `Model "${modelId}" is not being deleted.`,
|
|
32
21
|
code: "MODEL_NOT_BEING_DELETED"
|
|
33
22
|
});
|
|
34
|
-
const task = await
|
|
23
|
+
const task = await getTask.execute(taskId);
|
|
35
24
|
if (task?.definitionId !== DELETE_MODEL_TASK) throw new WebinyError({
|
|
36
25
|
message: `The task which is deleting a model cannot be found. Please check Step Functions for more info. Task id: ${taskId}`,
|
|
37
26
|
code: "DELETE_MODEL_TASK_NOT_FOUND",
|
|
@@ -40,7 +29,7 @@ const cancelDeleteModel = async (params)=>{
|
|
|
40
29
|
task: taskId
|
|
41
30
|
}
|
|
42
31
|
});
|
|
43
|
-
const abortResult = await
|
|
32
|
+
const abortResult = await abortTask.execute({
|
|
44
33
|
id: task.id,
|
|
45
34
|
message: "User canceled the task."
|
|
46
35
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql/deleteModel/cancelDeleteModel.js","sources":["../../../src/graphql/deleteModel/cancelDeleteModel.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/cancelDeleteModel.js","sources":["../../../src/graphql/deleteModel/cancelDeleteModel.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport type {\n IDeleteCmsModelTask,\n IDeleteModelTaskInput,\n IDeleteModelTaskOutput\n} from \"~/features/DeleteModelTask/types.js\";\nimport { createDeleteModelStore } from \"~/helpers/store.js\";\nimport { DELETE_MODEL_TASK } from \"~/constants.js\";\nimport { getStatus } from \"~/graphql/deleteModel/status.js\";\nimport { assertModelDeletable } from \"~/graphql/deleteModel/assertModelDeletable.js\";\nimport type { AccessControl } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport type { GetModelUseCase } from \"@webiny/api-headless-cms/features/contentModel/GetModel/index.js\";\nimport type { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { GetTaskUseCase, AbortTaskUseCase } from \"@webiny/background-tasks/api\";\n\nexport interface ICancelDeleteModelParams {\n readonly getModel: GetModelUseCase.Interface;\n readonly accessControl: AccessControl.Interface;\n readonly keyValueStore: GlobalKeyValueStore.Interface;\n readonly getTask: GetTaskUseCase.Interface;\n readonly abortTask: AbortTaskUseCase.Interface;\n readonly modelId: string;\n}\n\nexport const cancelDeleteModel = async (\n params: ICancelDeleteModelParams\n): Promise<IDeleteCmsModelTask> => {\n const { getModel, accessControl, keyValueStore, getTask, abortTask, modelId } = params;\n\n const modelResult = await getModel.execute(modelId);\n if (modelResult.isFail()) {\n throw modelResult.error;\n }\n const model = modelResult.value;\n\n await assertModelDeletable({ accessControl, model });\n\n const store = createDeleteModelStore(keyValueStore, model.tenant);\n const existing = await store.get(model.modelId);\n const taskId = existing?.task;\n\n await store.remove(model.modelId);\n if (!taskId) {\n throw new WebinyError({\n message: `Model \"${modelId}\" is not being deleted.`,\n code: \"MODEL_NOT_BEING_DELETED\"\n });\n }\n\n const task = await getTask.execute<IDeleteModelTaskInput, IDeleteModelTaskOutput>(taskId);\n if (task?.definitionId !== DELETE_MODEL_TASK) {\n throw new WebinyError({\n message: `The task which is deleting a model cannot be found. Please check Step Functions for more info. Task id: ${taskId}`,\n code: \"DELETE_MODEL_TASK_NOT_FOUND\",\n data: {\n model: model.modelId,\n task: taskId\n }\n });\n }\n\n const abortResult = await abortTask.execute<IDeleteModelTaskInput, IDeleteModelTaskOutput>({\n id: task.id,\n message: \"User canceled the task.\"\n });\n\n const canceledTask = abortResult.value;\n\n return {\n id: canceledTask.id,\n status: getStatus(canceledTask.taskStatus),\n total: canceledTask.output?.total || 0,\n deleted: canceledTask.output?.deleted || 0\n };\n};\n"],"names":["cancelDeleteModel","params","getModel","accessControl","keyValueStore","getTask","abortTask","modelId","modelResult","model","assertModelDeletable","store","createDeleteModelStore","existing","taskId","WebinyError","task","DELETE_MODEL_TASK","abortResult","canceledTask","getStatus"],"mappings":";;;;;AAwBO,MAAMA,oBAAoB,OAC7BC;IAEA,MAAM,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,aAAa,EAAEC,OAAO,EAAEC,SAAS,EAAEC,OAAO,EAAE,GAAGN;IAEhF,MAAMO,cAAc,MAAMN,SAAS,OAAO,CAACK;IAC3C,IAAIC,YAAY,MAAM,IAClB,MAAMA,YAAY,KAAK;IAE3B,MAAMC,QAAQD,YAAY,KAAK;IAE/B,MAAME,qBAAqB;QAAEP;QAAeM;IAAM;IAElD,MAAME,QAAQC,uBAAuBR,eAAeK,MAAM,MAAM;IAChE,MAAMI,WAAW,MAAMF,MAAM,GAAG,CAACF,MAAM,OAAO;IAC9C,MAAMK,SAASD,UAAU;IAEzB,MAAMF,MAAM,MAAM,CAACF,MAAM,OAAO;IAChC,IAAI,CAACK,QACD,MAAM,IAAIC,YAAY;QAClB,SAAS,CAAC,OAAO,EAAER,QAAQ,uBAAuB,CAAC;QACnD,MAAM;IACV;IAGJ,MAAMS,OAAO,MAAMX,QAAQ,OAAO,CAAgDS;IAClF,IAAIE,MAAM,iBAAiBC,mBACvB,MAAM,IAAIF,YAAY;QAClB,SAAS,CAAC,wGAAwG,EAAED,QAAQ;QAC5H,MAAM;QACN,MAAM;YACF,OAAOL,MAAM,OAAO;YACpB,MAAMK;QACV;IACJ;IAGJ,MAAMI,cAAc,MAAMZ,UAAU,OAAO,CAAgD;QACvF,IAAIU,KAAK,EAAE;QACX,SAAS;IACb;IAEA,MAAMG,eAAeD,YAAY,KAAK;IAEtC,OAAO;QACH,IAAIC,aAAa,EAAE;QACnB,QAAQC,UAAUD,aAAa,UAAU;QACzC,OAAOA,aAAa,MAAM,EAAE,SAAS;QACrC,SAASA,aAAa,MAAM,EAAE,WAAW;IAC7C;AACJ"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
2
2
|
import type { IDeleteCmsModelTask } from "../../features/DeleteModelTask/types.js";
|
|
3
|
+
import type { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
4
|
+
import type { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
5
|
+
import type { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
6
|
+
import type { TriggerTaskUseCase } from "@webiny/background-tasks/api";
|
|
3
7
|
export interface IFullyDeleteModelParams {
|
|
4
|
-
readonly
|
|
8
|
+
readonly getModel: GetModelUseCase.Interface;
|
|
9
|
+
readonly accessControl: AccessControl.Interface;
|
|
10
|
+
readonly keyValueStore: GlobalKeyValueStore.Interface;
|
|
11
|
+
readonly triggerTask: TriggerTaskUseCase.Interface;
|
|
12
|
+
readonly identityContext: IdentityContext.Interface;
|
|
5
13
|
readonly modelId: string;
|
|
6
14
|
}
|
|
7
15
|
export declare const fullyDeleteModel: (params: IFullyDeleteModelParams) => Promise<IDeleteCmsModelTask>;
|
|
@@ -1,34 +1,21 @@
|
|
|
1
|
-
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
2
1
|
import { createDeleteModelStore, createStoreValue } from "../../helpers/store.js";
|
|
3
2
|
import { DELETE_MODEL_TASK } from "../../constants.js";
|
|
4
3
|
import { getStatus } from "./status.js";
|
|
5
|
-
import {
|
|
6
|
-
import { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
7
|
-
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
8
|
-
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
9
|
-
import { TriggerTaskUseCase } from "@webiny/background-tasks/api";
|
|
4
|
+
import { assertModelDeletable } from "./assertModelDeletable.js";
|
|
10
5
|
const fullyDeleteModel = async (params)=>{
|
|
11
|
-
const {
|
|
12
|
-
const modelResult = await
|
|
6
|
+
const { getModel, accessControl, keyValueStore, triggerTask, identityContext, modelId } = params;
|
|
7
|
+
const modelResult = await getModel.execute(modelId);
|
|
13
8
|
if (modelResult.isFail()) throw modelResult.error;
|
|
14
9
|
const model = modelResult.value;
|
|
15
10
|
if (model.isPrivate) throw new Error("Cannot delete private model.");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
model
|
|
19
|
-
rwd: "d"
|
|
11
|
+
await assertModelDeletable({
|
|
12
|
+
accessControl,
|
|
13
|
+
model
|
|
20
14
|
});
|
|
21
|
-
|
|
22
|
-
const canAccessEntry = await accessControl.canAccessEntry({
|
|
23
|
-
model,
|
|
24
|
-
rwd: "w"
|
|
25
|
-
});
|
|
26
|
-
if (!canAccessEntry) throw new NotAuthorizedError(`Not allowed to access "${model.modelId}" entries.`);
|
|
27
|
-
if (!model) throw new Error(`Model "${modelId}" not found.`);
|
|
28
|
-
const store = createDeleteModelStore(context.container.resolve(GlobalKeyValueStore), model.tenant);
|
|
15
|
+
const store = createDeleteModelStore(keyValueStore, model.tenant);
|
|
29
16
|
const existing = await store.get(model.modelId);
|
|
30
17
|
if (existing?.task) throw new Error(`Model "${modelId}" is already getting deleted. Task id: ${existing.task}.`);
|
|
31
|
-
const triggerResult = await
|
|
18
|
+
const triggerResult = await triggerTask.execute({
|
|
32
19
|
input: {
|
|
33
20
|
modelId
|
|
34
21
|
},
|
|
@@ -36,7 +23,7 @@ const fullyDeleteModel = async (params)=>{
|
|
|
36
23
|
name: `Fully delete model: ${modelId}`
|
|
37
24
|
});
|
|
38
25
|
const task = triggerResult.value;
|
|
39
|
-
const identity =
|
|
26
|
+
const identity = identityContext.getIdentity();
|
|
40
27
|
await store.set(createStoreValue({
|
|
41
28
|
...model,
|
|
42
29
|
identity: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql/deleteModel/fullyDeleteModel.js","sources":["../../../src/graphql/deleteModel/fullyDeleteModel.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/fullyDeleteModel.js","sources":["../../../src/graphql/deleteModel/fullyDeleteModel.ts"],"sourcesContent":["import type { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport type {\n IDeleteCmsModelTask,\n IDeleteModelTaskInput\n} from \"~/features/DeleteModelTask/types.js\";\nimport { createDeleteModelStore, createStoreValue } from \"~/helpers/store.js\";\nimport { DELETE_MODEL_TASK } from \"~/constants.js\";\nimport { getStatus } from \"~/graphql/deleteModel/status.js\";\nimport { assertModelDeletable } from \"~/graphql/deleteModel/assertModelDeletable.js\";\nimport type { AccessControl } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport type { GetModelUseCase } from \"@webiny/api-headless-cms/features/contentModel/GetModel/index.js\";\nimport type { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { TriggerTaskUseCase } from \"@webiny/background-tasks/api\";\n\nexport interface IFullyDeleteModelParams {\n readonly getModel: GetModelUseCase.Interface;\n readonly accessControl: AccessControl.Interface;\n readonly keyValueStore: GlobalKeyValueStore.Interface;\n readonly triggerTask: TriggerTaskUseCase.Interface;\n readonly identityContext: IdentityContext.Interface;\n readonly modelId: string;\n}\n\nexport const fullyDeleteModel = async (\n params: IFullyDeleteModelParams\n): Promise<IDeleteCmsModelTask> => {\n const { getModel, accessControl, keyValueStore, triggerTask, identityContext, modelId } =\n params;\n\n const modelResult = await getModel.execute(modelId);\n if (modelResult.isFail()) {\n throw modelResult.error;\n }\n const model = modelResult.value;\n\n if (model.isPrivate) {\n throw new Error(`Cannot delete private model.`);\n }\n\n await assertModelDeletable({ accessControl, model });\n\n const store = createDeleteModelStore(keyValueStore, model.tenant);\n const existing = await store.get(model.modelId);\n if (existing?.task) {\n throw new Error(\n `Model \"${modelId}\" is already getting deleted. Task id: ${existing.task}.`\n );\n }\n\n const triggerResult = await triggerTask.execute<IDeleteModelTaskInput>({\n input: {\n modelId\n },\n definition: DELETE_MODEL_TASK,\n name: `Fully delete model: ${modelId}`\n });\n\n const task = triggerResult.value;\n\n const identity = identityContext.getIdentity();\n\n await store.set(\n createStoreValue({\n ...model,\n identity: {\n id: identity.id,\n type: identity.type,\n displayName: identity.displayName\n },\n task: task.id\n })\n );\n\n return {\n id: task.id,\n status: getStatus(task.taskStatus),\n total: 0,\n deleted: 0\n };\n};\n"],"names":["fullyDeleteModel","params","getModel","accessControl","keyValueStore","triggerTask","identityContext","modelId","modelResult","model","Error","assertModelDeletable","store","createDeleteModelStore","existing","triggerResult","DELETE_MODEL_TASK","task","identity","createStoreValue","getStatus"],"mappings":";;;;AAuBO,MAAMA,mBAAmB,OAC5BC;IAEA,MAAM,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,aAAa,EAAEC,WAAW,EAAEC,eAAe,EAAEC,OAAO,EAAE,GACnFN;IAEJ,MAAMO,cAAc,MAAMN,SAAS,OAAO,CAACK;IAC3C,IAAIC,YAAY,MAAM,IAClB,MAAMA,YAAY,KAAK;IAE3B,MAAMC,QAAQD,YAAY,KAAK;IAE/B,IAAIC,MAAM,SAAS,EACf,MAAM,IAAIC,MAAM;IAGpB,MAAMC,qBAAqB;QAAER;QAAeM;IAAM;IAElD,MAAMG,QAAQC,uBAAuBT,eAAeK,MAAM,MAAM;IAChE,MAAMK,WAAW,MAAMF,MAAM,GAAG,CAACH,MAAM,OAAO;IAC9C,IAAIK,UAAU,MACV,MAAM,IAAIJ,MACN,CAAC,OAAO,EAAEH,QAAQ,uCAAuC,EAAEO,SAAS,IAAI,CAAC,CAAC,CAAC;IAInF,MAAMC,gBAAgB,MAAMV,YAAY,OAAO,CAAwB;QACnE,OAAO;YACHE;QACJ;QACA,YAAYS;QACZ,MAAM,CAAC,oBAAoB,EAAET,SAAS;IAC1C;IAEA,MAAMU,OAAOF,cAAc,KAAK;IAEhC,MAAMG,WAAWZ,gBAAgB,WAAW;IAE5C,MAAMM,MAAM,GAAG,CACXO,iBAAiB;QACb,GAAGV,KAAK;QACR,UAAU;YACN,IAAIS,SAAS,EAAE;YACf,MAAMA,SAAS,IAAI;YACnB,aAAaA,SAAS,WAAW;QACrC;QACA,MAAMD,KAAK,EAAE;IACjB;IAGJ,OAAO;QACH,IAAIA,KAAK,EAAE;QACX,QAAQG,UAAUH,KAAK,UAAU;QACjC,OAAO;QACP,SAAS;IACb;AACJ"}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import type { HcmsTasksContext } from "../../types.js";
|
|
2
1
|
import type { IDeleteCmsModelTask } from "../../features/DeleteModelTask/types.js";
|
|
2
|
+
import type { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
3
|
+
import type { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
4
|
+
import type { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
5
|
+
import type { GetTaskUseCase } from "@webiny/background-tasks/api";
|
|
3
6
|
export interface IGetDeleteModelProgress {
|
|
4
|
-
readonly
|
|
7
|
+
readonly getModel: GetModelUseCase.Interface;
|
|
8
|
+
readonly accessControl: AccessControl.Interface;
|
|
9
|
+
readonly keyValueStore: GlobalKeyValueStore.Interface;
|
|
10
|
+
readonly getTask: GetTaskUseCase.Interface;
|
|
5
11
|
readonly modelId: string;
|
|
6
12
|
}
|
|
7
13
|
export declare const getDeleteModelProgress: (params: IGetDeleteModelProgress) => Promise<IDeleteCmsModelTask>;
|
|
@@ -3,16 +3,12 @@ import { NotFoundError } from "@webiny/api-graphql";
|
|
|
3
3
|
import { createDeleteModelStore } from "../../helpers/store.js";
|
|
4
4
|
import { DELETE_MODEL_TASK } from "../../constants.js";
|
|
5
5
|
import { getStatus } from "./status.js";
|
|
6
|
-
import {
|
|
7
|
-
import { AccessControl } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
8
|
-
import { GetModelUseCase } from "@webiny/api-headless-cms/features/contentModel/GetModel/index.js";
|
|
9
|
-
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
10
|
-
import { GetTaskUseCase } from "@webiny/background-tasks/api";
|
|
6
|
+
import { assertModelDeletable } from "./assertModelDeletable.js";
|
|
11
7
|
const getDeleteModelProgress = async (params)=>{
|
|
12
|
-
const {
|
|
8
|
+
const { getModel, accessControl, keyValueStore, getTask, modelId } = params;
|
|
13
9
|
let model;
|
|
14
10
|
try {
|
|
15
|
-
const modelResult = await
|
|
11
|
+
const modelResult = await getModel.execute(modelId);
|
|
16
12
|
if (modelResult.isFail()) throw modelResult.error;
|
|
17
13
|
model = modelResult.value;
|
|
18
14
|
} catch (ex) {
|
|
@@ -25,22 +21,15 @@ const getDeleteModelProgress = async (params)=>{
|
|
|
25
21
|
}
|
|
26
22
|
});
|
|
27
23
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
model
|
|
31
|
-
rwd: "d"
|
|
24
|
+
await assertModelDeletable({
|
|
25
|
+
accessControl,
|
|
26
|
+
model
|
|
32
27
|
});
|
|
33
|
-
|
|
34
|
-
const canAccessEntry = await accessControl.canAccessEntry({
|
|
35
|
-
model,
|
|
36
|
-
rwd: "w"
|
|
37
|
-
});
|
|
38
|
-
if (!canAccessEntry) throw new NotAuthorizedError(`Not allowed to access "${model.modelId}" entries.`);
|
|
39
|
-
const store = createDeleteModelStore(context.container.resolve(GlobalKeyValueStore), model.tenant);
|
|
28
|
+
const store = createDeleteModelStore(keyValueStore, model.tenant);
|
|
40
29
|
const existing = await store.get(model.modelId);
|
|
41
30
|
const taskId = existing?.task;
|
|
42
31
|
if (!taskId) throw new Error(`Model "${modelId}" is not being deleted.`);
|
|
43
|
-
const task = await
|
|
32
|
+
const task = await getTask.execute(taskId);
|
|
44
33
|
if (task?.definitionId !== DELETE_MODEL_TASK) throw new WebinyError({
|
|
45
34
|
message: "The task which is deleting a model cannot be found.",
|
|
46
35
|
code: "DELETE_MODEL_TASK_NOT_FOUND",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql/deleteModel/getDeleteModelProgress.js","sources":["../../../src/graphql/deleteModel/getDeleteModelProgress.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/getDeleteModelProgress.js","sources":["../../../src/graphql/deleteModel/getDeleteModelProgress.ts"],"sourcesContent":["import { WebinyError } from \"@webiny/error\";\nimport { NotFoundError } from \"@webiny/api-graphql\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport type {\n IDeleteCmsModelTask,\n IDeleteModelTaskInput,\n IDeleteModelTaskOutput\n} from \"~/features/DeleteModelTask/types.js\";\nimport { createDeleteModelStore } from \"~/helpers/store.js\";\nimport { DELETE_MODEL_TASK } from \"~/constants.js\";\nimport { getStatus } from \"~/graphql/deleteModel/status.js\";\nimport { assertModelDeletable } from \"~/graphql/deleteModel/assertModelDeletable.js\";\nimport type { AccessControl } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport type { GetModelUseCase } from \"@webiny/api-headless-cms/features/contentModel/GetModel/index.js\";\nimport type { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { GetTaskUseCase } from \"@webiny/background-tasks/api\";\n\nexport interface IGetDeleteModelProgress {\n readonly getModel: GetModelUseCase.Interface;\n readonly accessControl: AccessControl.Interface;\n readonly keyValueStore: GlobalKeyValueStore.Interface;\n readonly getTask: GetTaskUseCase.Interface;\n readonly modelId: string;\n}\n\nexport const getDeleteModelProgress = async (\n params: IGetDeleteModelProgress\n): Promise<IDeleteCmsModelTask> => {\n const { getModel, accessControl, keyValueStore, getTask, modelId } = params;\n\n let model: CmsModel;\n try {\n const modelResult = await getModel.execute(modelId);\n if (modelResult.isFail()) {\n throw modelResult.error;\n }\n model = modelResult.value;\n } catch (ex) {\n if (ex instanceof NotFoundError === false) {\n throw ex;\n }\n throw new WebinyError({\n message: \"Model not found. It must have been deleted already.\",\n code: \"MODEL_ALREADY_DELETED_FOUND\",\n data: {\n model: modelId\n }\n });\n }\n\n await assertModelDeletable({ accessControl, model });\n\n const store = createDeleteModelStore(keyValueStore, model.tenant);\n const existing = await store.get(model.modelId);\n\n const taskId = existing?.task;\n if (!taskId) {\n throw new Error(`Model \"${modelId}\" is not being deleted.`);\n }\n\n const task = await getTask.execute<IDeleteModelTaskInput, IDeleteModelTaskOutput>(taskId);\n if (task?.definitionId !== DELETE_MODEL_TASK) {\n throw new WebinyError({\n message: `The task which is deleting a model cannot be found.`,\n code: \"DELETE_MODEL_TASK_NOT_FOUND\",\n data: {\n model: model.modelId,\n task: taskId\n }\n });\n }\n return {\n id: task.id,\n status: getStatus(task.taskStatus),\n total: task.output?.total || 0,\n deleted: task.output?.deleted || 0\n };\n};\n"],"names":["getDeleteModelProgress","params","getModel","accessControl","keyValueStore","getTask","modelId","model","modelResult","ex","NotFoundError","WebinyError","assertModelDeletable","store","createDeleteModelStore","existing","taskId","Error","task","DELETE_MODEL_TASK","getStatus"],"mappings":";;;;;;AAyBO,MAAMA,yBAAyB,OAClCC;IAEA,MAAM,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,aAAa,EAAEC,OAAO,EAAEC,OAAO,EAAE,GAAGL;IAErE,IAAIM;IACJ,IAAI;QACA,MAAMC,cAAc,MAAMN,SAAS,OAAO,CAACI;QAC3C,IAAIE,YAAY,MAAM,IAClB,MAAMA,YAAY,KAAK;QAE3BD,QAAQC,YAAY,KAAK;IAC7B,EAAE,OAAOC,IAAI;QACT,IAAIA,cAAcC,kBAAkB,OAChC,MAAMD;QAEV,MAAM,IAAIE,YAAY;YAClB,SAAS;YACT,MAAM;YACN,MAAM;gBACF,OAAOL;YACX;QACJ;IACJ;IAEA,MAAMM,qBAAqB;QAAET;QAAeI;IAAM;IAElD,MAAMM,QAAQC,uBAAuBV,eAAeG,MAAM,MAAM;IAChE,MAAMQ,WAAW,MAAMF,MAAM,GAAG,CAACN,MAAM,OAAO;IAE9C,MAAMS,SAASD,UAAU;IACzB,IAAI,CAACC,QACD,MAAM,IAAIC,MAAM,CAAC,OAAO,EAAEX,QAAQ,uBAAuB,CAAC;IAG9D,MAAMY,OAAO,MAAMb,QAAQ,OAAO,CAAgDW;IAClF,IAAIE,MAAM,iBAAiBC,mBACvB,MAAM,IAAIR,YAAY;QAClB,SAAS;QACT,MAAM;QACN,MAAM;YACF,OAAOJ,MAAM,OAAO;YACpB,MAAMS;QACV;IACJ;IAEJ,OAAO;QACH,IAAIE,KAAK,EAAE;QACX,QAAQE,UAAUF,KAAK,UAAU;QACjC,OAAOA,KAAK,MAAM,EAAE,SAAS;QAC7B,SAASA,KAAK,MAAM,EAAE,WAAW;IACrC;AACJ"}
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
2
|
+
import { Logger } from "@webiny/api-core/features/logger/index.js";
|
|
3
|
+
import { CmsGraphQLSchemaPlugin, CmsGraphQLSchemaFactory } from "@webiny/api-headless-cms";
|
|
4
|
+
import { HeadlessCms } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
2
5
|
import type { HcmsTasksContext } from "../../types.js";
|
|
3
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Contributes the fullyDeleteModel schema. Previously a `RequestContextInitializer` that built the
|
|
8
|
+
* plugin and then registered a `CmsGraphQLSchemaFactory` holding it; since `execute()` is already
|
|
9
|
+
* awaited by `generateSchema`, the readiness check and the plugin construction can simply live
|
|
10
|
+
* there instead.
|
|
11
|
+
*/
|
|
12
|
+
declare class DeleteModelGraphQLSchemaFactory implements CmsGraphQLSchemaFactory.Interface {
|
|
13
|
+
private readonly tenantContext;
|
|
14
|
+
private readonly headlessCms;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
constructor(tenantContext: TenantContext.Interface, headlessCms: HeadlessCms.Interface, logger: Logger.Interface);
|
|
17
|
+
execute(): Promise<CmsGraphQLSchemaPlugin<HcmsTasksContext>[]>;
|
|
18
|
+
}
|
|
19
|
+
export declare const DeleteModelGraphQLSchemaFactoryImpl: typeof DeleteModelGraphQLSchemaFactory & {
|
|
20
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-headless-cms").ICmsGraphQLSchemaFactory>;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import zod from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
3
|
+
import { Logger } from "@webiny/api-core/features/logger/index.js";
|
|
4
|
+
import { CmsGraphQLSchemaFactory, CmsGraphQLSchemaPlugin } from "@webiny/api-headless-cms";
|
|
3
5
|
import { HeadlessCms } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
4
6
|
import { DeleteModelOperations } from "./abstractions.js";
|
|
5
7
|
import { ErrorResponse, Response, createResolverDecorator, resolve } from "@webiny/api-graphql";
|
|
@@ -25,12 +27,16 @@ const cancelValidation = zod.object({
|
|
|
25
27
|
const getValidation = zod.object({
|
|
26
28
|
modelId: zod.string()
|
|
27
29
|
}).readonly();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
class DeleteModelGraphQLSchemaFactory {
|
|
31
|
+
constructor(tenantContext, headlessCms, logger){
|
|
32
|
+
this.tenantContext = tenantContext;
|
|
33
|
+
this.headlessCms = headlessCms;
|
|
34
|
+
this.logger = logger;
|
|
35
|
+
}
|
|
36
|
+
async execute() {
|
|
37
|
+
if (!this.tenantContext.getTenant() || !this.headlessCms.MANAGE) return [];
|
|
38
|
+
const plugin = new CmsGraphQLSchemaPlugin({
|
|
39
|
+
typeDefs: `
|
|
34
40
|
enum DeleteCmsModelTaskStatus {
|
|
35
41
|
running
|
|
36
42
|
done
|
|
@@ -78,66 +84,75 @@ const createDeleteModelGraphQl = ()=>({
|
|
|
78
84
|
cancelFullyDeleteModel(modelId: ID!): CancelDeleteCmsModelResponse!
|
|
79
85
|
}
|
|
80
86
|
`,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
resolvers: {
|
|
88
|
+
CmsContentModel: {
|
|
89
|
+
isBeingDeleted: async (model, _, context)=>{
|
|
90
|
+
try {
|
|
91
|
+
return await context.container.resolve(DeleteModelOperations).isModelBeingDeleted(model.modelId);
|
|
92
|
+
} catch (ex) {
|
|
93
|
+
this.logger.error({
|
|
94
|
+
error: ex,
|
|
95
|
+
modelId: model.modelId
|
|
96
|
+
}, "Failed to read the delete-model status.");
|
|
90
97
|
}
|
|
91
|
-
|
|
92
|
-
Query: {
|
|
93
|
-
getDeleteModelProgress: async (_, args, context)=>resolve(async ()=>{
|
|
94
|
-
const input = getValidation.safeParse(args);
|
|
95
|
-
if (input.error) throw createZodError(input.error);
|
|
96
|
-
return context.container.resolve(DeleteModelOperations).getDeleteModelProgress(input.data.modelId);
|
|
97
|
-
})
|
|
98
|
-
},
|
|
99
|
-
Mutation: {
|
|
100
|
-
fullyDeleteModel: async (_, args, context)=>resolve(async ()=>{
|
|
101
|
-
const input = deleteValidation.safeParse(args);
|
|
102
|
-
if (input.error) throw createZodError(input.error);
|
|
103
|
-
return context.container.resolve(DeleteModelOperations).fullyDeleteModel(input.data.modelId);
|
|
104
|
-
}),
|
|
105
|
-
cancelFullyDeleteModel: async (_, args, context)=>resolve(async ()=>{
|
|
106
|
-
const input = cancelValidation.safeParse(args);
|
|
107
|
-
if (input.error) throw createZodError(input.error);
|
|
108
|
-
return context.container.resolve(DeleteModelOperations).cancelFullyDeleteModel(input.data.modelId);
|
|
109
|
-
})
|
|
98
|
+
return true;
|
|
110
99
|
}
|
|
111
100
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
]
|
|
101
|
+
Query: {
|
|
102
|
+
getDeleteModelProgress: async (_, args, context)=>resolve(async ()=>{
|
|
103
|
+
const input = getValidation.safeParse(args);
|
|
104
|
+
if (input.error) throw createZodError(input.error);
|
|
105
|
+
return context.container.resolve(DeleteModelOperations).getDeleteModelProgress(input.data.modelId);
|
|
106
|
+
})
|
|
107
|
+
},
|
|
108
|
+
Mutation: {
|
|
109
|
+
fullyDeleteModel: async (_, args, context)=>resolve(async ()=>{
|
|
110
|
+
const input = deleteValidation.safeParse(args);
|
|
111
|
+
if (input.error) throw createZodError(input.error);
|
|
112
|
+
return context.container.resolve(DeleteModelOperations).fullyDeleteModel(input.data.modelId);
|
|
113
|
+
}),
|
|
114
|
+
cancelFullyDeleteModel: async (_, args, context)=>resolve(async ()=>{
|
|
115
|
+
const input = cancelValidation.safeParse(args);
|
|
116
|
+
if (input.error) throw createZodError(input.error);
|
|
117
|
+
return context.container.resolve(DeleteModelOperations).cancelFullyDeleteModel(input.data.modelId);
|
|
118
|
+
})
|
|
131
119
|
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
},
|
|
121
|
+
resolverDecorators: {
|
|
122
|
+
["Query.listContentModels"]: [
|
|
123
|
+
createResolverDecorator((resolver)=>async (parent, args, context, info)=>{
|
|
124
|
+
const result = await resolver(parent, args, context, info);
|
|
125
|
+
if (result.error || !Array.isArray(result.data)) return result;
|
|
126
|
+
if (args?.includeBeingDeleted !== false) return result;
|
|
127
|
+
const listed = result.data;
|
|
128
|
+
try {
|
|
129
|
+
const beingDeletedList = await context.container.resolve(DeleteModelOperations).listModelsBeingDeleted();
|
|
130
|
+
return new Response(listed.filter((model)=>{
|
|
131
|
+
if (!model?.modelId) return false;
|
|
132
|
+
if (beingDeletedList.some((item)=>item.modelId === model.modelId)) return false;
|
|
133
|
+
return true;
|
|
134
|
+
}));
|
|
135
|
+
} catch (ex) {
|
|
136
|
+
return new ErrorResponse(ex);
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
plugin.name = "headless-cms.graphql.fullyDeleteModel";
|
|
143
|
+
return [
|
|
144
|
+
plugin
|
|
145
|
+
];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const DeleteModelGraphQLSchemaFactoryImpl = CmsGraphQLSchemaFactory.createImplementation({
|
|
149
|
+
implementation: DeleteModelGraphQLSchemaFactory,
|
|
150
|
+
dependencies: [
|
|
151
|
+
TenantContext,
|
|
152
|
+
HeadlessCms,
|
|
153
|
+
Logger
|
|
154
|
+
]
|
|
155
|
+
});
|
|
156
|
+
export { DeleteModelGraphQLSchemaFactoryImpl };
|
|
142
157
|
|
|
143
158
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql/deleteModel/index.js","sources":["../../../src/graphql/deleteModel/index.ts"],"sourcesContent":["import zod from \"zod\";\nimport type { RequestContextInitializer } from \"@webiny/event-handler-core\";\nimport {\n CmsGraphQLSchemaPlugin,\n CmsGraphQLSchemaFactory,\n isHeadlessCmsReady\n} from \"@webiny/api-headless-cms\";\nimport { HeadlessCms } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport { DeleteModelOperations } from \"~/graphql/deleteModel/abstractions.js\";\nimport type { HcmsTasksContext } from \"~/types.js\";\nimport { createResolverDecorator } from \"@webiny/api-graphql\";\nimport { ErrorResponse } from \"@webiny/api-graphql\";\nimport { resolve } from \"@webiny/api-graphql\";\nimport { Response } from \"@webiny/api-graphql\";\nimport { createZodError } from \"@webiny/utils\";\nimport type { IDeleteCmsModelTask } from \"~/features/DeleteModelTask/types.js\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport { validateConfirmation } from \"~/helpers/confirmation.js\";\n\nconst deleteValidation = zod\n .object({\n modelId: zod.string(),\n confirmation: zod.string()\n })\n .superRefine((value, context) => {\n if (validateConfirmation(value)) {\n return;\n }\n context.addIssue({\n code: zod.ZodIssueCode.custom,\n message: `Confirmation input does not match.`,\n fatal: true,\n path: [\"confirmation\"]\n });\n })\n .readonly();\n\nconst cancelValidation = zod\n .object({\n modelId: zod.string()\n })\n .readonly();\n\nconst getValidation = zod\n .object({\n modelId: zod.string()\n })\n .readonly();\n\nexport const createDeleteModelGraphQl = <\n T extends HcmsTasksContext = HcmsTasksContext\n>(): RequestContextInitializer.Interface => ({\n async init(inputContext: T) {\n const ready = await isHeadlessCmsReady(inputContext);\n\n if (!ready || !inputContext.container.resolve(HeadlessCms).MANAGE) {\n return;\n }\n\n const plugin = new CmsGraphQLSchemaPlugin<T>({\n typeDefs: /* GraphQL */ `\n enum DeleteCmsModelTaskStatus {\n running\n done\n error\n canceled\n }\n type DeleteCmsModelTask {\n id: ID!\n status: DeleteCmsModelTaskStatus!\n deleted: Int!\n total: Int!\n }\n\n type GetDeleteCmsModelProgressResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n type FullyDeleteCmsModelResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n type CancelDeleteCmsModelResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n extend type CmsContentModel {\n isBeingDeleted: Boolean!\n }\n\n extend type Query {\n getDeleteModelProgress(modelId: ID!): GetDeleteCmsModelProgressResponse!\n listContentModels(\n includeBeingDeleted: Boolean = false\n ): CmsContentModelListResponse\n }\n\n extend type Mutation {\n fullyDeleteModel(\n modelId: ID!\n confirmation: String!\n ): FullyDeleteCmsModelResponse!\n cancelFullyDeleteModel(modelId: ID!): CancelDeleteCmsModelResponse!\n }\n `,\n resolvers: {\n CmsContentModel: {\n isBeingDeleted: async (model: CmsModel, _: unknown, context) => {\n try {\n return await context.container\n .resolve(DeleteModelOperations)\n .isModelBeingDeleted(model.modelId);\n } catch (ex) {\n console.error(ex);\n }\n return true;\n }\n },\n Query: {\n getDeleteModelProgress: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = getValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .getDeleteModelProgress(input.data.modelId);\n });\n }\n },\n Mutation: {\n fullyDeleteModel: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = deleteValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .fullyDeleteModel(input.data.modelId);\n });\n },\n cancelFullyDeleteModel: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = cancelValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .cancelFullyDeleteModel(input.data.modelId);\n });\n }\n }\n },\n resolverDecorators: {\n [\"Query.listContentModels\"]: [\n createResolverDecorator<any, any, HcmsTasksContext>(\n resolver => async (parent, args, context, info) => {\n // TODO @bruno figure out how to fix these types\n const result = (await resolver(parent, args, context, info)) as any;\n if (result.error || !Array.isArray(result.data)) {\n return result;\n }\n\n if (args?.includeBeingDeleted !== false) {\n return result;\n }\n\n const listed = result.data as CmsModel[];\n\n try {\n const beingDeletedList = await context.container\n .resolve(DeleteModelOperations)\n .listModelsBeingDeleted();\n\n return new Response(\n listed.filter(model => {\n if (!model?.modelId) {\n return false;\n } else if (\n beingDeletedList.some(\n item => item.modelId === model.modelId\n )\n ) {\n return false;\n }\n return true;\n })\n );\n } catch (ex) {\n return new ErrorResponse(ex);\n }\n }\n )\n ]\n }\n });\n plugin.name = \"headless-cms.graphql.fullyDeleteModel\";\n inputContext.container.registerInstance(CmsGraphQLSchemaFactory, {\n execute: () => [plugin]\n });\n }\n});\n"],"names":["deleteValidation","zod","value","context","validateConfirmation","cancelValidation","getValidation","createDeleteModelGraphQl","inputContext","ready","isHeadlessCmsReady","HeadlessCms","plugin","CmsGraphQLSchemaPlugin","model","_","DeleteModelOperations","ex","console","args","resolve","input","createZodError","createResolverDecorator","resolver","parent","info","result","Array","listed","beingDeletedList","Response","item","ErrorResponse","CmsGraphQLSchemaFactory"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graphql/deleteModel/index.js","sources":["../../../src/graphql/deleteModel/index.ts"],"sourcesContent":["import zod from \"zod\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/abstractions.js\";\nimport { Logger } from \"@webiny/api-core/features/logger/index.js\";\nimport { CmsGraphQLSchemaPlugin, CmsGraphQLSchemaFactory } from \"@webiny/api-headless-cms\";\nimport { HeadlessCms } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport { DeleteModelOperations } from \"~/graphql/deleteModel/abstractions.js\";\nimport type { HcmsTasksContext } from \"~/types.js\";\nimport { createResolverDecorator } from \"@webiny/api-graphql\";\nimport { ErrorResponse } from \"@webiny/api-graphql\";\nimport { resolve } from \"@webiny/api-graphql\";\nimport { Response } from \"@webiny/api-graphql\";\nimport { createZodError } from \"@webiny/utils\";\nimport type { IDeleteCmsModelTask } from \"~/features/DeleteModelTask/types.js\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/index.js\";\nimport { validateConfirmation } from \"~/helpers/confirmation.js\";\n\nconst deleteValidation = zod\n .object({\n modelId: zod.string(),\n confirmation: zod.string()\n })\n .superRefine((value, context) => {\n if (validateConfirmation(value)) {\n return;\n }\n context.addIssue({\n code: zod.ZodIssueCode.custom,\n message: `Confirmation input does not match.`,\n fatal: true,\n path: [\"confirmation\"]\n });\n })\n .readonly();\n\nconst cancelValidation = zod\n .object({\n modelId: zod.string()\n })\n .readonly();\n\nconst getValidation = zod\n .object({\n modelId: zod.string()\n })\n .readonly();\n\n/**\n * Contributes the fullyDeleteModel schema. Previously a `RequestContextInitializer` that built the\n * plugin and then registered a `CmsGraphQLSchemaFactory` holding it; since `execute()` is already\n * awaited by `generateSchema`, the readiness check and the plugin construction can simply live\n * there instead.\n */\nclass DeleteModelGraphQLSchemaFactory implements CmsGraphQLSchemaFactory.Interface {\n constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly headlessCms: HeadlessCms.Interface,\n private readonly logger: Logger.Interface\n ) {}\n\n async execute() {\n type T = HcmsTasksContext;\n\n // On a fresh project there is no tenant until installation completes; and the delete-model\n // schema only belongs on the MANAGE endpoint. (`isHeadlessCmsReady` only checks the tenant.)\n if (!this.tenantContext.getTenant() || !this.headlessCms.MANAGE) {\n return [];\n }\n\n const plugin = new CmsGraphQLSchemaPlugin<T>({\n typeDefs: /* GraphQL */ `\n enum DeleteCmsModelTaskStatus {\n running\n done\n error\n canceled\n }\n type DeleteCmsModelTask {\n id: ID!\n status: DeleteCmsModelTaskStatus!\n deleted: Int!\n total: Int!\n }\n\n type GetDeleteCmsModelProgressResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n type FullyDeleteCmsModelResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n type CancelDeleteCmsModelResponse {\n data: DeleteCmsModelTask\n error: CmsError\n }\n\n extend type CmsContentModel {\n isBeingDeleted: Boolean!\n }\n\n extend type Query {\n getDeleteModelProgress(modelId: ID!): GetDeleteCmsModelProgressResponse!\n listContentModels(\n includeBeingDeleted: Boolean = false\n ): CmsContentModelListResponse\n }\n\n extend type Mutation {\n fullyDeleteModel(\n modelId: ID!\n confirmation: String!\n ): FullyDeleteCmsModelResponse!\n cancelFullyDeleteModel(modelId: ID!): CancelDeleteCmsModelResponse!\n }\n `,\n resolvers: {\n CmsContentModel: {\n isBeingDeleted: async (model: CmsModel, _: unknown, context) => {\n try {\n return await context.container\n .resolve(DeleteModelOperations)\n .isModelBeingDeleted(model.modelId);\n } catch (ex) {\n this.logger.error(\n { error: ex, modelId: model.modelId },\n \"Failed to read the delete-model status.\"\n );\n }\n return true;\n }\n },\n Query: {\n getDeleteModelProgress: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = getValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .getDeleteModelProgress(input.data.modelId);\n });\n }\n },\n Mutation: {\n fullyDeleteModel: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = deleteValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .fullyDeleteModel(input.data.modelId);\n });\n },\n cancelFullyDeleteModel: async (_: unknown, args: unknown, context) => {\n return resolve<IDeleteCmsModelTask>(async () => {\n const input = cancelValidation.safeParse(args);\n if (input.error) {\n throw createZodError(input.error);\n }\n return context.container\n .resolve(DeleteModelOperations)\n .cancelFullyDeleteModel(input.data.modelId);\n });\n }\n }\n },\n resolverDecorators: {\n [\"Query.listContentModels\"]: [\n createResolverDecorator<any, any, HcmsTasksContext>(\n resolver => async (parent, args, context, info) => {\n // TODO @bruno figure out how to fix these types\n const result = (await resolver(parent, args, context, info)) as any;\n if (result.error || !Array.isArray(result.data)) {\n return result;\n }\n\n if (args?.includeBeingDeleted !== false) {\n return result;\n }\n\n const listed = result.data as CmsModel[];\n\n try {\n const beingDeletedList = await context.container\n .resolve(DeleteModelOperations)\n .listModelsBeingDeleted();\n\n return new Response(\n listed.filter(model => {\n if (!model?.modelId) {\n return false;\n } else if (\n beingDeletedList.some(\n item => item.modelId === model.modelId\n )\n ) {\n return false;\n }\n return true;\n })\n );\n } catch (ex) {\n return new ErrorResponse(ex);\n }\n }\n )\n ]\n }\n });\n plugin.name = \"headless-cms.graphql.fullyDeleteModel\";\n return [plugin];\n }\n}\n\nexport const DeleteModelGraphQLSchemaFactoryImpl = CmsGraphQLSchemaFactory.createImplementation({\n implementation: DeleteModelGraphQLSchemaFactory,\n dependencies: [TenantContext, HeadlessCms, Logger]\n});\n"],"names":["deleteValidation","zod","value","context","validateConfirmation","cancelValidation","getValidation","DeleteModelGraphQLSchemaFactory","tenantContext","headlessCms","logger","plugin","CmsGraphQLSchemaPlugin","model","_","DeleteModelOperations","ex","args","resolve","input","createZodError","createResolverDecorator","resolver","parent","info","result","Array","listed","beingDeletedList","Response","item","ErrorResponse","DeleteModelGraphQLSchemaFactoryImpl","CmsGraphQLSchemaFactory","TenantContext","HeadlessCms","Logger"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/api-headless-cms-tasks",
|
|
3
|
-
"version": "6.6.0-alpha.
|
|
3
|
+
"version": "6.6.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -17,28 +17,28 @@
|
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@webiny/api-aco": "6.6.0-alpha.
|
|
21
|
-
"@webiny/api-graphql": "6.6.0-alpha.
|
|
22
|
-
"@webiny/api-headless-cms": "6.6.0-alpha.
|
|
23
|
-
"@webiny/api-headless-cms-bulk-actions": "6.6.0-alpha.
|
|
24
|
-
"@webiny/background-tasks": "6.6.0-alpha.
|
|
25
|
-
"@webiny/error": "6.6.0-alpha.
|
|
26
|
-
"@webiny/feature": "6.6.0-alpha.
|
|
27
|
-
"@webiny/utils": "6.6.0-alpha.
|
|
20
|
+
"@webiny/api-aco": "6.6.0-alpha.1",
|
|
21
|
+
"@webiny/api-graphql": "6.6.0-alpha.1",
|
|
22
|
+
"@webiny/api-headless-cms": "6.6.0-alpha.1",
|
|
23
|
+
"@webiny/api-headless-cms-bulk-actions": "6.6.0-alpha.1",
|
|
24
|
+
"@webiny/background-tasks": "6.6.0-alpha.1",
|
|
25
|
+
"@webiny/error": "6.6.0-alpha.1",
|
|
26
|
+
"@webiny/feature": "6.6.0-alpha.1",
|
|
27
|
+
"@webiny/utils": "6.6.0-alpha.1",
|
|
28
28
|
"graphql": "16.14.2",
|
|
29
29
|
"zod": "4.4.3"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@webiny/api-core": "6.6.0-alpha.
|
|
33
|
-
"@webiny/api-headless-cms-testing": "6.6.0-alpha.
|
|
34
|
-
"@webiny/api-opensearch": "6.6.0-alpha.
|
|
35
|
-
"@webiny/build-tools": "6.6.0-alpha.
|
|
36
|
-
"@webiny/event-handler-core": "6.6.0-alpha.
|
|
37
|
-
"@webiny/handler": "6.6.0-alpha.
|
|
38
|
-
"@webiny/plugins": "6.6.0-alpha.
|
|
39
|
-
"@webiny/
|
|
32
|
+
"@webiny/api-core": "6.6.0-alpha.1",
|
|
33
|
+
"@webiny/api-headless-cms-testing": "6.6.0-alpha.1",
|
|
34
|
+
"@webiny/api-opensearch": "6.6.0-alpha.1",
|
|
35
|
+
"@webiny/build-tools": "6.6.0-alpha.1",
|
|
36
|
+
"@webiny/event-handler-core": "6.6.0-alpha.1",
|
|
37
|
+
"@webiny/handler": "6.6.0-alpha.1",
|
|
38
|
+
"@webiny/plugins": "6.6.0-alpha.1",
|
|
39
|
+
"@webiny/wcp": "6.6.0-alpha.1",
|
|
40
40
|
"typescript": "7.0.2",
|
|
41
|
-
"vitest": "4.1.
|
|
41
|
+
"vitest": "4.1.11"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/abstractions.js";
|
|
2
|
-
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/abstractions.js";
|
|
3
|
-
import { createCacheKey, createMemoryCache } from "@webiny/api-headless-cms/utils/index.js";
|
|
4
|
-
import { DisableModelFeature } from "../../features/DisableModel/feature.js";
|
|
5
|
-
import { createDeleteModelStore } from "../../helpers/store.js";
|
|
6
|
-
import { fullyDeleteModel } from "./fullyDeleteModel.js";
|
|
7
|
-
import { cancelDeleteModel } from "./cancelDeleteModel.js";
|
|
8
|
-
import { getDeleteModelProgress } from "./getDeleteModelProgress.js";
|
|
9
|
-
import { DeleteModelOperations } from "./abstractions.js";
|
|
10
|
-
const createDeleteModelCrud = ()=>({
|
|
11
|
-
async init (context) {
|
|
12
|
-
const getTenant = ()=>context.container.resolve(TenantContext).getTenant().id;
|
|
13
|
-
const getStore = ()=>createDeleteModelStore(context.container.resolve(GlobalKeyValueStore), getTenant());
|
|
14
|
-
const cache = createMemoryCache();
|
|
15
|
-
const listModelsBeingDeleted = async ()=>{
|
|
16
|
-
const cacheKey = createCacheKey({
|
|
17
|
-
tenant: getTenant(),
|
|
18
|
-
type: "deleteModel"
|
|
19
|
-
});
|
|
20
|
-
return cache.getOrSet(cacheKey, ()=>getStore().list());
|
|
21
|
-
};
|
|
22
|
-
const isModelBeingDeleted = async (modelId)=>{
|
|
23
|
-
const items = await listModelsBeingDeleted();
|
|
24
|
-
return items.some((item)=>item.modelId === modelId);
|
|
25
|
-
};
|
|
26
|
-
const operations = {
|
|
27
|
-
listModelsBeingDeleted,
|
|
28
|
-
isModelBeingDeleted,
|
|
29
|
-
fullyDeleteModel: async (modelId)=>{
|
|
30
|
-
const result = await fullyDeleteModel({
|
|
31
|
-
context,
|
|
32
|
-
modelId
|
|
33
|
-
});
|
|
34
|
-
cache.clear();
|
|
35
|
-
return result;
|
|
36
|
-
},
|
|
37
|
-
cancelFullyDeleteModel: async (modelId)=>{
|
|
38
|
-
const result = await cancelDeleteModel({
|
|
39
|
-
context,
|
|
40
|
-
modelId
|
|
41
|
-
});
|
|
42
|
-
cache.clear();
|
|
43
|
-
return result;
|
|
44
|
-
},
|
|
45
|
-
getDeleteModelProgress: async (modelId)=>getDeleteModelProgress({
|
|
46
|
-
context,
|
|
47
|
-
modelId
|
|
48
|
-
})
|
|
49
|
-
};
|
|
50
|
-
context.container.registerInstance(DeleteModelOperations, operations);
|
|
51
|
-
DisableModelFeature.register(context.container);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
export { createDeleteModelCrud };
|
|
55
|
-
|
|
56
|
-
//# sourceMappingURL=crud.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"graphql/deleteModel/crud.js","sources":["../../../src/graphql/deleteModel/crud.ts"],"sourcesContent":["import type { HcmsTasksContext } from \"~/types.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/abstractions.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport { createCacheKey } from \"@webiny/api-headless-cms/utils/index.js\";\nimport { createMemoryCache } from \"@webiny/api-headless-cms/utils/index.js\";\nimport type { IStoreValue } from \"~/features/DeleteModelTask/types.js\";\nimport type { RequestContextInitializer } from \"@webiny/event-handler-core\";\nimport { DisableModelFeature } from \"~/features/DisableModel/feature.js\";\nimport { createDeleteModelStore } from \"~/helpers/store.js\";\nimport { fullyDeleteModel } from \"~/graphql/deleteModel/fullyDeleteModel.js\";\nimport { cancelDeleteModel } from \"~/graphql/deleteModel/cancelDeleteModel.js\";\nimport { getDeleteModelProgress } from \"~/graphql/deleteModel/getDeleteModelProgress.js\";\nimport { DeleteModelOperations } from \"~/graphql/deleteModel/abstractions.js\";\n\nexport const createDeleteModelCrud = (): RequestContextInitializer.Interface => ({\n async init(context: HcmsTasksContext) {\n const getTenant = (): string => {\n return context.container.resolve(TenantContext).getTenant().id;\n };\n\n const getStore = () => {\n return createDeleteModelStore(\n context.container.resolve(GlobalKeyValueStore),\n getTenant()\n );\n };\n\n const cache = createMemoryCache<Promise<IStoreValue[]>>();\n\n const listModelsBeingDeleted = async (): Promise<IStoreValue[]> => {\n const cacheKey = createCacheKey({\n tenant: getTenant(),\n type: \"deleteModel\"\n });\n\n return cache.getOrSet(cacheKey, () => getStore().list());\n };\n\n const isModelBeingDeleted = async (modelId: string): Promise<boolean> => {\n const items = await listModelsBeingDeleted();\n return items.some(item => item.modelId === modelId);\n };\n\n const operations: DeleteModelOperations.Interface = {\n listModelsBeingDeleted,\n isModelBeingDeleted,\n fullyDeleteModel: async (modelId: string) => {\n const result = await fullyDeleteModel({ context, modelId });\n cache.clear();\n return result;\n },\n cancelFullyDeleteModel: async (modelId: string) => {\n const result = await cancelDeleteModel({ context, modelId });\n cache.clear();\n return result;\n },\n getDeleteModelProgress: async (modelId: string) => {\n return getDeleteModelProgress({ context, modelId });\n }\n };\n\n context.container.registerInstance(DeleteModelOperations, operations);\n\n DisableModelFeature.register(context.container);\n }\n});\n"],"names":["createDeleteModelCrud","context","getTenant","TenantContext","getStore","createDeleteModelStore","GlobalKeyValueStore","cache","createMemoryCache","listModelsBeingDeleted","cacheKey","createCacheKey","isModelBeingDeleted","modelId","items","item","operations","result","fullyDeleteModel","cancelDeleteModel","getDeleteModelProgress","DeleteModelOperations","DisableModelFeature"],"mappings":";;;;;;;;;AAcO,MAAMA,wBAAwB,IAA4C;QAC7E,MAAM,MAAKC,OAAyB;YAChC,MAAMC,YAAY,IACPD,QAAQ,SAAS,CAAC,OAAO,CAACE,eAAe,SAAS,GAAG,EAAE;YAGlE,MAAMC,WAAW,IACNC,uBACHJ,QAAQ,SAAS,CAAC,OAAO,CAACK,sBAC1BJ;YAIR,MAAMK,QAAQC;YAEd,MAAMC,yBAAyB;gBAC3B,MAAMC,WAAWC,eAAe;oBAC5B,QAAQT;oBACR,MAAM;gBACV;gBAEA,OAAOK,MAAM,QAAQ,CAACG,UAAU,IAAMN,WAAW,IAAI;YACzD;YAEA,MAAMQ,sBAAsB,OAAOC;gBAC/B,MAAMC,QAAQ,MAAML;gBACpB,OAAOK,MAAM,IAAI,CAACC,CAAAA,OAAQA,KAAK,OAAO,KAAKF;YAC/C;YAEA,MAAMG,aAA8C;gBAChDP;gBACAG;gBACA,kBAAkB,OAAOC;oBACrB,MAAMI,SAAS,MAAMC,iBAAiB;wBAAEjB;wBAASY;oBAAQ;oBACzDN,MAAM,KAAK;oBACX,OAAOU;gBACX;gBACA,wBAAwB,OAAOJ;oBAC3B,MAAMI,SAAS,MAAME,kBAAkB;wBAAElB;wBAASY;oBAAQ;oBAC1DN,MAAM,KAAK;oBACX,OAAOU;gBACX;gBACA,wBAAwB,OAAOJ,UACpBO,uBAAuB;wBAAEnB;wBAASY;oBAAQ;YAEzD;YAEAZ,QAAQ,SAAS,CAAC,gBAAgB,CAACoB,uBAAuBL;YAE1DM,oBAAoB,QAAQ,CAACrB,QAAQ,SAAS;QAClD;IACJ"}
|