@webiny/api-record-locking 6.6.0-alpha.7 → 6.6.0-alpha.8

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 (48) hide show
  1. package/RecordLockingAppFeature.js +4 -4
  2. package/RecordLockingAppFeature.js.map +1 -1
  3. package/domain/abstractions.d.ts +9 -3
  4. package/domain/abstractions.js +2 -2
  5. package/domain/abstractions.js.map +1 -1
  6. package/features/GetLockRecord/GetLockRecordRepository.d.ts +4 -3
  7. package/features/GetLockRecord/GetLockRecordRepository.js +20 -15
  8. package/features/GetLockRecord/GetLockRecordRepository.js.map +1 -1
  9. package/features/ListAllLockRecords/ListAllLockRecordsRepository.d.ts +3 -3
  10. package/features/ListAllLockRecords/ListAllLockRecordsRepository.js +7 -6
  11. package/features/ListAllLockRecords/ListAllLockRecordsRepository.js.map +1 -1
  12. package/features/ListLockRecords/ListLockRecordsRepository.d.ts +4 -3
  13. package/features/ListLockRecords/ListLockRecordsRepository.js +7 -6
  14. package/features/ListLockRecords/ListLockRecordsRepository.js.map +1 -1
  15. package/features/LockEntry/LockEntryRepository.d.ts +4 -3
  16. package/features/LockEntry/LockEntryRepository.js +6 -5
  17. package/features/LockEntry/LockEntryRepository.js.map +1 -1
  18. package/features/RecordLockingFeature.d.ts +0 -5
  19. package/features/RecordLockingFeature.js +3 -2
  20. package/features/RecordLockingFeature.js.map +1 -1
  21. package/features/RecordLockingModelProvider.d.ts +18 -0
  22. package/features/RecordLockingModelProvider.js +22 -0
  23. package/features/RecordLockingModelProvider.js.map +1 -0
  24. package/features/UnlockEntry/UnlockEntryRepository.d.ts +3 -3
  25. package/features/UnlockEntry/UnlockEntryRepository.js +6 -5
  26. package/features/UnlockEntry/UnlockEntryRepository.js.map +1 -1
  27. package/features/UnlockEntryRequest/UnlockEntryRequestRepository.d.ts +3 -3
  28. package/features/UnlockEntryRequest/UnlockEntryRequestRepository.js +6 -5
  29. package/features/UnlockEntryRequest/UnlockEntryRequestRepository.js.map +1 -1
  30. package/features/UpdateEntryLock/UpdateEntryLockRepository.d.ts +4 -3
  31. package/features/UpdateEntryLock/UpdateEntryLockRepository.js +7 -6
  32. package/features/UpdateEntryLock/UpdateEntryLockRepository.js.map +1 -1
  33. package/graphql/RecordLockingGraphQLSchema.d.ts +23 -0
  34. package/graphql/RecordLockingGraphQLSchema.js +372 -0
  35. package/graphql/RecordLockingGraphQLSchema.js.map +1 -0
  36. package/graphql/checkPermissions.d.ts +3 -3
  37. package/graphql/checkPermissions.js +1 -3
  38. package/graphql/checkPermissions.js.map +1 -1
  39. package/package.json +13 -15
  40. package/domain/RecordLockingAppConfig.d.ts +0 -4
  41. package/domain/RecordLockingAppConfig.js +0 -5
  42. package/domain/RecordLockingAppConfig.js.map +0 -1
  43. package/graphql/RecordLockingContextualSchema.d.ts +0 -16
  44. package/graphql/RecordLockingContextualSchema.js +0 -74
  45. package/graphql/RecordLockingContextualSchema.js.map +0 -1
  46. package/graphql/schema.d.ts +0 -11
  47. package/graphql/schema.js +0 -297
  48. package/graphql/schema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"features/UnlockEntry/UnlockEntryRepository.js","sources":["../../../src/features/UnlockEntry/UnlockEntryRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { DeleteEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/DeleteEntry\";\nimport { createIdentifier } from \"@webiny/utils\";\nimport { UnlockEntryRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { RecordLockingModel } from \"~/domain/abstractions.js\";\nimport { LockRecordNotFoundError, UnlockEntryError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\n\nclass UnlockEntryRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private model: RecordLockingModel.Interface,\n private deleteEntry: DeleteEntryUseCase.Interface\n ) {}\n\n async delete(lockRecordId: string): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const entryId = createLockRecordDatabaseId(lockRecordId);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const result = await this.deleteEntry.execute(this.model, id, {\n permanently: true\n });\n\n if (result.isFail()) {\n if (result.error.code === \"Cms/Entry/NotFound\") {\n return Result.fail(new LockRecordNotFoundError());\n }\n return Result.fail(new UnlockEntryError(result.error));\n }\n\n return Result.ok();\n } catch (error) {\n return Result.fail(new UnlockEntryError(error as Error));\n }\n }\n}\n\nexport const UnlockEntryRepository = RepositoryAbstraction.createImplementation({\n implementation: UnlockEntryRepositoryImpl,\n dependencies: [RecordLockingModel, DeleteEntryUseCase]\n});\n"],"names":["UnlockEntryRepositoryImpl","model","deleteEntry","lockRecordId","entryId","createLockRecordDatabaseId","id","createIdentifier","result","Result","LockRecordNotFoundError","UnlockEntryError","error","UnlockEntryRepository","RepositoryAbstraction","RecordLockingModel","DeleteEntryUseCase"],"mappings":";;;;;;;AAQA,MAAMA;IACF,YACYC,KAAmC,EACnCC,WAAyC,CACnD;aAFUD,KAAK,GAALA;aACAC,WAAW,GAAXA;IACT;IAEH,MAAM,OAAOC,YAAoB,EAAsD;QACnF,IAAI;YACA,MAAMC,UAAUC,2BAA2BF;YAC3C,MAAMG,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,SAAS,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAEF,IAAI;gBAC1D,aAAa;YACjB;YAEA,IAAIE,OAAO,MAAM,IAAI;gBACjB,IAAIA,AAAsB,yBAAtBA,OAAO,KAAK,CAAC,IAAI,EACjB,OAAOC,OAAO,IAAI,CAAC,IAAIC;gBAE3B,OAAOD,OAAO,IAAI,CAAC,IAAIE,iBAAiBH,OAAO,KAAK;YACxD;YAEA,OAAOC,OAAO,EAAE;QACpB,EAAE,OAAOG,OAAO;YACZ,OAAOH,OAAO,IAAI,CAAC,IAAIE,iBAAiBC;QAC5C;IACJ;AACJ;AAEO,MAAMC,8CAAwBC,sBAAAA,oBAA0C,CAAC;IAC5E,gBAAgBd;IAChB,cAAc;QAACe;QAAoBC;KAAmB;AAC1D"}
