/
CmsSnapshot.js
155 lines (130 loc) · 4.72 KB
/
CmsSnapshot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
const { MemoryCache } = require('@thinkpixellab-public/px-long-operations');
const chunkArray = require('./utils/chunkArray');
// limit concurrency in parallel api calls
const PARALLEL_API_CALL_LIMIT = 25;
class CmsSnapshot {
constructor(manifest, source) {
// give each CMS an ID
if (manifest.version) {
this.id = 'published-' + manifest.version;
} else {
this.id = new Date().toISOString();
}
this.manifest = manifest;
this.source = source;
this._collectionsCache = {};
// general purpose cache that can be used by clients that need to cache
// computed results based on data fetched from the CMS
this.cache = new MemoryCache();
}
getMediaUrl(mediaInfo) {
if (
mediaInfo &&
typeof mediaInfo === 'object' &&
mediaInfo.libraryId &&
mediaInfo.fileId &&
mediaInfo.extension &&
this.manifest.media
) {
const library = this.manifest.media[mediaInfo.libraryId];
if (library && library.publicUrl) {
return library.publicUrl + mediaInfo.fileId + '.' + mediaInfo.extension;
}
}
return null;
}
getMediaDetails(mediaInfo) {
if (
mediaInfo &&
typeof mediaInfo === 'object' &&
mediaInfo.libraryId &&
mediaInfo.fileId &&
mediaInfo.extension
) {
const library = (this.manifest.media || {})[mediaInfo.libraryId];
const libraryPublicUrl = library?.publicUrl;
let publicUrl = (libraryPublicUrl || '') + mediaInfo.fileId + '.' + mediaInfo.extension;
const details = {
libraryPublicUrl,
libraryId: mediaInfo.libraryId,
extension: mediaInfo.extension,
fileId: mediaInfo.fileId,
publicUrl,
};
// add height and width (not always available)
if (mediaInfo.width && mediaInfo.height) {
details.width = mediaInfo.width;
details.height = mediaInfo.height;
}
return details;
}
return null;
}
async getItem(collectionId, itemId) {
const collectionItemVersions = this.manifest.collections[collectionId];
if (collectionItemVersions) {
const itemVersion = collectionItemVersions[itemId];
if (itemVersion) {
return this.source.getItem(collectionId, itemId, itemVersion);
}
}
return null;
}
async getItems(collectionId) {
// see if we have the cached item
const cachedItems = this._collectionsCache[collectionId];
if (cachedItems) {
return cachedItems;
}
let items = [];
const collectionItems = this.manifest.collections[collectionId];
if (collectionItems) {
// fetch items in parallel
const itemIds = Object.keys(collectionItems);
let fetchedItems = [];
for (const idChunks of chunkArray(itemIds, PARALLEL_API_CALL_LIMIT)) {
const chunkItems = await Promise.all(
idChunks.map(itemId => this.getItem(collectionId, itemId))
);
fetchedItems = fetchedItems.concat(chunkItems);
}
// remove any empty items
items = fetchedItems.filter(item => !!item);
this._collectionsCache[collectionId] = items;
}
return items;
}
async getLocalizedString(
collectionId,
itemId,
locale,
fallbackToSource = true,
fallbackToId = true
) {
let result = null;
const entry = await this.getItem(collectionId, itemId);
if (entry) {
const localeEntry = entry[locale];
if (localeEntry?.selected) {
result = localeEntry[localeEntry.selected];
}
if (fallbackToSource && (result === null || result === undefined)) {
result = entry.source;
}
}
// fallback to loc-id if no entry was found
if (fallbackToId && (result === null || result === undefined)) {
return itemId;
}
return result;
}
async getLocalizedLookup(locale, lookupEntry) {
// if a collectionId and itemId are found, lookup localized string
if (lookupEntry?.collectionId && lookupEntry?.itemId) {
return this.getLocalizedString(lookupEntry.collectionId, lookupEntry.itemId, locale);
}
// otherwise use non-localized text if set
return lookupEntry?.text;
}
}
module.exports = CmsSnapshot;