@webiny/api-headless-cms 5.18.3 → 5.19.0-beta.3

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 (30) hide show
  1. package/content/plugins/crud/contentEntry/afterDelete.d.ts +7 -0
  2. package/content/plugins/crud/contentEntry/afterDelete.js +41 -0
  3. package/content/plugins/crud/contentEntry/markLockedFields.d.ts +7 -3
  4. package/content/plugins/crud/contentEntry/markLockedFields.js +41 -7
  5. package/content/plugins/crud/contentEntry/referenceFieldsMapping.d.ts +12 -0
  6. package/content/plugins/crud/contentEntry/referenceFieldsMapping.js +251 -0
  7. package/content/plugins/crud/contentEntry.crud.d.ts +0 -4
  8. package/content/plugins/crud/contentEntry.crud.js +127 -51
  9. package/content/plugins/crud/contentModel/beforeCreate.js +1 -1
  10. package/content/plugins/crud/index.js +6 -4
  11. package/content/plugins/graphqlFields/ref.js +70 -34
  12. package/content/plugins/modelManager/DefaultCmsModelManager.js +7 -1
  13. package/content/plugins/schema/contentEntries.js +39 -28
  14. package/content/plugins/schema/createManageResolvers.js +6 -2
  15. package/content/plugins/schema/createManageSDL.js +2 -0
  16. package/content/plugins/schema/resolvers/manage/resolveDelete.js +7 -1
  17. package/content/plugins/schema/resolvers/manage/resolveRepublish.d.ts +2 -0
  18. package/content/plugins/schema/resolvers/manage/resolveRepublish.js +21 -0
  19. package/content/plugins/utils/renderSortEnum.js +12 -12
  20. package/content/plugins/validators/patternPlugins/index.js +5 -1
  21. package/content/plugins/validators/patternPlugins/lowerCaseSpace.d.ts +3 -0
  22. package/content/plugins/validators/patternPlugins/lowerCaseSpace.js +17 -0
  23. package/content/plugins/validators/patternPlugins/upperCaseSpace.d.ts +3 -0
  24. package/content/plugins/validators/patternPlugins/upperCaseSpace.js +17 -0
  25. package/index.d.ts +1 -1
  26. package/package.json +24 -23
  27. package/plugins/crud/index.js +20 -2
  28. package/plugins/crud/system.crud.js +25 -7
  29. package/types.d.ts +25 -36
  30. package/types.js +0 -6
@@ -0,0 +1,7 @@
1
+ import { Topic } from "@webiny/pubsub/types";
2
+ import { AfterEntryDeleteTopicParams, CmsContext } from "../../../../types";
3
+ export interface Params {
4
+ context: CmsContext;
5
+ onAfterDelete: Topic<AfterEntryDeleteTopicParams>;
6
+ }
7
+ export declare const assignAfterEntryDelete: (params: Params) => void;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.assignAfterEntryDelete = void 0;
7
+
8
+ var _markLockedFields = require("./markLockedFields");
9
+
10
+ const assignAfterEntryDelete = params => {
11
+ const {
12
+ context,
13
+ onAfterDelete
14
+ } = params;
15
+ onAfterDelete.subscribe(async params => {
16
+ const {
17
+ entry,
18
+ model
19
+ } = params;
20
+ const {
21
+ items
22
+ } = await context.cms.storageOperations.entries.list(model, {
23
+ where: {
24
+ entryId_not: entry.entryId,
25
+ latest: true
26
+ },
27
+ limit: 1
28
+ });
29
+
30
+ if (items.length > 0) {
31
+ return;
32
+ }
33
+
34
+ await (0, _markLockedFields.markUnlockedFields)({
35
+ context,
36
+ model
37
+ });
38
+ });
39
+ };
40
+
41
+ exports.assignAfterEntryDelete = assignAfterEntryDelete;
@@ -1,8 +1,12 @@
1
1
  import { CmsEntry, CmsModel, CmsContext } from "../../../../types";