1
+ {"version":3,"file":"features/UnlockEntry/UnlockEntryRepository.js","sources":["../../../src/features/UnlockEntry/UnlockEntryRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { DeleteEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/DeleteEntry\";\nimport { createIdentifier } from \"@webiny/utils\";\nimport { UnlockEntryRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { RecordLockingModelProvider } from \"~/domain/abstractions.js\";\nimport { LockRecordNotFoundError, UnlockEntryError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\n\nclass UnlockEntryRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private modelProvider: RecordLockingModelProvider.Interface,\n private deleteEntry: DeleteEntryUseCase.Interface\n ) {}\n\n async delete(lockRecordId: string): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const model = await this.modelProvider.get();\n\n const entryId = createLockRecordDatabaseId(lockRecordId);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const result = await this.deleteEntry.execute(model, id, {\n permanently: true\n });\n\n if (result.isFail()) {\n if (result.error.code === \"Cms/Entry/NotFound\") {\n return Result.fail(new LockRecordNotFoundError());\n }\n return Result.fail(new UnlockEntryError(result.error));\n }\n\n return Result.ok();\n } catch (error) {\n return Result.fail(new UnlockEntryError(error as Error));\n }\n }\n}\n\nexport const UnlockEntryRepository = RepositoryAbstraction.createImplementation({\n implementation: UnlockEntryRepositoryImpl,\n dependencies: [RecordLockingModelProvider, DeleteEntryUseCase]\n});\n"],"names":["UnlockEntryRepositoryImpl","modelProvider","deleteEntry","lockRecordId","model","entryId","createLockRecordDatabaseId","id","createIdentifier","result","Result","LockRecordNotFoundError","UnlockEntryError","error","UnlockEntryRepository","RepositoryAbstraction","RecordLockingModelProvider","DeleteEntryUseCase"],"mappings":";;;;;;;AAQA,MAAMA;IACF,YACYC,aAAmD,EACnDC,WAAyC,CACnD;aAFUD,aAAa,GAAbA;aACAC,WAAW,GAAXA;IACT;IAEH,MAAM,OAAOC,YAAoB,EAAsD;QACnF,IAAI;YACA,MAAMC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG;YAE1C,MAAMC,UAAUC,2BAA2BH;YAC3C,MAAMI,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,SAAS,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAACL,OAAOG,IAAI;gBACrD,aAAa;YACjB;YAEA,IAAIE,OAAO,MAAM,IAAI;gBACjB,IAAIA,AAAsB,yBAAtBA,OAAO,KAAK,CAAC,IAAI,EACjB,OAAOC,OAAO,IAAI,CAAC,IAAIC;gBAE3B,OAAOD,OAAO,IAAI,CAAC,IAAIE,iBAAiBH,OAAO,KAAK;YACxD;YAEA,OAAOC,OAAO,EAAE;QACpB,EAAE,OAAOG,OAAO;YACZ,OAAOH,OAAO,IAAI,CAAC,IAAIE,iBAAiBC;QAC5C;IACJ;AACJ;AAEO,MAAMC,8CAAwBC,sBAAAA,oBAA0C,CAAC;IAC5E,gBAAgBf;IAChB,cAAc;QAACgB;QAA4BC;KAAmB;AAClE"}
@@ -2,13 +2,13 @@ import { Result } from "@webiny/feature/api";
2
2
  import { UnlockEntryRequestRepository as RepositoryAbstraction } from "./abstractions.js";
3
3
  import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry";
4
4
  import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
5
+ import { RecordLockingModelProvider } from "../../domain/abstractions.js";
5
6
  import type { ILockRecord } from "../../domain/LockRecord.js";
6
- import type { CmsModel } from "@webiny/api-headless-cms/types";
7
7
  declare class UnlockEntryRequestRepositoryImpl implements RepositoryAbstraction.Interface {
8
8
  private updateEntry;
9
9
  private identityContext;
10
- private model;
11
- constructor(updateEntry: UpdateEntryUseCase.Interface, identityContext: IdentityContext.Interface, model: CmsModel);
10
+ private modelProvider;
11
+ constructor(updateEntry: UpdateEntryUseCase.Interface, identityContext: IdentityContext.Interface, modelProvider: RecordLockingModelProvider.Interface);
12
12
  update(record: ILockRecord): Promise<Result<ILockRecord, RepositoryAbstraction.Error>>;
13
13
  }
