@agility/content-sync 1.1.2 → 1.1.4
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/.babelrc +6 -6
- package/.vscode/launch.json +34 -34
- package/README.md +206 -206
- package/dist/agility-sync-sdk.node.js +4244 -1473
- package/package.json +46 -46
- package/src/methods/clearSync.js +7 -7
- package/src/methods/runSync.js +94 -94
- package/src/methods/syncContent.js +80 -80
- package/src/methods/syncPages.js +75 -75
- package/src/store-interface-console.js +72 -72
- package/src/store-interface-filesystem.js +201 -198
- package/src/store-interface.js +511 -505
- package/src/sync-client.js +74 -74
- package/src/util.js +45 -45
- package/test/01-getSyncClient.tests.js +37 -37
- package/test/02-runSync.tests.js +74 -74
- package/test/03-store.getContentItem.tests.js +25 -25
- package/test/04-store.getContentList.tests.js +67 -67
- package/test/05-store.getPage.tests.js +25 -25
- package/test/06-store.getRedirects.tests.js +26 -26
- package/test/99-clearSync.tests.js +29 -29
- package/test/_syncClients.config.js +57 -57
- package/webpack.config.js +32 -32
package/src/store-interface.js
CHANGED
|
@@ -1,505 +1,511 @@
|
|
|
1
|
-
import {
|
|
2
|
-
logDebug,
|
|
3
|
-
logInfo,
|
|
4
|
-
logError,
|
|
5
|
-
logWarning,
|
|
6
|
-
logSuccess,
|
|
7
|
-
asyncForEach,
|
|
8
|
-
} from "./util";
|
|
9
|
-
|
|
10
|
-
let store = null;
|
|
11
|
-
let options = null;
|
|
12
|
-
|
|
13
|
-
const validateStoreInterface = (storeCandidate) => {
|
|
14
|
-
if (!storeCandidate.clearItems) {
|
|
15
|
-
throw new TypeError(
|
|
16
|
-
"Your sync store interface must implement `clearItems`."
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!storeCandidate.deleteItem) {
|
|
21
|
-
throw new TypeError(
|
|
22
|
-
"Your sync store interface must implement `deleteItem`."
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!storeCandidate.getItem) {
|
|
27
|
-
throw new TypeError("Your sync store interface must implement `getItem`.");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!storeCandidate.saveItem) {
|
|
31
|
-
throw new TypeError("Your sync store interface must implement `saveItem`.");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!storeCandidate.mergeItemToList) {
|
|
35
|
-
throw new TypeError(
|
|
36
|
-
"Your sync store interface must implement `mergeItemToList`."
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const setStore = (storeToUse, storeOptions) => {
|
|
42
|
-
validateStoreInterface(storeToUse);
|
|
43
|
-
store = storeToUse;
|
|
44
|
-
options = storeOptions;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const getStore = () => {
|
|
48
|
-
return store
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// sanitize graphql node names
|
|
52
|
-
const sanitizeName = (name) => {
|
|
53
|
-
|
|
54
|
-
if (name !== undefined && name !== null) {
|
|
55
|
-
return name.replace(/\W/g, "")
|
|
56
|
-
} else {
|
|
57
|
-
return null
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const saveContentItem = async ({ contentItem, languageCode }) => {
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
!contentItem ||
|
|
66
|
-
!contentItem.properties
|
|
67
|
-
) {
|
|
68
|
-
logWarning("Null item or item with no properties cannot be saved");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let definitionName = sanitizeName(contentItem.properties.definitionName)
|
|
73
|
-
let referenceName = contentItem.properties.referenceName
|
|
74
|
-
|
|
75
|
-
if (contentItem.properties.state === 3) {
|
|
76
|
-
//if the item is deleted
|
|
77
|
-
|
|
78
|
-
//grab the reference name from the currently saved item...
|
|
79
|
-
const currentItem = await store.getItem({
|
|
80
|
-
options,
|
|
81
|
-
itemType: "item",
|
|
82
|
-
languageCode,
|
|
83
|
-
itemID: contentItem.contentID,
|
|
84
|
-
});
|
|
85
|
-
if (currentItem) {
|
|
86
|
-
|
|
87
|
-
//if the item is deleted, we need to grab the def and ref name from the current
|
|
88
|
-
definitionName = sanitizeName(currentItem.properties.definitionName)
|
|
89
|
-
referenceName = currentItem.properties.referenceName
|
|
90
|
-
|
|
91
|
-
await store.deleteItem({
|
|
92
|
-
options,
|
|
93
|
-
itemType: "item",
|
|
94
|
-
languageCode,
|
|
95
|
-
itemID: contentItem.contentID,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
//regular item
|
|
100
|
-
if (!contentItem.properties.definitionName
|
|
101
|
-
|| !contentItem.properties.referenceName) {
|
|
102
|
-
logWarning(`Content with id ${contentItem.contentID} does not have the neccessary properties to be saved.`)
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await store.saveItem({
|
|
109
|
-
options,
|
|
110
|
-
item: contentItem,
|
|
111
|
-
itemType: "item",
|
|
112
|
-
languageCode,
|
|
113
|
-
itemID: contentItem.contentID,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (referenceName) {
|
|
118
|
-
//merge the item by reference or definition name - it might need to be merged into a list
|
|
119
|
-
await store.mergeItemToList({
|
|
120
|
-
options,
|
|
121
|
-
item: contentItem,
|
|
122
|
-
languageCode,
|
|
123
|
-
itemID: contentItem.contentID,
|
|
124
|
-
referenceName,
|
|
125
|
-
definitionName,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const savePageItem = async ({ pageItem, languageCode }) => {
|
|
131
|
-
if (pageItem.properties.state === 3) {
|
|
132
|
-
//item is deleted
|
|
133
|
-
await store.deleteItem({
|
|
134
|
-
options,
|
|
135
|
-
itemType: "page",
|
|
136
|
-
languageCode,
|
|
137
|
-
itemID: pageItem.pageID,
|
|
138
|
-
});
|
|
139
|
-
} else {
|
|
140
|
-
//regular item
|
|
141
|
-
await store.saveItem({
|
|
142
|
-
options,
|
|
143
|
-
item: pageItem,
|
|
144
|
-
itemType: "page",
|
|
145
|
-
languageCode,
|
|
146
|
-
itemID: pageItem.pageID,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const saveSitemap = async ({ sitemap, channelName, languageCode }) => {
|
|
152
|
-
await store.saveItem({
|
|
153
|
-
options,
|
|
154
|
-
item: sitemap,
|
|
155
|
-
itemType: "sitemap",
|
|
156
|
-
languageCode,
|
|
157
|
-
itemID: channelName,
|
|
158
|
-
});
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const saveSitemapNested = async ({
|
|
162
|
-
sitemapNested,
|
|
163
|
-
channelName,
|
|
164
|
-
languageCode,
|
|
165
|
-
}) => {
|
|
166
|
-
await store.saveItem({
|
|
167
|
-
options,
|
|
168
|
-
item: sitemapNested,
|
|
169
|
-
itemType: "nestedsitemap",
|
|
170
|
-
languageCode,
|
|
171
|
-
itemID: channelName,
|
|
172
|
-
});
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const saveUrlRedirections = async ({ urlRedirections, languageCode }) => {
|
|
176
|
-
await store.saveItem({
|
|
177
|
-
options,
|
|
178
|
-
item: urlRedirections,
|
|
179
|
-
itemType: "urlredirections",
|
|
180
|
-
languageCode,
|
|
181
|
-
itemID: "urlredirections",
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const getUrlRedirections = async ({ languageCode }) => {
|
|
186
|
-
return await store.getItem({
|
|
187
|
-
options,
|
|
188
|
-
itemType: "urlredirections",
|
|
189
|
-
languageCode,
|
|
190
|
-
itemID: "urlredirections",
|
|
191
|
-
});
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const saveSyncState = async ({ syncState, languageCode }) => {
|
|
195
|
-
await store.saveItem({
|
|
196
|
-
options,
|
|
197
|
-
item: syncState,
|
|
198
|
-
itemType: "state",
|
|
199
|
-
languageCode,
|
|
200
|
-
itemID: "sync",
|
|
201
|
-
});
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const getSyncState = async (languageCode) => {
|
|
205
|
-
return await store.getItem({
|
|
206
|
-
options,
|
|
207
|
-
itemType: "state",
|
|
208
|
-
languageCode,
|
|
209
|
-
itemID: "sync",
|
|
210
|
-
});
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Gets the details of a content item by its Content ID.
|
|
215
|
-
* @memberof AgilitySync.Client.Content
|
|
216
|
-
* @param {Object} requestParams - The paramters for the SDK request.
|
|
217
|
-
* @param {number} requestParams.contentID - The contentID of the requested item in this language.
|
|
218
|
-
* @param {string} requestParams.languageCode - The language code of the content you want to retrieve.
|
|
219
|
-
* @param {number} [requestParams.depth] - The depth, representing the levels in which you want linked content auto-resolved. Default is **1**.
|
|
220
|
-
* @param {boolean} [requestParams.expandAllContentLinks] - Whether or not to expand entire linked content references, includings lists and items that are rendered in the CMS as Grid or Link. Default is **false**
|
|
221
|
-
* @returns {Promise<Object>} - Returns a content item object.
|
|
222
|
-
*/
|
|
223
|
-
const getContentItem = async ({ contentID, languageCode, depth, contentLinkDepth, expandAllContentLinks = false }) => {
|
|
224
|
-
|
|
225
|
-
if (depth === undefined && contentLinkDepth !== undefined) {
|
|
226
|
-
depth = contentLinkDepth
|
|
227
|
-
} else if (depth === undefined && contentLinkDepth === undefined) {
|
|
228
|
-
depth = 2
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const contentItem = await store.getItem({
|
|
232
|
-
options,
|
|
233
|
-
itemType: "item",
|
|
234
|
-
languageCode,
|
|
235
|
-
itemID: contentID,
|
|
236
|
-
});
|
|
237
|
-
return await expandContentItem({ contentItem, languageCode, depth, expandAllContentLinks });
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const expandContentItem = async ({ contentItem, languageCode, depth, expandAllContentLinks = false }) => {
|
|
241
|
-
if (!contentItem) return null;
|
|
242
|
-
|
|
243
|
-
if (depth > 0) {
|
|
244
|
-
//make this work for the .fields or the .customFields property...
|
|
245
|
-
let fields = contentItem.fields;
|
|
246
|
-
if (!fields) fields = contentItem.customFields;
|
|
247
|
-
for (const fieldName in fields) {
|
|
248
|
-
const fieldValue = fields[fieldName];
|
|
249
|
-
if (!fieldValue) {
|
|
250
|
-
//do nothing...
|
|
251
|
-
continue;
|
|
252
|
-
} else if (fieldValue.contentid > 0) {
|
|
253
|
-
//single linked item
|
|
254
|
-
const childItem = await getContentItem({
|
|
255
|
-
contentID: fieldValue.contentid,
|
|
256
|
-
languageCode,
|
|
257
|
-
depth: depth - 1,
|
|
258
|
-
});
|
|
259
|
-
if (childItem != null) fields[fieldName] = childItem;
|
|
260
|
-
} else if (fieldValue.fulllist === true
|
|
261
|
-
&& fieldValue.referencename
|
|
262
|
-
&& expandAllContentLinks === true) {
|
|
263
|
-
|
|
264
|
-
//LINK TO THE FULL LIST
|
|
265
|
-
const referenceName = fieldValue.referencename
|
|
266
|
-
|
|
267
|
-
const skip = 0
|
|
268
|
-
const take = 50
|
|
269
|
-
|
|
270
|
-
const list = await getContentList({
|
|
271
|
-
referenceName,
|
|
272
|
-
languageCode,
|
|
273
|
-
depth: depth - 1,
|
|
274
|
-
expandAllContentLinks,
|
|
275
|
-
skip,
|
|
276
|
-
take
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
let sortIDAry = []
|
|
280
|
-
|
|
281
|
-
if (fieldValue.sortids && fieldValue.sortids.split) {
|
|
282
|
-
sortIDAry = fieldValue.sortids.split(",");
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
let itemCount = 0
|
|
286
|
-
const childItems = [];
|
|
287
|
-
for (const childItemID of sortIDAry) {
|
|
288
|
-
itemCount++
|
|
289
|
-
const childItem = await getContentItem({
|
|
290
|
-
contentID: childItemID,
|
|
291
|
-
languageCode,
|
|
292
|
-
depth: depth - 1,
|
|
293
|
-
expandAllContentLinks,
|
|
294
|
-
skip,
|
|
295
|
-
take
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
if (childItem != null) {
|
|
299
|
-
childItems.push(childItem);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
for (const listItem of list.items) {
|
|
304
|
-
itemCount++
|
|
305
|
-
if (itemCount > 50) break;
|
|
306
|
-
|
|
307
|
-
const listItemContentID = listItem.contentID
|
|
308
|
-
if (sortIDAry.includes(`${listItemContentID}`)) {
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const childItem = await getContentItem({
|
|
313
|
-
contentID: listItemContentID,
|
|
314
|
-
languageCode,
|
|
315
|
-
depth: depth - 1,
|
|
316
|
-
expandAllContentLinks
|
|
317
|
-
});
|
|
318
|
-
if (childItem != null) childItems.push(childItem);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
fields[fieldName] = childItems;
|
|
322
|
-
|
|
323
|
-
} else if (fieldValue.sortids && fieldValue.sortids.split && fieldValue.fulllist !== true) {
|
|
324
|
-
//MULTI LINKED ITEM
|
|
325
|
-
let sortIDAry = []
|
|
326
|
-
if (fieldValue.sortids && fieldValue.sortids.split) {
|
|
327
|
-
sortIDAry = fieldValue.sortids.split(",");
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const skip = expandAllContentLinks ? 0 : undefined
|
|
331
|
-
const take = expandAllContentLinks ? 50 : undefined
|
|
332
|
-
|
|
333
|
-
const childItems = [];
|
|
334
|
-
for (const childItemID of sortIDAry) {
|
|
335
|
-
const childItem = await getContentItem({
|
|
336
|
-
contentID: childItemID,
|
|
337
|
-
languageCode,
|
|
338
|
-
depth: depth - 1,
|
|
339
|
-
expandAllContentLinks,
|
|
340
|
-
skip,
|
|
341
|
-
take
|
|
342
|
-
});
|
|
343
|
-
if (childItem != null) childItems.push(childItem);
|
|
344
|
-
}
|
|
345
|
-
fields[fieldName] = childItems;
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
return contentItem;
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Retrieves a list of content items by reference name. If skip or take has been specified, returns an object with an items array and totalCount property. Otherwise returns an array of items.
|
|
357
|
-
* @memberof AgilitySync.Client.Content
|
|
358
|
-
* @param {Object} requestParams - The parameters for this request.
|
|
359
|
-
* @param {string} requestParams.referenceName - The unique reference name of the content list you wish to retrieve in the specified language.
|
|
360
|
-
* @param {string} requestParams.languageCode - The language code of the content you want to retrieve.
|
|
361
|
-
* @param {number} [requestParams.depth] - The depth, representing the levels in which you want linked content auto-resolved. Default is **1**.
|
|
362
|
-
* @param {boolean} [requestParams.expandAllContentLinks] - Whether or not to expand entire linked content references, includings lists and items that are rendered in the CMS as Grid or Link. Default is **false**
|
|
363
|
-
* @param {number} [requestParams.take] - The maximum number of items to retrieve in this request.
|
|
364
|
-
* @param {number} [requestParams.skip] - The number of items to skip from the list. Used for implementing pagination.
|
|
365
|
-
* @returns {Promise<[] | Object>} - Returns a list of content items, or, if skip or take has been specified, an object with an items array and totalCount property.
|
|
366
|
-
*/
|
|
367
|
-
const getContentList = async ({ referenceName, languageCode, depth
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
//
|
|
413
|
-
return
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
1
|
+
import {
|
|
2
|
+
logDebug,
|
|
3
|
+
logInfo,
|
|
4
|
+
logError,
|
|
5
|
+
logWarning,
|
|
6
|
+
logSuccess,
|
|
7
|
+
asyncForEach,
|
|
8
|
+
} from "./util";
|
|
9
|
+
|
|
10
|
+
let store = null;
|
|
11
|
+
let options = null;
|
|
12
|
+
|
|
13
|
+
const validateStoreInterface = (storeCandidate) => {
|
|
14
|
+
if (!storeCandidate.clearItems) {
|
|
15
|
+
throw new TypeError(
|
|
16
|
+
"Your sync store interface must implement `clearItems`."
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!storeCandidate.deleteItem) {
|
|
21
|
+
throw new TypeError(
|
|
22
|
+
"Your sync store interface must implement `deleteItem`."
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!storeCandidate.getItem) {
|
|
27
|
+
throw new TypeError("Your sync store interface must implement `getItem`.");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!storeCandidate.saveItem) {
|
|
31
|
+
throw new TypeError("Your sync store interface must implement `saveItem`.");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!storeCandidate.mergeItemToList) {
|
|
35
|
+
throw new TypeError(
|
|
36
|
+
"Your sync store interface must implement `mergeItemToList`."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const setStore = (storeToUse, storeOptions) => {
|
|
42
|
+
validateStoreInterface(storeToUse);
|
|
43
|
+
store = storeToUse;
|
|
44
|
+
options = storeOptions;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getStore = () => {
|
|
48
|
+
return store
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// sanitize graphql node names
|
|
52
|
+
const sanitizeName = (name) => {
|
|
53
|
+
|
|
54
|
+
if (name !== undefined && name !== null) {
|
|
55
|
+
return name.replace(/\W/g, "")
|
|
56
|
+
} else {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const saveContentItem = async ({ contentItem, languageCode }) => {
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
!contentItem ||
|
|
66
|
+
!contentItem.properties
|
|
67
|
+
) {
|
|
68
|
+
logWarning("Null item or item with no properties cannot be saved");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let definitionName = sanitizeName(contentItem.properties.definitionName)
|
|
73
|
+
let referenceName = contentItem.properties.referenceName
|
|
74
|
+
|
|
75
|
+
if (contentItem.properties.state === 3) {
|
|
76
|
+
//if the item is deleted
|
|
77
|
+
|
|
78
|
+
//grab the reference name from the currently saved item...
|
|
79
|
+
const currentItem = await store.getItem({
|
|
80
|
+
options,
|
|
81
|
+
itemType: "item",
|
|
82
|
+
languageCode,
|
|
83
|
+
itemID: contentItem.contentID,
|
|
84
|
+
});
|
|
85
|
+
if (currentItem) {
|
|
86
|
+
|
|
87
|
+
//if the item is deleted, we need to grab the def and ref name from the current
|
|
88
|
+
definitionName = sanitizeName(currentItem.properties.definitionName)
|
|
89
|
+
referenceName = currentItem.properties.referenceName
|
|
90
|
+
|
|
91
|
+
await store.deleteItem({
|
|
92
|
+
options,
|
|
93
|
+
itemType: "item",
|
|
94
|
+
languageCode,
|
|
95
|
+
itemID: contentItem.contentID,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
//regular item
|
|
100
|
+
if (!contentItem.properties.definitionName
|
|
101
|
+
|| !contentItem.properties.referenceName) {
|
|
102
|
+
logWarning(`Content with id ${contentItem.contentID} does not have the neccessary properties to be saved.`)
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
await store.saveItem({
|
|
109
|
+
options,
|
|
110
|
+
item: contentItem,
|
|
111
|
+
itemType: "item",
|
|
112
|
+
languageCode,
|
|
113
|
+
itemID: contentItem.contentID,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (referenceName) {
|
|
118
|
+
//merge the item by reference or definition name - it might need to be merged into a list
|
|
119
|
+
await store.mergeItemToList({
|
|
120
|
+
options,
|
|
121
|
+
item: contentItem,
|
|
122
|
+
languageCode,
|
|
123
|
+
itemID: contentItem.contentID,
|
|
124
|
+
referenceName,
|
|
125
|
+
definitionName,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const savePageItem = async ({ pageItem, languageCode }) => {
|
|
131
|
+
if (pageItem.properties.state === 3) {
|
|
132
|
+
//item is deleted
|
|
133
|
+
await store.deleteItem({
|
|
134
|
+
options,
|
|
135
|
+
itemType: "page",
|
|
136
|
+
languageCode,
|
|
137
|
+
itemID: pageItem.pageID,
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
//regular item
|
|
141
|
+
await store.saveItem({
|
|
142
|
+
options,
|
|
143
|
+
item: pageItem,
|
|
144
|
+
itemType: "page",
|
|
145
|
+
languageCode,
|
|
146
|
+
itemID: pageItem.pageID,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const saveSitemap = async ({ sitemap, channelName, languageCode }) => {
|
|
152
|
+
await store.saveItem({
|
|
153
|
+
options,
|
|
154
|
+
item: sitemap,
|
|
155
|
+
itemType: "sitemap",
|
|
156
|
+
languageCode,
|
|
157
|
+
itemID: channelName,
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const saveSitemapNested = async ({
|
|
162
|
+
sitemapNested,
|
|
163
|
+
channelName,
|
|
164
|
+
languageCode,
|
|
165
|
+
}) => {
|
|
166
|
+
await store.saveItem({
|
|
167
|
+
options,
|
|
168
|
+
item: sitemapNested,
|
|
169
|
+
itemType: "nestedsitemap",
|
|
170
|
+
languageCode,
|
|
171
|
+
itemID: channelName,
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const saveUrlRedirections = async ({ urlRedirections, languageCode }) => {
|
|
176
|
+
await store.saveItem({
|
|
177
|
+
options,
|
|
178
|
+
item: urlRedirections,
|
|
179
|
+
itemType: "urlredirections",
|
|
180
|
+
languageCode,
|
|
181
|
+
itemID: "urlredirections",
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const getUrlRedirections = async ({ languageCode }) => {
|
|
186
|
+
return await store.getItem({
|
|
187
|
+
options,
|
|
188
|
+
itemType: "urlredirections",
|
|
189
|
+
languageCode,
|
|
190
|
+
itemID: "urlredirections",
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const saveSyncState = async ({ syncState, languageCode }) => {
|
|
195
|
+
await store.saveItem({
|
|
196
|
+
options,
|
|
197
|
+
item: syncState,
|
|
198
|
+
itemType: "state",
|
|
199
|
+
languageCode,
|
|
200
|
+
itemID: "sync",
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const getSyncState = async (languageCode) => {
|
|
205
|
+
return await store.getItem({
|
|
206
|
+
options,
|
|
207
|
+
itemType: "state",
|
|
208
|
+
languageCode,
|
|
209
|
+
itemID: "sync",
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Gets the details of a content item by its Content ID.
|
|
215
|
+
* @memberof AgilitySync.Client.Content
|
|
216
|
+
* @param {Object} requestParams - The paramters for the SDK request.
|
|
217
|
+
* @param {number} requestParams.contentID - The contentID of the requested item in this language.
|
|
218
|
+
* @param {string} requestParams.languageCode - The language code of the content you want to retrieve.
|
|
219
|
+
* @param {number} [requestParams.depth] - The depth, representing the levels in which you want linked content auto-resolved. Default is **1**.
|
|
220
|
+
* @param {boolean} [requestParams.expandAllContentLinks] - Whether or not to expand entire linked content references, includings lists and items that are rendered in the CMS as Grid or Link. Default is **false**
|
|
221
|
+
* @returns {Promise<Object>} - Returns a content item object.
|
|
222
|
+
*/
|
|
223
|
+
const getContentItem = async ({ contentID, languageCode, depth, contentLinkDepth, expandAllContentLinks = false }) => {
|
|
224
|
+
|
|
225
|
+
if (depth === undefined && contentLinkDepth !== undefined) {
|
|
226
|
+
depth = contentLinkDepth
|
|
227
|
+
} else if (depth === undefined && contentLinkDepth === undefined) {
|
|
228
|
+
depth = 2
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const contentItem = await store.getItem({
|
|
232
|
+
options,
|
|
233
|
+
itemType: "item",
|
|
234
|
+
languageCode,
|
|
235
|
+
itemID: contentID,
|
|
236
|
+
});
|
|
237
|
+
return await expandContentItem({ contentItem, languageCode, depth, expandAllContentLinks });
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const expandContentItem = async ({ contentItem, languageCode, depth, expandAllContentLinks = false }) => {
|
|
241
|
+
if (!contentItem) return null;
|
|
242
|
+
|
|
243
|
+
if (depth > 0) {
|
|
244
|
+
//make this work for the .fields or the .customFields property...
|
|
245
|
+
let fields = contentItem.fields;
|
|
246
|
+
if (!fields) fields = contentItem.customFields;
|
|
247
|
+
for (const fieldName in fields) {
|
|
248
|
+
const fieldValue = fields[fieldName];
|
|
249
|
+
if (!fieldValue) {
|
|
250
|
+
//do nothing...
|
|
251
|
+
continue;
|
|
252
|
+
} else if (fieldValue.contentid > 0) {
|
|
253
|
+
//single linked item
|
|
254
|
+
const childItem = await getContentItem({
|
|
255
|
+
contentID: fieldValue.contentid,
|
|
256
|
+
languageCode,
|
|
257
|
+
depth: depth - 1,
|
|
258
|
+
});
|
|
259
|
+
if (childItem != null) fields[fieldName] = childItem;
|
|
260
|
+
} else if (fieldValue.fulllist === true
|
|
261
|
+
&& fieldValue.referencename
|
|
262
|
+
&& expandAllContentLinks === true) {
|
|
263
|
+
|
|
264
|
+
//LINK TO THE FULL LIST
|
|
265
|
+
const referenceName = fieldValue.referencename
|
|
266
|
+
|
|
267
|
+
const skip = 0
|
|
268
|
+
const take = 50
|
|
269
|
+
|
|
270
|
+
const list = await getContentList({
|
|
271
|
+
referenceName,
|
|
272
|
+
languageCode,
|
|
273
|
+
depth: depth - 1,
|
|
274
|
+
expandAllContentLinks,
|
|
275
|
+
skip,
|
|
276
|
+
take
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
let sortIDAry = []
|
|
280
|
+
|
|
281
|
+
if (fieldValue.sortids && fieldValue.sortids.split) {
|
|
282
|
+
sortIDAry = fieldValue.sortids.split(",");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let itemCount = 0
|
|
286
|
+
const childItems = [];
|
|
287
|
+
for (const childItemID of sortIDAry) {
|
|
288
|
+
itemCount++
|
|
289
|
+
const childItem = await getContentItem({
|
|
290
|
+
contentID: childItemID,
|
|
291
|
+
languageCode,
|
|
292
|
+
depth: depth - 1,
|
|
293
|
+
expandAllContentLinks,
|
|
294
|
+
skip,
|
|
295
|
+
take
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
if (childItem != null) {
|
|
299
|
+
childItems.push(childItem);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
for (const listItem of list.items) {
|
|
304
|
+
itemCount++
|
|
305
|
+
if (itemCount > 50) break;
|
|
306
|
+
|
|
307
|
+
const listItemContentID = listItem.contentID
|
|
308
|
+
if (sortIDAry.includes(`${listItemContentID}`)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const childItem = await getContentItem({
|
|
313
|
+
contentID: listItemContentID,
|
|
314
|
+
languageCode,
|
|
315
|
+
depth: depth - 1,
|
|
316
|
+
expandAllContentLinks
|
|
317
|
+
});
|
|
318
|
+
if (childItem != null) childItems.push(childItem);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fields[fieldName] = childItems;
|
|
322
|
+
|
|
323
|
+
} else if (fieldValue.sortids && fieldValue.sortids.split && fieldValue.fulllist !== true) {
|
|
324
|
+
//MULTI LINKED ITEM
|
|
325
|
+
let sortIDAry = []
|
|
326
|
+
if (fieldValue.sortids && fieldValue.sortids.split) {
|
|
327
|
+
sortIDAry = fieldValue.sortids.split(",");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const skip = expandAllContentLinks ? 0 : undefined
|
|
331
|
+
const take = expandAllContentLinks ? 50 : undefined
|
|
332
|
+
|
|
333
|
+
const childItems = [];
|
|
334
|
+
for (const childItemID of sortIDAry) {
|
|
335
|
+
const childItem = await getContentItem({
|
|
336
|
+
contentID: childItemID,
|
|
337
|
+
languageCode,
|
|
338
|
+
depth: depth - 1,
|
|
339
|
+
expandAllContentLinks,
|
|
340
|
+
skip,
|
|
341
|
+
take
|
|
342
|
+
});
|
|
343
|
+
if (childItem != null) childItems.push(childItem);
|
|
344
|
+
}
|
|
345
|
+
fields[fieldName] = childItems;
|
|
346
|
+
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return contentItem;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Retrieves a list of content items by reference name. If skip or take has been specified, returns an object with an items array and totalCount property. Otherwise returns an array of items.
|
|
357
|
+
* @memberof AgilitySync.Client.Content
|
|
358
|
+
* @param {Object} requestParams - The parameters for this request.
|
|
359
|
+
* @param {string} requestParams.referenceName - The unique reference name of the content list you wish to retrieve in the specified language.
|
|
360
|
+
* @param {string} requestParams.languageCode - The language code of the content you want to retrieve.
|
|
361
|
+
* @param {number} [requestParams.depth] - The depth, representing the levels in which you want linked content auto-resolved. Default is **1**.
|
|
362
|
+
* @param {boolean} [requestParams.expandAllContentLinks] - Whether or not to expand entire linked content references, includings lists and items that are rendered in the CMS as Grid or Link. Default is **false**
|
|
363
|
+
* @param {number} [requestParams.take] - The maximum number of items to retrieve in this request.
|
|
364
|
+
* @param {number} [requestParams.skip] - The number of items to skip from the list. Used for implementing pagination.
|
|
365
|
+
* @returns {Promise<[] | Object>} - Returns a list of content items, or, if skip or take has been specified, an object with an items array and totalCount property.
|
|
366
|
+
*/
|
|
367
|
+
const getContentList = async ({ referenceName, languageCode, depth, contentLinkDepth, expandAllContentLinks = false, skip = -1, take = -1 }) => {
|
|
368
|
+
|
|
369
|
+
if (depth === undefined && contentLinkDepth !== undefined) {
|
|
370
|
+
depth = contentLinkDepth
|
|
371
|
+
} else if (depth === undefined && contentLinkDepth === undefined) {
|
|
372
|
+
depth = 0
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let lst = await store.getItem({
|
|
376
|
+
options,
|
|
377
|
+
itemType: "list",
|
|
378
|
+
languageCode,
|
|
379
|
+
itemID: referenceName,
|
|
380
|
+
}) || [];
|
|
381
|
+
|
|
382
|
+
if (depth > 0 && take === -1) {
|
|
383
|
+
throw new Error("If you specify depth > 0, you must also specify the take parameter.")
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (expandAllContentLinks && take === -1) {
|
|
387
|
+
throw new Error("If you specify expandAllContentLinks=true, you must also specify the take parameter.")
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const totalCount = lst.length
|
|
391
|
+
|
|
392
|
+
if (skip > 0 && skip < lst.length) {
|
|
393
|
+
lst = lst.slice(skip)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (take > 0 && take < lst.length) {
|
|
397
|
+
lst = lst.slice(0, take)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (depth > 0) {
|
|
401
|
+
for (let i=0; i<lst.length;i++) {
|
|
402
|
+
lst[i] = await expandContentItem({
|
|
403
|
+
contentItem: lst[i],
|
|
404
|
+
depth: depth - 1,
|
|
405
|
+
languageCode,
|
|
406
|
+
expandAllContentLinks
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (skip > 0 || take > 0) {
|
|
412
|
+
//if we have sliced this array, return an object with an items and totalCount property
|
|
413
|
+
return {
|
|
414
|
+
items: lst,
|
|
415
|
+
totalCount
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
//just return the full list
|
|
419
|
+
return lst
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* Get a Page based on it's id and languageCode.
|
|
429
|
+
* @param {*} { pageID, languageCode, depth = 3 }
|
|
430
|
+
* @returns
|
|
431
|
+
*/
|
|
432
|
+
const getPage = async ({ pageID, languageCode, depth, contentLinkDepth, expandAllContentLinks = false }) => {
|
|
433
|
+
|
|
434
|
+
if (depth === undefined && contentLinkDepth !== undefined) {
|
|
435
|
+
depth = contentLinkDepth
|
|
436
|
+
} else if (depth === undefined && contentLinkDepth === undefined) {
|
|
437
|
+
depth = 2
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
let pageItem = await store.getItem({
|
|
441
|
+
options,
|
|
442
|
+
itemType: "page",
|
|
443
|
+
languageCode,
|
|
444
|
+
itemID: pageID,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
if (depth > 0) {
|
|
448
|
+
//if a depth was specified, pull in the modules (content items) for this page
|
|
449
|
+
for (const zoneName in pageItem.zones) {
|
|
450
|
+
const zone = pageItem.zones[zoneName];
|
|
451
|
+
|
|
452
|
+
for (const mod of zone) {
|
|
453
|
+
const moduleItem = await getContentItem({
|
|
454
|
+
options,
|
|
455
|
+
contentID: mod.item.contentid,
|
|
456
|
+
languageCode,
|
|
457
|
+
depth: depth - 1,
|
|
458
|
+
expandAllContentLinks
|
|
459
|
+
});
|
|
460
|
+
mod.item = moduleItem;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return pageItem;
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
const getSitemap = async ({ channelName, languageCode }) => {
|
|
469
|
+
return await store.getItem({
|
|
470
|
+
options,
|
|
471
|
+
itemType: "sitemap",
|
|
472
|
+
languageCode,
|
|
473
|
+
itemID: channelName,
|
|
474
|
+
});
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
const getSitemapNested = async ({ channelName, languageCode }) => {
|
|
478
|
+
return await store.getItem({
|
|
479
|
+
options,
|
|
480
|
+
itemType: "nestedsitemap",
|
|
481
|
+
languageCode,
|
|
482
|
+
itemID: channelName,
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Clear everything out.
|
|
488
|
+
*/
|
|
489
|
+
const clear = async () => {
|
|
490
|
+
await store.clearItems({ options });
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
export default {
|
|
494
|
+
saveContentItem,
|
|
495
|
+
savePageItem,
|
|
496
|
+
getContentItem,
|
|
497
|
+
getContentList,
|
|
498
|
+
getPage,
|
|
499
|
+
getSitemap,
|
|
500
|
+
getSitemapFlat: getSitemap,
|
|
501
|
+
getSitemapNested,
|
|
502
|
+
saveSitemap,
|
|
503
|
+
saveSitemapNested,
|
|
504
|
+
saveUrlRedirections,
|
|
505
|
+
getUrlRedirections,
|
|
506
|
+
getSyncState,
|
|
507
|
+
saveSyncState,
|
|
508
|
+
clear,
|
|
509
|
+
setStore,
|
|
510
|
+
getStore
|
|
511
|
+
};
|