2
- interface Args {
2
+ export interface MarkLockedFieldsParams {
3
3
  model: CmsModel;
4
4
  entry: CmsEntry;
5
5
  context: CmsContext;
6
6
  }
7
- export declare const markLockedFields: ({ model, context }: Args) => Promise<void>;
8
- export {};
7
+ export declare const markLockedFields: (params: MarkLockedFieldsParams) => Promise<void>;
8
+ export interface MarkFieldsUnlockedParams {
9
+ context: CmsContext;
10
+ model: CmsModel;
11
+ }
12
+ export declare const markUnlockedFields: (params: MarkFieldsUnlockedParams) => Promise<void>;
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.markLockedFields = void 0;
8
+ exports.markUnlockedFields = exports.markLockedFields = void 0;
9
9
 
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
 
@@ -17,11 +17,15 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
17
17
 
18
18
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
19
19
 
20
- const markLockedFields = async ({
21
- model,
22
- context
23
- }) => {
24
- // If the model is registered via a plugin, we don't need do process anything.
20
+ const markLockedFields = async params => {
21
+ const {
22
+ model,
23
+ context
24
+ } = params;
25
+ /**
26
+ * If the model is registered via a plugin, we don't need do process anything.
27
+ */
28
+
25
29
  const plugins = context.plugins.byType(_CmsModelPlugin.CmsModelPlugin.type);
26
30
 
27
31
  if (plugins.find(plugin => plugin.contentModel.modelId === model.modelId)) {
@@ -80,4 +84,34 @@ const markLockedFields = async ({
80
84
  }
81
85
  };
82
86
 
83
- exports.markLockedFields = markLockedFields;
87
+ exports.markLockedFields = markLockedFields;
88
+
89
+ const markUnlockedFields = async params => {
90
+ const {
91
+ context,
92
+ model
93
+ } = params;
94
+ /**
95
+ * If the model is registered via a plugin, we don't need do process anything.
96
+ */
97
+
98
+ const plugins = context.plugins.byType(_CmsModelPlugin.CmsModelPlugin.type);
99
+
100
+ if (plugins.find(plugin => plugin.contentModel.modelId === model.modelId)) {
101
+ return;
102
+ }
103
+
104
+ try {
105
+ await context.cms.updateModelDirect({
106
+ original: model,
107
+ model: _objectSpread(_objectSpread({}, model), {}, {
108
+ lockedFields: []
109
+ })
110
+ });
111
+ model.lockedFields = [];
112
+ } catch (ex) {
113
+ throw new _error.default(`Could not update model "${model.modelId}" with unlocked fields.`, "MODEL_UNLOCKED_FIELDS_UPDATE_FAILED", ex);
114
+ }
115
+ };
116
+
117
+ exports.markUnlockedFields = markUnlockedFields;
@@ -0,0 +1,12 @@
1
+ import { CmsContext, CmsModel } from "../../../../types";
2
+ interface ReferenceObject {
3
+ id: string;
4
+ modelId: string;
5
+ }
6
+ interface Params {
7
+ context: CmsContext;
8
+ model: CmsModel;
9
+ input: Record<string, ReferenceObject | ReferenceObject[]>;
10
+ }
11
+ export declare const referenceFieldsMapping: (params: Params) => Promise<Record<string, any>>;
12
+ export {};
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.referenceFieldsMapping = void 0;
9
+
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+
12
+ var _error = _interopRequireDefault(require("@webiny/error"));
13
+
14
+ var _dotProp = _interopRequireDefault(require("dot-prop"));
15
+
16
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
17
+
18
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
19
+
20
+ const buildReferenceFieldPaths = params => {
21
+ const {
22
+ fields,
23
+ parentPaths: initialParentPaths,
24
+ input
25
+ } = params;
26
+ const parentPaths = [].concat(initialParentPaths);
27
+ const isMultipleValues = Array.isArray(input);
28
+ return fields.filter(field => ["object", "ref"].includes(field.type)).reduce((collection, field) => {
29
+ /**
30
+ * First we check the ref field
31
+ */
32
+ if (field.type === "ref") {
33
+ const parentPathsValue = parentPaths.length > 0 ? `${parentPaths.join(".")}.` : "";
34
+
35
+ if (field.multipleValues) {
36
+ const inputValue = _dotProp.default.get(input, `${field.fieldId}`, []);
37
+
38
+ if (Array.isArray(inputValue) === false) {
39
+ return collection;
40
+ }
41
+
42
+ for (const key in inputValue) {
43
+ const path = `${parentPathsValue}${field.fieldId}.${key}`;
44
+ collection.push(path);
45
+ }
46
+
47
+ return collection;
48
+ }
49
+
50
+ if (isMultipleValues) {
51
+ for (const key in input) {
52
+ const path = `${parentPathsValue}${key}.${field.fieldId}`;
53
+ collection.push(path);
54
+ }
55
+
56
+ return collection;
57
+ }
58
+
59
+ collection.push(`${parentPathsValue}${field.fieldId}`);
60
+ return collection;
61
+ }
62
+ /**
63
+ * Then we move onto the object field
64
+ */
65
+
66
+
67
+ const parentPathsValue = parentPaths.length > 0 ? `${parentPaths.join(".")}.` : "";
68
+ /**
69
+ * This is if received input is array. We need to map key with fieldId at this point.
70
+ */
71
+
72
+ if (isMultipleValues) {
73
+ for (const key in input) {
74
+ const path = `${parentPathsValue}${key}.${field.fieldId}`;
75
+ collection.push(path);
76
+ }
77
+
78
+ return collection;
79
+ }
80
+
81
+ const objFieldPath = `${field.fieldId}`;
82
+
83
+ const objFieldInputValue = _dotProp.default.get(input, objFieldPath, []);
84
+ /**
85
+ * If field is multiple values one, we need to go through the input and use the existing keys.
86
+ */
87
+
88
+
89
+ if (field.multipleValues) {
90
+ if (Array.isArray(objFieldInputValue) === false) {
91
+ return collection;
92
+ }
93
+
94
+ for (const key in objFieldInputValue) {
95
+ const result = buildReferenceFieldPaths({
96
+ fields: field.settings.fields,
97
+ input: objFieldInputValue[key],
98
+ parentPaths: parentPaths.concat([field.fieldId, key])
99
+ });
100
+ collection.push(...result);
101
+ }
102
+
103
+ return collection;
104
+ }
105
+ /**
106
+ * Single value reference field.
107
+ */
108
+
109
+
110
+ const results = buildReferenceFieldPaths({
111
+ fields: field.settings.fields,
112
+ input: objFieldInputValue,
113
+ parentPaths: parentPaths.concat([field.fieldId])
114
+ });
115
+ return collection.concat(results);
116
+ }, []);
117
+ };
118
+
119
+ const referenceFieldsMapping = async params => {
120
+ const {
121
+ context,
122
+ model,
123
+ input
124
+ } = params;
125
+
126
+ let output = _objectSpread({}, input);
127
+
128
+ const referenceFieldPaths = buildReferenceFieldPaths({
129
+ fields: model.fields,
130
+ input,
131
+ parentPaths: []
132
+ });
133
+
134
+ if (referenceFieldPaths.length === 0) {
135
+ return output;
136
+ }
137
+
138
+ const referencesByModel = {};
139
+ const pathsByReferenceId = {};
140
+
141
+ for (const path of referenceFieldPaths) {
142
+ const ref = _dotProp.default.get(output, path);
143
+
144
+ if (!ref || !ref.id || !ref.modelId) {
145
+ continue;
146
+ }
147
+
148
+ if (!referencesByModel[ref.modelId]) {
149
+ referencesByModel[ref.modelId] = [];
150
+ }
151
+
152
+ referencesByModel[ref.modelId].push(ref.id);
153
+
154
+ if (!pathsByReferenceId[ref.id]) {
155
+ pathsByReferenceId[ref.id] = [];
156
+ }
157
+
158
+ pathsByReferenceId[ref.id].push(path);
159
+ }
160
+ /**
161
+ * Again, no point in going further.
162
+ */
163
+
164
+
165
+ if (Object.keys(referencesByModel).length === 0) {
166
+ return output;
167
+ }
168
+ /**
169
+ * Load all models and use only those that are used in reference.
170
+ */
171
+
172
+
173
+ const models = (await context.cms.listModels()).filter(model => {
174
+ const entries = referencesByModel[model.modelId];
175
+
176
+ if (Array.isArray(entries) === false || entries.length === 0) {
177
+ return false;
178
+ }
179
+
180
+ return true;
181
+ });
182
+ /**
183
+ * Check for any model existence, just in case.
184
+ */
185
+
186
+ if (models.length === 0) {
187
+ return output;
188
+ }
189
+ /**
190
+ * Load all the entries by their ID
191
+ */
192
+
193
+
194
+ const promises = models.map(model => {
195
+ return context.cms.getEntriesByIds(model, referencesByModel[model.modelId]);
196
+ });
197
+ const results = await Promise.all(promises);
198
+ const records = results.reduce((collection, entries) => {
199
+ for (const entry of entries) {
200
+ collection[entry.id] = entry;
201
+ }
202
+
203
+ return collection;
204
+ }, {});
205
+ /**
206
+ * Verify that all referenced entries actually exist.
207
+ */
208
+
209
+ for (const modelId in referencesByModel) {
210
+ const entries = referencesByModel[modelId];
211
+
212
+ for (const entry of entries) {
213
+ if (records[entry]) {
214
+ continue;
215
+ }
216
+
217
+ throw new _error.default(`Missing referenced entry with id "${entry}" in model "${modelId}".`, "ENTRY_NOT_FOUND", {
218
+ entry,
219
+ model: modelId
220
+ });
221
+ }
222
+ }
223
+ /**
224
+ * In the end, assign the entryId, id and model values to the output.
225
+ */
226
+
227
+
228
+ for (const id in pathsByReferenceId) {
229
+ const entry = records[id];
230
+ const paths = pathsByReferenceId[id];
231
+
232
+ if (!entry) {
233
+ throw new _error.default("Missing entry in records.", "ENTRY_ERROR", {
234
+ id,
235
+ paths
236
+ });
237
+ }
238
+
239
+ for (const path of paths) {
240
+ output = _dotProp.default.set(output, path, {
241
+ id: entry.id,
242
+ entryId: entry.entryId,
243
+ modelId: entry.modelId
244
+ });
245
+ }
246
+ }
247
+
248
+ return output;
249
+ };
250
+
251
+ exports.referenceFieldsMapping = referenceFieldsMapping;
@@ -1,6 +1,4 @@
1
1
  import { CmsEntryContext, CmsContext, HeadlessCmsStorageOperations } from "../../../types";
2
- import { I18NLocale } from "@webiny/api-i18n/types";
3
- import { Tenant } from "@webiny/api-tenancy/types";
4
2
  import { SecurityIdentity } from "@webiny/api-security/types";
5
3
  export declare const STATUS_DRAFT = "draft";
6
4
  export declare const STATUS_PUBLISHED = "published";
@@ -10,8 +8,6 @@ export declare const STATUS_REVIEW_REQUESTED = "reviewRequested";
10
8
  export interface Params {
11
9
  storageOperations: HeadlessCmsStorageOperations;
12
10
  context: CmsContext;
13
- getTenant: () => Tenant;
14
- getLocale: () => I18NLocale;
15
11
  getIdentity: () => SecurityIdentity;
16
12
  }
17
13
  export declare const createContentEntryCrud: (params: Params) => CmsEntryContext;