14
14
  export declare const UnlockEntryRequestRepository: typeof UnlockEntryRequestRepositoryImpl & {
@@ -2,25 +2,26 @@ import { Result } from "@webiny/feature/api";
2
2
  import { UnlockEntryRequestRepository } from "./abstractions.js";
3
3
  import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEntry/UpdateEntry";
4
4
  import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
5
- import { RecordLockingModel } from "../../domain/abstractions.js";
5
+ import { RecordLockingModelProvider } from "../../domain/abstractions.js";
6
6
  import { UnlockEntryRequestError } from "../../domain/errors.js";
7
7
  import { createLockRecordDatabaseId } from "../../utils/lockRecordDatabaseId.js";
8
8
  import { createIdentifier } from "@webiny/utils";
9
9
  class UnlockEntryRequestRepositoryImpl {
10
- constructor(updateEntry, identityContext, model){
10
+ constructor(updateEntry, identityContext, modelProvider){
11
11
  this.updateEntry = updateEntry;
12
12
  this.identityContext = identityContext;
13
- this.model = model;
13
+ this.modelProvider = modelProvider;
14
14
  }
15
15
  async update(record) {
16
16
  try {
17
+ const model = await this.modelProvider.get();
17
18
  const entryId = createLockRecordDatabaseId(record.id);
18
19
  const id = createIdentifier({
19
20
  id: entryId,
20
21
  version: 1
21
22
  });
22
23
  const recordValues = record.toObject();
23
- const result = await this.identityContext.withoutAuthorization(async ()=>await this.updateEntry.execute(this.model, id, {
24
+ const result = await this.identityContext.withoutAuthorization(async ()=>await this.updateEntry.execute(model, id, {
24
25
  ...recordValues,
25
26
  values: recordValues
26
27
  }));
@@ -36,7 +37,7 @@ const UnlockEntryRequestRepository_UnlockEntryRequestRepository = UnlockEntryReq
36
37
  dependencies: [
37
38
  UpdateEntryUseCase,
38
39
  IdentityContext,
39
- RecordLockingModel
40
+ RecordLockingModelProvider
40
41
  ]
41
42
  });
42
43
  export { UnlockEntryRequestRepository_UnlockEntryRequestRepository as UnlockEntryRequestRepository };
@@ -1 +1 @@
1
- {"version":3,"file":"features/UnlockEntryRequest/UnlockEntryRequestRepository.js","sources":["../../../src/features/UnlockEntryRequest/UnlockEntryRequestRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UnlockEntryRequestRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { RecordLockingModel } from \"~/domain/abstractions.js\";\nimport type { ILockRecord } from \"~/domain/LockRecord.js\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types\";\nimport { UnlockEntryRequestError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\nimport { createIdentifier } from \"@webiny/utils\";\n\nclass UnlockEntryRequestRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private updateEntry: UpdateEntryUseCase.Interface,\n private identityContext: IdentityContext.Interface,\n private model: CmsModel\n ) {}\n\n async update(record: ILockRecord): Promise<Result<ILockRecord, RepositoryAbstraction.Error>> {\n try {\n const entryId = createLockRecordDatabaseId(record.id);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const recordValues = record.toObject();\n const result = await this.identityContext.withoutAuthorization(async () => {\n return await this.updateEntry.execute(this.model, id, {\n ...recordValues,\n values: recordValues\n });\n });\n\n if (result.isFail()) {\n return Result.fail(new UnlockEntryRequestError(result.error));\n }\n\n return Result.ok(record);\n } catch (error) {\n return Result.fail(new UnlockEntryRequestError(error as Error));\n }\n }\n}\n\nexport const UnlockEntryRequestRepository = RepositoryAbstraction.createImplementation({\n implementation: UnlockEntryRequestRepositoryImpl,\n dependencies: [UpdateEntryUseCase, IdentityContext, RecordLockingModel]\n});\n"],"names":["UnlockEntryRequestRepositoryImpl","updateEntry","identityContext","model","record","entryId","createLockRecordDatabaseId","id","createIdentifier","recordValues","result","Result","UnlockEntryRequestError","error","UnlockEntryRequestRepository","RepositoryAbstraction","UpdateEntryUseCase","IdentityContext","RecordLockingModel"],"mappings":";;;;;;;;AAWA,MAAMA;IACF,YACYC,WAAyC,EACzCC,eAA0C,EAC1CC,KAAe,CACzB;aAHUF,WAAW,GAAXA;aACAC,eAAe,GAAfA;aACAC,KAAK,GAALA;IACT;IAEH,MAAM,OAAOC,MAAmB,EAA6D;QACzF,IAAI;YACA,MAAMC,UAAUC,2BAA2BF,OAAO,EAAE;YACpD,MAAMG,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,eAAeL,OAAO,QAAQ;YACpC,MAAMM,SAAS,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,UACpD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAEH,IAAI;oBAClD,GAAGE,YAAY;oBACf,QAAQA;gBACZ;YAGJ,IAAIC,OAAO,MAAM,IACb,OAAOC,OAAO,IAAI,CAAC,IAAIC,wBAAwBF,OAAO,KAAK;YAG/D,OAAOC,OAAO,EAAE,CAACP;QACrB,EAAE,OAAOS,OAAO;YACZ,OAAOF,OAAO,IAAI,CAAC,IAAIC,wBAAwBC;QACnD;IACJ;AACJ;AAEO,MAAMC,4DAA+BC,6BAAAA,oBAA0C,CAAC;IACnF,gBAAgBf;IAChB,cAAc;QAACgB;QAAoBC;QAAiBC;KAAmB;AAC3E"}
1
+ {"version":3,"file":"features/UnlockEntryRequest/UnlockEntryRequestRepository.js","sources":["../../../src/features/UnlockEntryRequest/UnlockEntryRequestRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UnlockEntryRequestRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { RecordLockingModelProvider } from \"~/domain/abstractions.js\";\nimport type { ILockRecord } from \"~/domain/LockRecord.js\";\nimport { UnlockEntryRequestError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\nimport { createIdentifier } from \"@webiny/utils\";\n\nclass UnlockEntryRequestRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private updateEntry: UpdateEntryUseCase.Interface,\n private identityContext: IdentityContext.Interface,\n private modelProvider: RecordLockingModelProvider.Interface\n ) {}\n\n async update(record: ILockRecord): Promise<Result<ILockRecord, RepositoryAbstraction.Error>> {\n try {\n const model = await this.modelProvider.get();\n\n const entryId = createLockRecordDatabaseId(record.id);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const recordValues = record.toObject();\n const result = await this.identityContext.withoutAuthorization(async () => {\n return await this.updateEntry.execute(model, id, {\n ...recordValues,\n values: recordValues\n });\n });\n\n if (result.isFail()) {\n return Result.fail(new UnlockEntryRequestError(result.error));\n }\n\n return Result.ok(record);\n } catch (error) {\n return Result.fail(new UnlockEntryRequestError(error as Error));\n }\n }\n}\n\nexport const UnlockEntryRequestRepository = RepositoryAbstraction.createImplementation({\n implementation: UnlockEntryRequestRepositoryImpl,\n dependencies: [UpdateEntryUseCase, IdentityContext, RecordLockingModelProvider]\n});\n"],"names":["UnlockEntryRequestRepositoryImpl","updateEntry","identityContext","modelProvider","record","model","entryId","createLockRecordDatabaseId","id","createIdentifier","recordValues","result","Result","UnlockEntryRequestError","error","UnlockEntryRequestRepository","RepositoryAbstraction","UpdateEntryUseCase","IdentityContext","RecordLockingModelProvider"],"mappings":";;;;;;;;AAUA,MAAMA;IACF,YACYC,WAAyC,EACzCC,eAA0C,EAC1CC,aAAmD,CAC7D;aAHUF,WAAW,GAAXA;aACAC,eAAe,GAAfA;aACAC,aAAa,GAAbA;IACT;IAEH,MAAM,OAAOC,MAAmB,EAA6D;QACzF,IAAI;YACA,MAAMC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG;YAE1C,MAAMC,UAAUC,2BAA2BH,OAAO,EAAE;YACpD,MAAMI,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,eAAeN,OAAO,QAAQ;YACpC,MAAMO,SAAS,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,UACpD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAACN,OAAOG,IAAI;oBAC7C,GAAGE,YAAY;oBACf,QAAQA;gBACZ;YAGJ,IAAIC,OAAO,MAAM,IACb,OAAOC,OAAO,IAAI,CAAC,IAAIC,wBAAwBF,OAAO,KAAK;YAG/D,OAAOC,OAAO,EAAE,CAACR;QACrB,EAAE,OAAOU,OAAO;YACZ,OAAOF,OAAO,IAAI,CAAC,IAAIC,wBAAwBC;QACnD;IACJ;AACJ;AAEO,MAAMC,4DAA+BC,6BAAAA,oBAA0C,CAAC;IACnF,gBAAgBhB;IAChB,cAAc;QAACiB;QAAoBC;QAAiBC;KAA2B;AACnF"}
@@ -3,15 +3,16 @@ import { UpdateEntryUseCase } from "@webiny/api-headless-cms/features/contentEnt
3
3
  import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEntry/GetEntryById";
4
4
  import { Result } from "@webiny/feature/api";
5
5
  import { UpdateEntryLockRepository as RepositoryAbstraction } from "./abstractions.js";
6
- import { RecordLockingConfig, RecordLockingModel } from "../../domain/abstractions.js";
6
+ import { RecordLockingConfig } from "../../domain/abstractions.js";
7
+ import { RecordLockingModelProvider } from "../../domain/abstractions.js";
7
8
  import type { ILockRecord } from "../../domain/LockRecord.js";
8
9
  declare class UpdateEntryLockRepositoryImpl implements RepositoryAbstraction.Interface {
9
- private model;
10
+ private modelProvider;
10
11
  private config;
11
12
  private identityContext;
12
13
  private updateEntry;
13
14
  private getEntryById;
14
- constructor(model: RecordLockingModel.Interface, config: RecordLockingConfig.Interface, identityContext: IdentityContext.Interface, updateEntry: UpdateEntryUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface);
15
+ constructor(modelProvider: RecordLockingModelProvider.Interface, config: RecordLockingConfig.Interface, identityContext: IdentityContext.Interface, updateEntry: UpdateEntryUseCase.Interface, getEntryById: GetEntryByIdUseCase.Interface);
15
16
  update(lockRecordId: string, updateOwner: boolean): Promise<Result<ILockRecord, RepositoryAbstraction.Error>>;
16
17
  }
17
18
  export declare const UpdateEntryLockRepository: typeof UpdateEntryLockRepositoryImpl & {
@@ -4,13 +4,13 @@ import { GetEntryByIdUseCase } from "@webiny/api-headless-cms/features/contentEn
4
4
  import { Result } from "@webiny/feature/api";
5
5
  import { createIdentifier } from "@webiny/utils";
6
6
  import { UpdateEntryLockRepository } from "./abstractions.js";
7
- import { RecordLockingConfig, RecordLockingModel } from "../../domain/abstractions.js";
7
+ import { RecordLockingConfig, RecordLockingModelProvider } from "../../domain/abstractions.js";
8
8
  import { LockRecord } from "../../domain/LockRecord.js";
9
9
  import { LockRecordPersistenceError } from "../../domain/errors.js";
10
10
  import { createLockRecordDatabaseId } from "../../utils/lockRecordDatabaseId.js";
11
11
  class UpdateEntryLockRepositoryImpl {
12
- constructor(model, config, identityContext, updateEntry, getEntryById){
13
- this.model = model;
12
+ constructor(modelProvider, config, identityContext, updateEntry, getEntryById){
13
+ this.modelProvider = modelProvider;
14
14
  this.config = config;
15
15
  this.identityContext = identityContext;
16
16
  this.updateEntry = updateEntry;
@@ -18,6 +18,7 @@ class UpdateEntryLockRepositoryImpl {
18
18
  }
19
19
  async update(lockRecordId, updateOwner) {
20
20
  try {
21
+ const model = await this.modelProvider.get();
21
22
  const entryId = createLockRecordDatabaseId(lockRecordId);
22
23
  const id = createIdentifier({
23
24
  id: entryId,
@@ -33,9 +34,9 @@ class UpdateEntryLockRepositoryImpl {
33
34
  updateData.createdBy = identity;
34
35
  updateData.savedBy = identity;
35
36
  }
36
- const result = await this.updateEntry.execute(this.model, id, updateData);
37
+ const result = await this.updateEntry.execute(model, id, updateData);
37
38
  if (result.isFail()) return Result.fail(new LockRecordPersistenceError(result.error));
38
- const getResult = await this.getEntryById.execute(this.model, id);
39
+ const getResult = await this.getEntryById.execute(model, id);
39
40
  if (getResult.isFail()) return Result.fail(new LockRecordPersistenceError(getResult.error));
40
41
  const entry = getResult.value;
41
42
  const lockRecord = new LockRecord(entry, this.config.timeout);
@@ -48,7 +49,7 @@ class UpdateEntryLockRepositoryImpl {
48
49
  const UpdateEntryLockRepository_UpdateEntryLockRepository = UpdateEntryLockRepository.createImplementation({
49
50
  implementation: UpdateEntryLockRepositoryImpl,
50
51
  dependencies: [
51
- RecordLockingModel,
52
+ RecordLockingModelProvider,
52
53
  RecordLockingConfig,
53
54
  IdentityContext,
54
55
  UpdateEntryUseCase,
@@ -1 +1 @@
1
- {"version":3,"file":"features/UpdateEntryLock/UpdateEntryLockRepository.js","sources":["../../../src/features/UpdateEntryLock/UpdateEntryLockRepository.ts"],"sourcesContent":["import { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport { Result } from \"@webiny/feature/api\";\nimport { createIdentifier } from \"@webiny/utils\";\nimport { UpdateEntryLockRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { RecordLockingConfig, RecordLockingModel } from \"~/domain/abstractions.js\";\nimport type { ILockRecord } from \"~/domain/LockRecord.js\";\nimport { LockRecord } from \"~/domain/LockRecord.js\";\nimport type { LockRecordValues } from \"~/domain/types.js\";\nimport { LockRecordPersistenceError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\n\nclass UpdateEntryLockRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private model: RecordLockingModel.Interface,\n private config: RecordLockingConfig.Interface,\n private identityContext: IdentityContext.Interface,\n private updateEntry: UpdateEntryUseCase.Interface,\n private getEntryById: GetEntryByIdUseCase.Interface\n ) {}\n\n async update(\n lockRecordId: string,\n updateOwner: boolean\n ): Promise<Result<ILockRecord, RepositoryAbstraction.Error>> {\n try {\n const entryId = createLockRecordDatabaseId(lockRecordId);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const identity = this.identityContext.getIdentity();\n const now = new Date().toISOString();\n\n // Build update data\n const updateData: any = {\n savedOn: now\n };\n\n // If updating owner (expired lock), also update created fields\n if (updateOwner) {\n updateData.createdOn = now;\n updateData.createdBy = identity;\n updateData.savedBy = identity;\n }\n\n const result = await this.updateEntry.execute(this.model, id, updateData);\n\n if (result.isFail()) {\n return Result.fail(new LockRecordPersistenceError(result.error));\n }\n\n // Fetch the updated entry to return full lock record\n const getResult = await this.getEntryById.execute<LockRecordValues>(this.model, id);\n\n if (getResult.isFail()) {\n return Result.fail(new LockRecordPersistenceError(getResult.error));\n }\n\n const entry = getResult.value;\n const lockRecord = new LockRecord(entry, this.config.timeout);\n\n return Result.ok(lockRecord);\n } catch (error) {\n return Result.fail(new LockRecordPersistenceError(error as Error));\n }\n }\n}\n\nexport const UpdateEntryLockRepository = RepositoryAbstraction.createImplementation({\n implementation: UpdateEntryLockRepositoryImpl,\n dependencies: [\n RecordLockingModel,\n RecordLockingConfig,\n IdentityContext,\n UpdateEntryUseCase,\n GetEntryByIdUseCase\n ]\n});\n"],"names":["UpdateEntryLockRepositoryImpl","model","config","identityContext","updateEntry","getEntryById","lockRecordId","updateOwner","entryId","createLockRecordDatabaseId","id","createIdentifier","identity","now","Date","updateData","result","Result","LockRecordPersistenceError","getResult","entry","lockRecord","LockRecord","error","UpdateEntryLockRepository","RepositoryAbstraction","RecordLockingModel","RecordLockingConfig","IdentityContext","UpdateEntryUseCase","GetEntryByIdUseCase"],"mappings":";;;;;;;;;;AAaA,MAAMA;IACF,YACYC,KAAmC,EACnCC,MAAqC,EACrCC,eAA0C,EAC1CC,WAAyC,EACzCC,YAA2C,CACrD;aALUJ,KAAK,GAALA;aACAC,MAAM,GAANA;aACAC,eAAe,GAAfA;aACAC,WAAW,GAAXA;aACAC,YAAY,GAAZA;IACT;IAEH,MAAM,OACFC,YAAoB,EACpBC,WAAoB,EACqC;QACzD,IAAI;YACA,MAAMC,UAAUC,2BAA2BH;YAC3C,MAAMI,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,WAAW,IAAI,CAAC,eAAe,CAAC,WAAW;YACjD,MAAMC,MAAM,IAAIC,OAAO,WAAW;YAGlC,MAAMC,aAAkB;gBACpB,SAASF;YACb;YAGA,IAAIN,aAAa;gBACbQ,WAAW,SAAS,GAAGF;gBACvBE,WAAW,SAAS,GAAGH;gBACvBG,WAAW,OAAO,GAAGH;YACzB;YAEA,MAAMI,SAAS,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAEN,IAAIK;YAE9D,IAAIC,OAAO,MAAM,IACb,OAAOC,OAAO,IAAI,CAAC,IAAIC,2BAA2BF,OAAO,KAAK;YAIlE,MAAMG,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAmB,IAAI,CAAC,KAAK,EAAET;YAEhF,IAAIS,UAAU,MAAM,IAChB,OAAOF,OAAO,IAAI,CAAC,IAAIC,2BAA2BC,UAAU,KAAK;YAGrE,MAAMC,QAAQD,UAAU,KAAK;YAC7B,MAAME,aAAa,IAAIC,WAAWF,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO;YAE5D,OAAOH,OAAO,EAAE,CAACI;QACrB,EAAE,OAAOE,OAAO;YACZ,OAAON,OAAO,IAAI,CAAC,IAAIC,2BAA2BK;QACtD;IACJ;AACJ;AAEO,MAAMC,sDAA4BC,0BAAAA,oBAA0C,CAAC;IAChF,gBAAgBzB;IAChB,cAAc;QACV0B;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
1
+ {"version":3,"file":"features/UpdateEntryLock/UpdateEntryLockRepository.js","sources":["../../../src/features/UpdateEntryLock/UpdateEntryLockRepository.ts"],"sourcesContent":["import { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { UpdateEntryUseCase } from \"@webiny/api-headless-cms/features/contentEntry/UpdateEntry\";\nimport { GetEntryByIdUseCase } from \"@webiny/api-headless-cms/features/contentEntry/GetEntryById\";\nimport { Result } from \"@webiny/feature/api\";\nimport { createIdentifier } from \"@webiny/utils\";\nimport { UpdateEntryLockRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { RecordLockingConfig } from \"~/domain/abstractions.js\";\nimport { RecordLockingModelProvider } from \"~/domain/abstractions.js\";\nimport type { ILockRecord } from \"~/domain/LockRecord.js\";\nimport { LockRecord } from \"~/domain/LockRecord.js\";\nimport type { LockRecordValues } from \"~/domain/types.js\";\nimport { LockRecordPersistenceError } from \"~/domain/errors.js\";\nimport { createLockRecordDatabaseId } from \"~/utils/lockRecordDatabaseId.js\";\n\nclass UpdateEntryLockRepositoryImpl implements RepositoryAbstraction.Interface {\n constructor(\n private modelProvider: RecordLockingModelProvider.Interface,\n private config: RecordLockingConfig.Interface,\n private identityContext: IdentityContext.Interface,\n private updateEntry: UpdateEntryUseCase.Interface,\n private getEntryById: GetEntryByIdUseCase.Interface\n ) {}\n\n async update(\n lockRecordId: string,\n updateOwner: boolean\n ): Promise<Result<ILockRecord, RepositoryAbstraction.Error>> {\n try {\n const model = await this.modelProvider.get();\n\n const entryId = createLockRecordDatabaseId(lockRecordId);\n const id = createIdentifier({\n id: entryId,\n version: 1\n });\n\n const identity = this.identityContext.getIdentity();\n const now = new Date().toISOString();\n\n // Build update data\n const updateData: any = {\n savedOn: now\n };\n\n // If updating owner (expired lock), also update created fields\n if (updateOwner) {\n updateData.createdOn = now;\n updateData.createdBy = identity;\n updateData.savedBy = identity;\n }\n\n const result = await this.updateEntry.execute(model, id, updateData);\n\n if (result.isFail()) {\n return Result.fail(new LockRecordPersistenceError(result.error));\n }\n\n // Fetch the updated entry to return full lock record\n const getResult = await this.getEntryById.execute<LockRecordValues>(model, id);\n\n if (getResult.isFail()) {\n return Result.fail(new LockRecordPersistenceError(getResult.error));\n }\n\n const entry = getResult.value;\n const lockRecord = new LockRecord(entry, this.config.timeout);\n\n return Result.ok(lockRecord);\n } catch (error) {\n return Result.fail(new LockRecordPersistenceError(error as Error));\n }\n }\n}\n\nexport const UpdateEntryLockRepository = RepositoryAbstraction.createImplementation({\n implementation: UpdateEntryLockRepositoryImpl,\n dependencies: [\n RecordLockingModelProvider,\n RecordLockingConfig,\n IdentityContext,\n UpdateEntryUseCase,\n GetEntryByIdUseCase\n ]\n});\n"],"names":["UpdateEntryLockRepositoryImpl","modelProvider","config","identityContext","updateEntry","getEntryById","lockRecordId","updateOwner","model","entryId","createLockRecordDatabaseId","id","createIdentifier","identity","now","Date","updateData","result","Result","LockRecordPersistenceError","getResult","entry","lockRecord","LockRecord","error","UpdateEntryLockRepository","RepositoryAbstraction","RecordLockingModelProvider","RecordLockingConfig","IdentityContext","UpdateEntryUseCase","GetEntryByIdUseCase"],"mappings":";;;;;;;;;;AAcA,MAAMA;IACF,YACYC,aAAmD,EACnDC,MAAqC,EACrCC,eAA0C,EAC1CC,WAAyC,EACzCC,YAA2C,CACrD;aALUJ,aAAa,GAAbA;aACAC,MAAM,GAANA;aACAC,eAAe,GAAfA;aACAC,WAAW,GAAXA;aACAC,YAAY,GAAZA;IACT;IAEH,MAAM,OACFC,YAAoB,EACpBC,WAAoB,EACqC;QACzD,IAAI;YACA,MAAMC,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG;YAE1C,MAAMC,UAAUC,2BAA2BJ;YAC3C,MAAMK,KAAKC,iBAAiB;gBACxB,IAAIH;gBACJ,SAAS;YACb;YAEA,MAAMI,WAAW,IAAI,CAAC,eAAe,CAAC,WAAW;YACjD,MAAMC,MAAM,IAAIC,OAAO,WAAW;YAGlC,MAAMC,aAAkB;gBACpB,SAASF;YACb;YAGA,IAAIP,aAAa;gBACbS,WAAW,SAAS,GAAGF;gBACvBE,WAAW,SAAS,GAAGH;gBACvBG,WAAW,OAAO,GAAGH;YACzB;YAEA,MAAMI,SAAS,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAACT,OAAOG,IAAIK;YAEzD,IAAIC,OAAO,MAAM,IACb,OAAOC,OAAO,IAAI,CAAC,IAAIC,2BAA2BF,OAAO,KAAK;YAIlE,MAAMG,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAmBZ,OAAOG;YAE3E,IAAIS,UAAU,MAAM,IAChB,OAAOF,OAAO,IAAI,CAAC,IAAIC,2BAA2BC,UAAU,KAAK;YAGrE,MAAMC,QAAQD,UAAU,KAAK;YAC7B,MAAME,aAAa,IAAIC,WAAWF,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO;YAE5D,OAAOH,OAAO,EAAE,CAACI;QACrB,EAAE,OAAOE,OAAO;YACZ,OAAON,OAAO,IAAI,CAAC,IAAIC,2BAA2BK;QACtD;IACJ;AACJ;AAEO,MAAMC,sDAA4BC,0BAAAA,oBAA0C,CAAC;IAChF,gBAAgB1B;IAChB,cAAc;QACV2B;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
@@ -0,0 +1,23 @@
1
+ import { GraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
2
+ import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
3
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
4
+ import { ListModelsUseCase } from "@webiny/api-headless-cms/features/contentModel/ListModels/index.js";
5
+ import { CmsModelFieldToGraphQLRegistry } from "@webiny/api-headless-cms/exports/api/cms/graphql.js";
6
+ import { RecordLockingModelProvider } from "../domain/abstractions.js";
7
+ /**
8
+ * The record locking GraphQL schema. The lock record type is rendered from the lock record model,
9
+ * which is loaded when the schema is composed.
10
+ */
11
+ declare class RecordLockingGraphQLSchemaImpl implements GraphQLSchemaFactory.Interface {
12
+ private readonly tenantContext;
13
+ private readonly identityContext;
14
+ private readonly modelProvider;
15
+ private readonly listModelsUseCase;
16
+ private readonly fieldRegistry;
17
+ constructor(tenantContext: TenantContext.Interface, identityContext: IdentityContext.Interface, modelProvider: RecordLockingModelProvider.Interface, listModelsUseCase: ListModelsUseCase.Interface, fieldRegistry: CmsModelFieldToGraphQLRegistry.Interface);
18
+ execute(builder: GraphQLSchemaFactory.SchemaBuilder): Promise<GraphQLSchemaFactory.SchemaBuilder>;
19
+ }
20
+ export declare const RecordLockingGraphQLSchema: typeof RecordLockingGraphQLSchemaImpl & {
21
+ __abstraction: import("@webiny/di").Abstraction<import("@webiny/api-graphql/graphql/abstractions.public.js").IGraphQLSchemaFactory>;
22
+ };
23
+ export {};
@@ -0,0 +1,372 @@
1
+ import { GraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
2
+ import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
3
+ import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
4
+ import { ListModelsUseCase } from "@webiny/api-headless-cms/features/contentModel/ListModels/index.js";
5
+ import { CmsModelFieldToGraphQLRegistry } from "@webiny/api-headless-cms/exports/api/cms/graphql.js";
6
+ import { renderFields } from "@webiny/api-headless-cms/utils/renderFields.js";
7
+ import { renderListFilterFields } from "@webiny/api-headless-cms/utils/renderListFilterFields.js";
8
+ import { renderSortEnum } from "@webiny/api-headless-cms/utils/renderSortEnum.js";
9
+ import { RecordLockingModelProvider } from "../domain/abstractions.js";
10
+ import { IsEntryLockedUseCase } from "../features/IsEntryLocked/abstractions.js";
11
+ import { GetLockRecordUseCase } from "../features/GetLockRecord/abstractions.js";
12
+ import { GetLockedEntryLockRecordUseCase } from "../features/GetLockedEntryLockRecord/abstractions.js";
13
+ import { ListLockRecordsUseCase } from "../features/ListLockRecords/abstractions.js";
14
+ import { ListAllLockRecordsUseCase } from "../features/ListAllLockRecords/abstractions.js";
15
+ import { LockEntryUseCase } from "../features/LockEntry/abstractions.js";
16
+ import { UpdateEntryLockUseCase } from "../features/UpdateEntryLock/abstractions.js";
17
+ import { UnlockEntryUseCase } from "../features/UnlockEntry/abstractions.js";
18
+ import { UnlockEntryRequestUseCase } from "../features/UnlockEntryRequest/abstractions.js";
19
+ import { resolve, resolveList } from "./resolve.js";
20
+ import { checkPermissions } from "./checkPermissions.js";
21
+ function renderTypeDefs(params) {
22
+ const { model, fieldRegistry } = params;
23
+ const models = params.models.filter((model)=>model.fields.length > 0);
24
+ const recordLockingFields = renderFields({
25
+ models,
26
+ model,
27
+ fields: model.fields,
28
+ type: "manage",
29
+ fieldRegistry
30
+ });
31
+ const listFilterFieldsRender = renderListFilterFields({
32
+ model,
33
+ fields: model.fields,
34
+ type: "manage",
35
+ fieldRegistry,
36
+ excludeFields: [
37
+ "entryId"
38
+ ]
39
+ });
40
+ const sortEnumRender = renderSortEnum({
41
+ model,
42
+ fields: model.fields,
43
+ fieldRegistry,
44
+ sorters: []
45
+ });
46
+ return `
47
+ ${recordLockingFields.map((f)=>f.typeDefs).join("\n")}
48
+
49
+ type RecordLockingError {
50
+ message: String
51
+ code: String
52
+ data: JSON
53
+ stack: String
54
+ }
55
+
56
+ enum RecordLockingRecordActionType {
57
+ requested
58
+ approved
59
+ denied
60
+ }
61
+
62
+ type RecordLockingIdentity {
63
+ id: String!
64
+ displayName: String
65
+ type: String
66
+ }
67
+
68
+ type RecordLockingRecordAction {
69
+ id: ID!
70
+ type: RecordLockingRecordActionType!
71
+ message: String
72
+ createdBy: RecordLockingIdentity!
73
+ createdOn: DateTime!
74
+ }
75
+
76
+ type RecordLockingRecord {
77
+ id: ID!
78
+ lockedBy: RecordLockingIdentity!
79
+ lockedOn: DateTime!
80
+ updatedOn: DateTime!
81
+ expiresOn: DateTime!
82
+ ${recordLockingFields.map((f)=>f.fields).join("\n")}
83
+ }
84
+
85
+ type RecordLockingIsEntryLockedResponse {
86
+ data: Boolean
87
+ error: RecordLockingError
88
+ }
89
+
90
+ type RecordLockingGetLockRecordResponse {
91
+ data: RecordLockingRecord
92
+ error: RecordLockingError
93
+ }
94
+
95
+ type RecordLockingGetLockedEntryLockRecordResponse {
96
+ data: RecordLockingRecord
97
+ error: RecordLockingError
98
+ }
99
+
100
+ type RecordLockingListLockRecordsResponse {
101
+ data: [RecordLockingRecord!]
102
+ error: RecordLockingError
103
+ }
104
+
105
+ type RecordLockingLockEntryResponse {
106
+ data: RecordLockingRecord
107
+ error: RecordLockingError
108
+ }
109
+
110
+ type RecordLockingUpdateLockResponse {
111
+ data: RecordLockingRecord
112
+ error: RecordLockingError
113
+ }
114
+
115
+ type RecordLockingUnlockEntryResponse {
116
+ data: RecordLockingRecord
117
+ error: RecordLockingError
118
+ }
119
+
120
+ type RecordLockingUnlockEntryRequestResponse {
121
+ data: RecordLockingRecord
122
+ error: RecordLockingError
123
+ }
124
+
125
+ input RecordLockingListWhereInput {
126
+ ${listFilterFieldsRender.allFiltersAsString()}
127
+ }
128
+
129
+ enum RecordLockingListSorter {
130
+ ${sortEnumRender}
131
+ }
132
+
133
+ type RecordLockingQuery {
134
+ _empty: String
135
+ }
136
+
137
+ type RecordLockingMutation {
138
+ _empty: String
139
+ }
140
+
141
+ extend type RecordLockingQuery {
142
+ isEntryLocked(id: ID!, type: String!): RecordLockingIsEntryLockedResponse!
143
+ getLockRecord(id: ID!, type: String!): RecordLockingGetLockRecordResponse!
144
+ # Returns lock record or null - if entry is locked in context of the current user, does not throw an error like getLockRecord if no record in the DB
145
+ getLockedEntryLockRecord(id: ID!, type: String!): RecordLockingGetLockedEntryLockRecordResponse!
146
+ listAllLockRecords(
147
+ where: RecordLockingListWhereInput
148
+ sort: [RecordLockingListSorter!]
149
+ limit: Int
150
+ after: String
151
+ ): RecordLockingListLockRecordsResponse!
152
+ # Basically same as listAllLockRecords except this one will filter out records with expired lock.
153
+ listLockRecords(
154
+ where: RecordLockingListWhereInput
155
+ sort: [RecordLockingListSorter!]
156
+ limit: Int
157
+ after: String
158
+ ): RecordLockingListLockRecordsResponse!
159
+ }
160
+
161
+ extend type RecordLockingMutation {
162
+ lockEntry(id: ID!, type: String!): RecordLockingLockEntryResponse!
163
+ updateEntryLock(id: ID!, type: String!): RecordLockingUpdateLockResponse!
164
+ unlockEntry(id: ID!, type: String!, force: Boolean): RecordLockingUnlockEntryResponse!
165
+ unlockEntryRequest(
166
+ id: ID!
167
+ type: String!
168
+ ): RecordLockingUnlockEntryRequestResponse!
169
+ }
170
+
171
+ extend type Query {
172
+ recordLocking: RecordLockingQuery
173
+ }
174
+
175
+ extend type Mutation {
176
+ recordLocking: RecordLockingMutation
177
+ }
178
+ `;
179
+ }
180
+ function addQueryResolvers(builder) {
181
+ builder.addResolver({
182
+ path: "Query.recordLocking",
183
+ resolver: ()=>async ()=>({})
184
+ });
185
+ builder.addResolver({
186
+ path: "RecordLockingQuery.isEntryLocked",
187
+ dependencies: [
188
+ IdentityContext,
189
+ IsEntryLockedUseCase
190
+ ],
191
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
192
+ checkPermissions(identityContext);
193
+ const result = await useCase.execute({
194
+ id: args.id,
195
+ type: args.type
196
+ });
197
+ if (result.isFail()) throw result.error;
198
+ return result.value;
199
+ })
200
+ });
201
+ builder.addResolver({
202
+ path: "RecordLockingQuery.getLockRecord",
203
+ dependencies: [
204
+ IdentityContext,
205
+ GetLockRecordUseCase
206
+ ],
207
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
208
+ checkPermissions(identityContext);
209
+ const result = await useCase.execute({
210
+ id: args.id,
211
+ type: args.type
212
+ });
213
+ if (result.isFail()) throw result.error;
214
+ return result.value;
215
+ })
216
+ });
217
+ builder.addResolver({
218
+ path: "RecordLockingQuery.getLockedEntryLockRecord",
219
+ dependencies: [
220
+ IdentityContext,
221
+ GetLockedEntryLockRecordUseCase
222
+ ],
223
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
224
+ checkPermissions(identityContext);
225
+ const result = await useCase.execute({
226
+ id: args.id,
227
+ type: args.type
228
+ });
229
+ if (result.isFail()) return null;
230
+ return result.value;
231
+ })
232
+ });
233
+ builder.addResolver({
234
+ path: "RecordLockingQuery.listLockRecords",
235
+ dependencies: [
236
+ IdentityContext,
237
+ ListLockRecordsUseCase
238
+ ],
239
+ resolver: (identityContext, useCase)=>({ args })=>resolveList(async ()=>{
240
+ checkPermissions(identityContext);
241
+ const result = await useCase.execute(args);
242
+ if (result.isFail()) throw result.error;
243
+ return result.value;
244
+ })
245
+ });
246
+ builder.addResolver({
247
+ path: "RecordLockingQuery.listAllLockRecords",
248
+ dependencies: [
249
+ IdentityContext,
250
+ ListAllLockRecordsUseCase
251
+ ],
252
+ resolver: (identityContext, useCase)=>({ args })=>resolveList(async ()=>{
253
+ checkPermissions(identityContext);
254
+ const result = await useCase.execute(args);
255
+ if (result.isFail()) throw result.error;
256
+ return result.value;
257
+ })
258
+ });
259
+ }
260
+ function addMutationResolvers(builder) {
261
+ builder.addResolver({
262
+ path: "Mutation.recordLocking",
263
+ resolver: ()=>async ()=>({})
264
+ });
265
+ builder.addResolver({
266
+ path: "RecordLockingMutation.lockEntry",
267
+ dependencies: [
268
+ IdentityContext,
269
+ LockEntryUseCase
270
+ ],
271
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
272
+ checkPermissions(identityContext);
273
+ const result = await useCase.execute({
274
+ id: args.id,
275
+ type: args.type
276
+ });
277
+ if (result.isFail()) throw result.error;
278
+ return result.value;
279
+ })
280
+ });
281
+ builder.addResolver({
282
+ path: "RecordLockingMutation.updateEntryLock",
283
+ dependencies: [
284
+ IdentityContext,
285
+ UpdateEntryLockUseCase
286
+ ],
287
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
288
+ checkPermissions(identityContext);
289
+ const result = await useCase.execute({
290
+ id: args.id,
291
+ type: args.type
292
+ });
293
+ if (result.isFail()) throw result.error;
294
+ return result.value;
295
+ })
296
+ });
297
+ builder.addResolver({
298
+ path: "RecordLockingMutation.unlockEntry",
299
+ dependencies: [
300
+ IdentityContext,
301
+ UnlockEntryUseCase
302
+ ],
303
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
304
+ checkPermissions(identityContext);
305
+ const result = await useCase.execute({
306
+ id: args.id,
307
+ type: args.type,
308
+ force: args.force
309
+ });
310
+ if (result.isFail()) throw result.error;
311
+ return result.value;
312
+ })
313
+ });
314
+ builder.addResolver({
315
+ path: "RecordLockingMutation.unlockEntryRequest",
316
+ dependencies: [
317
+ IdentityContext,
318
+ UnlockEntryRequestUseCase
319
+ ],
320
+ resolver: (identityContext, useCase)=>({ args })=>resolve(async ()=>{
321
+ checkPermissions(identityContext);
322
+ const result = await useCase.execute({
323
+ id: args.id,
324
+ type: args.type
325
+ });
326
+ if (result.isFail()) throw result.error;
327
+ return result.value;
328
+ })
329
+ });
330
+ }
331
+ class RecordLockingGraphQLSchemaImpl {
332
+ constructor(tenantContext, identityContext, modelProvider, listModelsUseCase, fieldRegistry){
333
+ this.tenantContext = tenantContext;
334
+ this.identityContext = identityContext;
335
+ this.modelProvider = modelProvider;
336
+ this.listModelsUseCase = listModelsUseCase;
337
+ this.fieldRegistry = fieldRegistry;
338
+ }
339
+ async execute(builder) {
340
+ if (!this.tenantContext.getTenant()) return builder;
341
+ const model = await this.modelProvider.get();
342
+ const models = await this.identityContext.withoutAuthorization(async ()=>{
343
+ const result = await this.listModelsUseCase.execute({
344
+ includePrivate: false
345
+ });
346
+ if (result.isFail()) throw result.error;
347
+ return result.value;
348
+ });
349
+ const typeDefs = renderTypeDefs({
350
+ model,
351
+ models,
352
+ fieldRegistry: this.fieldRegistry
353
+ });
354
+ builder.addTypeDefs(typeDefs);
355
+ addQueryResolvers(builder);
356
+ addMutationResolvers(builder);
357
+ return builder;
358
+ }
359
+ }
360
+ const RecordLockingGraphQLSchema = GraphQLSchemaFactory.createImplementation({
361
+ implementation: RecordLockingGraphQLSchemaImpl,
362
+ dependencies: [
363
+ TenantContext,
364
+ IdentityContext,
365
+ RecordLockingModelProvider,
366
+ ListModelsUseCase,
367
+ CmsModelFieldToGraphQLRegistry
368
+ ]
369
+ });
370
+ export { RecordLockingGraphQLSchema };
371
+
372
+ //# sourceMappingURL=RecordLockingGraphQLSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql/RecordLockingGraphQLSchema.js","sources":["../../src/graphql/RecordLockingGraphQLSchema.ts"],"sourcesContent":["import { GraphQLSchemaFactory } from \"@webiny/api-graphql/graphql/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { ListModelsUseCase } from \"@webiny/api-headless-cms/features/contentModel/ListModels/index.js\";\nimport { CmsModelFieldToGraphQLRegistry } from \"@webiny/api-headless-cms/exports/api/cms/graphql.js\";\nimport { renderFields } from \"@webiny/api-headless-cms/utils/renderFields.js\";\nimport { renderListFilterFields } from \"@webiny/api-headless-cms/utils/renderListFilterFields.js\";\nimport { renderSortEnum } from \"@webiny/api-headless-cms/utils/renderSortEnum.js\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types/model.js\";\nimport { RecordLockingModelProvider } from \"~/domain/abstractions.js\";\nimport { IsEntryLockedUseCase } from \"~/features/IsEntryLocked/abstractions.js\";\nimport { GetLockRecordUseCase } from \"~/features/GetLockRecord/abstractions.js\";\nimport { GetLockedEntryLockRecordUseCase } from \"~/features/GetLockedEntryLockRecord/abstractions.js\";\nimport { ListLockRecordsUseCase } from \"~/features/ListLockRecords/abstractions.js\";\nimport type { ListLockRecordsInput } from \"~/features/ListLockRecords/abstractions.js\";\nimport { ListAllLockRecordsUseCase } from \"~/features/ListAllLockRecords/abstractions.js\";\nimport type { ListAllLockRecordsInput } from \"~/features/ListAllLockRecords/abstractions.js\";\nimport { LockEntryUseCase } from \"~/features/LockEntry/abstractions.js\";\nimport { UpdateEntryLockUseCase } from \"~/features/UpdateEntryLock/abstractions.js\";\nimport { UnlockEntryUseCase } from \"~/features/UnlockEntry/abstractions.js\";\nimport { UnlockEntryRequestUseCase } from \"~/features/UnlockEntryRequest/abstractions.js\";\nimport { resolve } from \"./resolve.js\";\nimport { resolveList } from \"./resolve.js\";\nimport { checkPermissions } from \"./checkPermissions.js\";\n\ninterface IEntryArgs {\n id: string;\n type: string;\n}\n\ninterface IUnlockEntryArgs extends IEntryArgs {\n force?: boolean;\n}\n\ninterface IResolverParams<TArgs = unknown> {\n args: TArgs;\n}\n\ninterface IRenderTypeDefsParams {\n model: CmsModel;\n models: CmsModel[];\n fieldRegistry: CmsModelFieldToGraphQLRegistry.Interface;\n}\n\nfunction renderTypeDefs(params: IRenderTypeDefsParams): string {\n const { model, fieldRegistry } = params;\n\n const models = params.models.filter(model => {\n return model.fields.length > 0;\n });\n\n const recordLockingFields = renderFields({\n models,\n model,\n fields: model.fields,\n type: \"manage\",\n fieldRegistry\n });\n\n const listFilterFieldsRender = renderListFilterFields({\n model,\n fields: model.fields,\n type: \"manage\",\n fieldRegistry,\n excludeFields: [\"entryId\"]\n });\n\n const sortEnumRender = renderSortEnum({\n model,\n fields: model.fields,\n fieldRegistry,\n sorters: []\n });\n\n return /* GraphQL */ `\n ${recordLockingFields.map(f => f.typeDefs).join(\"\\n\")}\n\n type RecordLockingError {\n message: String\n code: String\n data: JSON\n stack: String\n }\n\n enum RecordLockingRecordActionType {\n requested\n approved\n denied\n }\n\n type RecordLockingIdentity {\n id: String!\n displayName: String\n type: String\n }\n\n type RecordLockingRecordAction {\n id: ID!\n type: RecordLockingRecordActionType!\n message: String\n createdBy: RecordLockingIdentity!\n createdOn: DateTime!\n }\n\n type RecordLockingRecord {\n id: ID!\n lockedBy: RecordLockingIdentity!\n lockedOn: DateTime!\n updatedOn: DateTime!\n expiresOn: DateTime!\n ${recordLockingFields.map(f => f.fields).join(\"\\n\")}\n }\n\n type RecordLockingIsEntryLockedResponse {\n data: Boolean\n error: RecordLockingError\n }\n\n type RecordLockingGetLockRecordResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n type RecordLockingGetLockedEntryLockRecordResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n type RecordLockingListLockRecordsResponse {\n data: [RecordLockingRecord!]\n error: RecordLockingError\n }\n\n type RecordLockingLockEntryResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n type RecordLockingUpdateLockResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n type RecordLockingUnlockEntryResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n type RecordLockingUnlockEntryRequestResponse {\n data: RecordLockingRecord\n error: RecordLockingError\n }\n\n input RecordLockingListWhereInput {\n ${listFilterFieldsRender.allFiltersAsString()}\n }\n\n enum RecordLockingListSorter {\n ${sortEnumRender}\n }\n\n type RecordLockingQuery {\n _empty: String\n }\n\n type RecordLockingMutation {\n _empty: String\n }\n\n extend type RecordLockingQuery {\n isEntryLocked(id: ID!, type: String!): RecordLockingIsEntryLockedResponse!\n getLockRecord(id: ID!, type: String!): RecordLockingGetLockRecordResponse!\n # Returns lock record or null - if entry is locked in context of the current user, does not throw an error like getLockRecord if no record in the DB\n getLockedEntryLockRecord(id: ID!, type: String!): RecordLockingGetLockedEntryLockRecordResponse!\n listAllLockRecords(\n where: RecordLockingListWhereInput\n sort: [RecordLockingListSorter!]\n limit: Int\n after: String\n ): RecordLockingListLockRecordsResponse!\n # Basically same as listAllLockRecords except this one will filter out records with expired lock.\n listLockRecords(\n where: RecordLockingListWhereInput\n sort: [RecordLockingListSorter!]\n limit: Int\n after: String\n ): RecordLockingListLockRecordsResponse!\n }\n\n extend type RecordLockingMutation {\n lockEntry(id: ID!, type: String!): RecordLockingLockEntryResponse!\n updateEntryLock(id: ID!, type: String!): RecordLockingUpdateLockResponse!\n unlockEntry(id: ID!, type: String!, force: Boolean): RecordLockingUnlockEntryResponse!\n unlockEntryRequest(\n id: ID!\n type: String!\n ): RecordLockingUnlockEntryRequestResponse!\n }\n\n extend type Query {\n recordLocking: RecordLockingQuery\n }\n\n extend type Mutation {\n recordLocking: RecordLockingMutation\n }\n `;\n}\n\nfunction addQueryResolvers(builder: GraphQLSchemaFactory.SchemaBuilder): void {\n builder.addResolver({\n path: \"Query.recordLocking\",\n resolver: () => async () => ({})\n });\n\n builder.addResolver({\n path: \"RecordLockingQuery.isEntryLocked\",\n dependencies: [IdentityContext, IsEntryLockedUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: IsEntryLockedUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingQuery.getLockRecord\",\n dependencies: [IdentityContext, GetLockRecordUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: GetLockRecordUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingQuery.getLockedEntryLockRecord\",\n dependencies: [IdentityContext, GetLockedEntryLockRecordUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: GetLockedEntryLockRecordUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n // Returns null if not found/expired/locked by current user.\n if (result.isFail()) {\n return null;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingQuery.listLockRecords\",\n dependencies: [IdentityContext, ListLockRecordsUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: ListLockRecordsUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<ListLockRecordsInput>) => {\n return resolveList(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute(args);\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingQuery.listAllLockRecords\",\n dependencies: [IdentityContext, ListAllLockRecordsUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: ListAllLockRecordsUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<ListAllLockRecordsInput>) => {\n return resolveList(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute(args);\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n}\n\nfunction addMutationResolvers(builder: GraphQLSchemaFactory.SchemaBuilder): void {\n builder.addResolver({\n path: \"Mutation.recordLocking\",\n resolver: () => async () => ({})\n });\n\n builder.addResolver({\n path: \"RecordLockingMutation.lockEntry\",\n dependencies: [IdentityContext, LockEntryUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: LockEntryUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingMutation.updateEntryLock\",\n dependencies: [IdentityContext, UpdateEntryLockUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: UpdateEntryLockUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingMutation.unlockEntry\",\n dependencies: [IdentityContext, UnlockEntryUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: UnlockEntryUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IUnlockEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type,\n force: args.force\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n\n builder.addResolver({\n path: \"RecordLockingMutation.unlockEntryRequest\",\n dependencies: [IdentityContext, UnlockEntryRequestUseCase],\n resolver: (\n identityContext: IdentityContext.Interface,\n useCase: UnlockEntryRequestUseCase.Interface\n ) => {\n return ({ args }: IResolverParams<IEntryArgs>) => {\n return resolve(async () => {\n checkPermissions(identityContext);\n const result = await useCase.execute({\n id: args.id,\n type: args.type\n });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n };\n }\n });\n}\n\n/**\n * The record locking GraphQL schema. The lock record type is rendered from the lock record model,\n * which is loaded when the schema is composed.\n */\nclass RecordLockingGraphQLSchemaImpl implements GraphQLSchemaFactory.Interface {\n public constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly identityContext: IdentityContext.Interface,\n private readonly modelProvider: RecordLockingModelProvider.Interface,\n private readonly listModelsUseCase: ListModelsUseCase.Interface,\n private readonly fieldRegistry: CmsModelFieldToGraphQLRegistry.Interface\n ) {}\n\n public async execute(\n builder: GraphQLSchemaFactory.SchemaBuilder\n ): Promise<GraphQLSchemaFactory.SchemaBuilder> {\n // There is no tenant until installation completes, and no model to render a schema from.\n if (!this.tenantContext.getTenant()) {\n return builder;\n }\n\n const model = await this.modelProvider.get();\n\n // The model list feeds `ref` field rendering. ListModels is filtered by permission, so it\n // is read without authorization to keep the schema the same for every identity.\n const models = await this.identityContext.withoutAuthorization(async () => {\n const result = await this.listModelsUseCase.execute({ includePrivate: false });\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n\n const typeDefs = renderTypeDefs({\n model,\n models,\n fieldRegistry: this.fieldRegistry\n });\n\n builder.addTypeDefs(typeDefs);\n addQueryResolvers(builder);\n addMutationResolvers(builder);\n\n return builder;\n }\n}\n\nexport const RecordLockingGraphQLSchema = GraphQLSchemaFactory.createImplementation({\n implementation: RecordLockingGraphQLSchemaImpl,\n dependencies: [\n TenantContext,\n IdentityContext,\n RecordLockingModelProvider,\n ListModelsUseCase,\n CmsModelFieldToGraphQLRegistry\n ]\n});\n"],"names":["renderTypeDefs","params","model","fieldRegistry","models","recordLockingFields","renderFields","listFilterFieldsRender","renderListFilterFields","sortEnumRender","renderSortEnum","f","addQueryResolvers","builder","IdentityContext","IsEntryLockedUseCase","identityContext","useCase","args","resolve","checkPermissions","result","GetLockRecordUseCase","GetLockedEntryLockRecordUseCase","ListLockRecordsUseCase","resolveList","ListAllLockRecordsUseCase","addMutationResolvers","LockEntryUseCase","UpdateEntryLockUseCase","UnlockEntryUseCase","UnlockEntryRequestUseCase","RecordLockingGraphQLSchemaImpl","tenantContext","modelProvider","listModelsUseCase","typeDefs","RecordLockingGraphQLSchema","GraphQLSchemaFactory","TenantContext","RecordLockingModelProvider","ListModelsUseCase","CmsModelFieldToGraphQLRegistry"],"mappings":"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"}