@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.
- package/content/plugins/crud/contentEntry/afterDelete.d.ts +7 -0
- package/content/plugins/crud/contentEntry/afterDelete.js +41 -0
- package/content/plugins/crud/contentEntry/markLockedFields.d.ts +7 -3
- package/content/plugins/crud/contentEntry/markLockedFields.js +41 -7
- package/content/plugins/crud/contentEntry/referenceFieldsMapping.d.ts +12 -0
- package/content/plugins/crud/contentEntry/referenceFieldsMapping.js +251 -0
- package/content/plugins/crud/contentEntry.crud.d.ts +0 -4
- package/content/plugins/crud/contentEntry.crud.js +127 -51
- package/content/plugins/crud/contentModel/beforeCreate.js +1 -1
- package/content/plugins/crud/index.js +6 -4
- package/content/plugins/graphqlFields/ref.js +70 -34
- package/content/plugins/modelManager/DefaultCmsModelManager.js +7 -1
- package/content/plugins/schema/contentEntries.js +39 -28
- package/content/plugins/schema/createManageResolvers.js +6 -2
- package/content/plugins/schema/createManageSDL.js +2 -0
- package/content/plugins/schema/resolvers/manage/resolveDelete.js +7 -1
- package/content/plugins/schema/resolvers/manage/resolveRepublish.d.ts +2 -0
- package/content/plugins/schema/resolvers/manage/resolveRepublish.js +21 -0
- package/content/plugins/utils/renderSortEnum.js +12 -12
- package/content/plugins/validators/patternPlugins/index.js +5 -1
- package/content/plugins/validators/patternPlugins/lowerCaseSpace.d.ts +3 -0
- package/content/plugins/validators/patternPlugins/lowerCaseSpace.js +17 -0
- package/content/plugins/validators/patternPlugins/upperCaseSpace.d.ts +3 -0
- package/content/plugins/validators/patternPlugins/upperCaseSpace.js +17 -0
- package/index.d.ts +1 -1
- package/package.json +24 -23
- package/plugins/crud/index.js +20 -2
- package/plugins/crud/system.crud.js +25 -7
- package/types.d.ts +25 -36
- 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
|
|
2
|
+
export interface MarkLockedFieldsParams {
|
|
3
3
|
model: CmsModel;
|
|
4
4
|
entry: CmsEntry;
|
|
5
5
|
context: CmsContext;
|
|
6
6
|
}
|
|
7
|
-
export declare const markLockedFields: (
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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;
|