@nascentdigital/funnel-cms 4.4.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/dist/api/AssetClient.d.ts +53 -0
- package/dist/api/AssetClient.js +2 -0
- package/dist/api/AssetUploadClient.d.ts +17 -0
- package/dist/api/AssetUploadClient.js +26 -0
- package/dist/api/AuthClient.d.ts +29 -0
- package/dist/api/AuthClient.js +2 -0
- package/dist/api/ChangeSetClient.d.ts +84 -0
- package/dist/api/ChangeSetClient.js +31 -0
- package/dist/api/CollectionClient.d.ts +187 -0
- package/dist/api/CollectionClient.js +2 -0
- package/dist/api/ContentClient.d.ts +43 -0
- package/dist/api/ContentClient.js +34 -0
- package/dist/api/IAssetApiClient.d.ts +9 -0
- package/dist/api/IAssetApiClient.js +2 -0
- package/dist/api/PageClient.d.ts +264 -0
- package/dist/api/PageClient.js +2 -0
- package/dist/api/SiteClient.d.ts +23 -0
- package/dist/api/SiteClient.js +2 -0
- package/dist/api/SiteConfigClient.d.ts +26 -0
- package/dist/api/SiteConfigClient.js +2 -0
- package/dist/api/UpgradeClient.d.ts +16 -0
- package/dist/api/UpgradeClient.js +2 -0
- package/dist/api/UserClient.d.ts +46 -0
- package/dist/api/UserClient.js +2 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.js +27 -0
- package/dist/errors/CMSError.d.ts +8 -0
- package/dist/errors/CMSError.js +17 -0
- package/dist/errors/CMSErrors.d.ts +5 -0
- package/dist/errors/CMSErrors.js +36 -0
- package/dist/errors/LinkedDependantsError.d.ts +21 -0
- package/dist/errors/LinkedDependantsError.js +31 -0
- package/dist/errors/LockdownError.d.ts +4 -0
- package/dist/errors/LockdownError.js +12 -0
- package/dist/errors/SlugValidationError.d.ts +21 -0
- package/dist/errors/SlugValidationError.js +23 -0
- package/dist/errors/TranslateReferencesError.d.ts +21 -0
- package/dist/errors/TranslateReferencesError.js +22 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +25 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/models/Entity.d.ts +14 -0
- package/dist/models/Entity.js +2 -0
- package/dist/models/Environment.d.ts +1 -0
- package/dist/models/Environment.js +2 -0
- package/dist/models/Pagination.d.ts +20 -0
- package/dist/models/Pagination.js +21 -0
- package/dist/models/Privilege.d.ts +57 -0
- package/dist/models/Privilege.js +163 -0
- package/dist/models/Role.d.ts +33 -0
- package/dist/models/Role.js +118 -0
- package/dist/models/SiteConfig.d.ts +14 -0
- package/dist/models/SiteConfig.js +2 -0
- package/dist/models/Upgrade.d.ts +40 -0
- package/dist/models/Upgrade.js +19 -0
- package/dist/models/User.d.ts +41 -0
- package/dist/models/User.js +71 -0
- package/dist/models/Versioned.d.ts +22 -0
- package/dist/models/Versioned.js +45 -0
- package/dist/models/index.d.ts +9 -0
- package/dist/models/index.js +25 -0
- package/dist/strapi/IStrapiContentClient.d.ts +39 -0
- package/dist/strapi/IStrapiContentClient.js +2 -0
- package/dist/strapi/Strapi.d.ts +37 -0
- package/dist/strapi/Strapi.js +156 -0
- package/dist/strapi/StrapiAssetClient.d.ts +11 -0
- package/dist/strapi/StrapiAssetClient.js +143 -0
- package/dist/strapi/StrapiAssetUploadClient.d.ts +6 -0
- package/dist/strapi/StrapiAssetUploadClient.js +109 -0
- package/dist/strapi/StrapiAuthClient.d.ts +9 -0
- package/dist/strapi/StrapiAuthClient.js +64 -0
- package/dist/strapi/StrapiChangeSetClient.d.ts +22 -0
- package/dist/strapi/StrapiChangeSetClient.js +218 -0
- package/dist/strapi/StrapiCollectionClient.d.ts +18 -0
- package/dist/strapi/StrapiCollectionClient.js +610 -0
- package/dist/strapi/StrapiContentClient.d.ts +38 -0
- package/dist/strapi/StrapiContentClient.js +105 -0
- package/dist/strapi/StrapiContentClientFactory.d.ts +13 -0
- package/dist/strapi/StrapiContentClientFactory.js +19 -0
- package/dist/strapi/StrapiPageClient.d.ts +23 -0
- package/dist/strapi/StrapiPageClient.js +882 -0
- package/dist/strapi/StrapiSiteConfigClient.d.ts +8 -0
- package/dist/strapi/StrapiSiteConfigClient.js +50 -0
- package/dist/strapi/StrapiUpgradeClient.d.ts +13 -0
- package/dist/strapi/StrapiUpgradeClient.js +118 -0
- package/dist/strapi/StrapiUserClient.d.ts +17 -0
- package/dist/strapi/StrapiUserClient.js +199 -0
- package/dist/strapi/client.d.ts +1 -0
- package/dist/strapi/client.js +17 -0
- package/dist/strapi/index.d.ts +3 -0
- package/dist/strapi/index.js +19 -0
- package/dist/strapi/models/StrapiAsset.d.ts +10 -0
- package/dist/strapi/models/StrapiAsset.js +16 -0
- package/dist/strapi/models/StrapiData.d.ts +13 -0
- package/dist/strapi/models/StrapiData.js +16 -0
- package/dist/strapi/models/StrapiFile.d.ts +18 -0
- package/dist/strapi/models/StrapiFile.js +2 -0
- package/dist/strapi/models/index.d.ts +3 -0
- package/dist/strapi/models/index.js +19 -0
- package/dist/strapi/serialization/ChangeSetData.d.ts +15 -0
- package/dist/strapi/serialization/ChangeSetData.js +76 -0
- package/dist/strapi/serialization/CollectionData.d.ts +57 -0
- package/dist/strapi/serialization/CollectionData.js +258 -0
- package/dist/strapi/serialization/CollectionSnapshotData.d.ts +16 -0
- package/dist/strapi/serialization/CollectionSnapshotData.js +66 -0
- package/dist/strapi/serialization/PageData.d.ts +126 -0
- package/dist/strapi/serialization/PageData.js +335 -0
- package/dist/strapi/serialization/PageSnapshotData.d.ts +20 -0
- package/dist/strapi/serialization/PageSnapshotData.js +69 -0
- package/dist/strapi/serialization/RoleData.d.ts +5 -0
- package/dist/strapi/serialization/RoleData.js +2 -0
- package/dist/strapi/serialization/SiteConfigData.d.ts +11 -0
- package/dist/strapi/serialization/SiteConfigData.js +23 -0
- package/dist/strapi/serialization/StrapiAssetData.d.ts +17 -0
- package/dist/strapi/serialization/StrapiAssetData.js +39 -0
- package/dist/strapi/serialization/UserData.d.ts +18 -0
- package/dist/strapi/serialization/UserData.js +42 -0
- package/dist/strapi/serialization/VersionData.d.ts +26 -0
- package/dist/strapi/serialization/VersionData.js +88 -0
- package/dist/strapi/serialization/index.d.ts +10 -0
- package/dist/strapi/serialization/index.js +26 -0
- package/dist/strapi/test.d.ts +563 -0
- package/dist/strapi/test.js +1131 -0
- package/package.json +42 -0
|
@@ -0,0 +1,882 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.StrapiPageClient = void 0;
|
|
15
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
16
|
+
const errors_1 = require("../errors");
|
|
17
|
+
const serialization_1 = require("./serialization");
|
|
18
|
+
const Strapi_1 = require("./Strapi");
|
|
19
|
+
// client extension
|
|
20
|
+
class StrapiPageClient {
|
|
21
|
+
constructor(provider) {
|
|
22
|
+
this.provider = provider;
|
|
23
|
+
}
|
|
24
|
+
async getOverview({ brand, region, version }) {
|
|
25
|
+
const { static: staticPages, dynamic } = await this.provider.customRequest({
|
|
26
|
+
command: 'query/pages',
|
|
27
|
+
params: { brand, region, preview: version === 'draft' ? 'true' : 'false' }
|
|
28
|
+
});
|
|
29
|
+
// transform static links
|
|
30
|
+
return {
|
|
31
|
+
static: staticPages.map(({ type, refs }) => ({
|
|
32
|
+
type,
|
|
33
|
+
refs: Object.entries(refs).reduce((refs, [language, ref]) => {
|
|
34
|
+
// map page
|
|
35
|
+
refs[language] = serialization_1.PageData.deserializeRef(ref);
|
|
36
|
+
// keep reducing
|
|
37
|
+
return refs;
|
|
38
|
+
}, {})
|
|
39
|
+
})),
|
|
40
|
+
dynamic
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async getSummaries(args) {
|
|
44
|
+
// fetch all published pages (as summaries)
|
|
45
|
+
const client = this.provider.client;
|
|
46
|
+
const strapiUrl = client.baseURL;
|
|
47
|
+
const collection = client.collection('pages');
|
|
48
|
+
const resultProps = funnel_core_1.Schema.Page.Data.AsLink.props;
|
|
49
|
+
const entries = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(resultProps), sort: args.version === 'published'
|
|
50
|
+
? ['type', 'publishedOn:desc', 'updatedAt:desc']
|
|
51
|
+
: ['type', 'updatedAt:desc'] }, getPageQueryParams(args)));
|
|
52
|
+
// transform to dtos
|
|
53
|
+
return entries.items.map(item => serialization_1.PageData.deserialize(item, strapiUrl, resultProps));
|
|
54
|
+
}
|
|
55
|
+
async getPreviews(_a) {
|
|
56
|
+
var { pagination } = _a, args = __rest(_a, ["pagination"]);
|
|
57
|
+
// fetch all pages that match (as link data)
|
|
58
|
+
const client = this.provider.client;
|
|
59
|
+
const strapiUrl = client.baseURL;
|
|
60
|
+
const collection = client.collection('pages');
|
|
61
|
+
const resultProps = funnel_core_1.Schema.Page.Data.AsPreview.props;
|
|
62
|
+
const { filters, status } = getPageQueryParams(args);
|
|
63
|
+
const _b = await Strapi_1.Strapi.paginate({
|
|
64
|
+
collection,
|
|
65
|
+
pagination,
|
|
66
|
+
fields: serialization_1.PageData.getStrapiFilter(resultProps),
|
|
67
|
+
filters: {
|
|
68
|
+
$and: [
|
|
69
|
+
Object.assign(Object.assign({}, filters), { preview: { $not: { $eq: '{}' } } }),
|
|
70
|
+
{ preview: { $notNull: true } }
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
populate: serialization_1.PageData.Populate.preview,
|
|
74
|
+
sort: args.version === 'published'
|
|
75
|
+
? ['publishedOn:desc', 'updatedAt:desc']
|
|
76
|
+
: ['updatedAt:desc'],
|
|
77
|
+
status
|
|
78
|
+
}), { items } = _b, paginated = __rest(_b, ["items"]);
|
|
79
|
+
// transform and return items
|
|
80
|
+
return Object.assign({ items: items.map(item => serialization_1.PageData.deserialize(item, strapiUrl, resultProps)) }, paginated);
|
|
81
|
+
}
|
|
82
|
+
async search(_a) {
|
|
83
|
+
var { pagination } = _a, args = __rest(_a, ["pagination"]);
|
|
84
|
+
// fetch all pages that match (as link data)
|
|
85
|
+
const client = this.provider.client;
|
|
86
|
+
const strapiUrl = client.baseURL;
|
|
87
|
+
const collection = client.collection('pages');
|
|
88
|
+
const resultProps = funnel_core_1.Schema.Page.Data.AsLink.props;
|
|
89
|
+
const _b = await Strapi_1.Strapi.paginate(Object.assign({ collection,
|
|
90
|
+
pagination, fields: serialization_1.PageData.getStrapiFilter(resultProps), sort: args.version === 'published'
|
|
91
|
+
? ['publishedOn:desc', 'updatedAt:desc']
|
|
92
|
+
: ['updatedAt:desc'] }, getPageQueryParams(args))), { items } = _b, paginated = __rest(_b, ["items"]);
|
|
93
|
+
// transform and return items
|
|
94
|
+
return Object.assign({ items: items.map(item => serialization_1.PageData.deserialize(item, strapiUrl, resultProps)) }, paginated);
|
|
95
|
+
}
|
|
96
|
+
async query(_a) {
|
|
97
|
+
var { pagination } = _a, args = __rest(_a, ["pagination"]);
|
|
98
|
+
// setup
|
|
99
|
+
const client = this.provider.client;
|
|
100
|
+
const strapiUrl = client.baseURL;
|
|
101
|
+
const collection = client.collection('pages');
|
|
102
|
+
const resultProps = funnel_core_1.Schema.Page.Data.AsPreview.props;
|
|
103
|
+
// fetch ranking of pages
|
|
104
|
+
const { type, version, brand, region, language, sort, excludeIds = [] } = args;
|
|
105
|
+
const rankedPageIds = await this.provider.customRequest({
|
|
106
|
+
method: 'GET',
|
|
107
|
+
command: 'query/rank-pages',
|
|
108
|
+
params: {
|
|
109
|
+
preview: version === 'draft',
|
|
110
|
+
type: funnel_core_1.ArrayUtils.coerce(type),
|
|
111
|
+
brand, region, language, sort
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// filter out excluded ids
|
|
115
|
+
const filteredRankedPageIds = rankedPageIds.filter(id => !excludeIds.includes(id));
|
|
116
|
+
// get subset of ids based on pagination
|
|
117
|
+
const start = pagination === 'all' ? 0 : pagination.page - 1;
|
|
118
|
+
const end = pagination === 'all' ? rankedPageIds.length : pagination.page * pagination.pageSize;
|
|
119
|
+
const scopedRankedPageIds = filteredRankedPageIds.slice(start, end);
|
|
120
|
+
// fetch page previews by ids
|
|
121
|
+
const { data: unorderedPages } = await collection.find(Object.assign({ fields: serialization_1.PageData.getStrapiFilter(resultProps), populate: serialization_1.PageData.Populate.preview }, getPageQueryParams(Object.assign(Object.assign({}, args), { ids: scopedRankedPageIds }))));
|
|
122
|
+
// apply sorting to fetched page previews
|
|
123
|
+
const rankedPages = scopedRankedPageIds.map(id => {
|
|
124
|
+
const pageIndex = unorderedPages.findIndex(page => page.documentId === id);
|
|
125
|
+
const [page] = unorderedPages.splice(pageIndex, 1);
|
|
126
|
+
return page;
|
|
127
|
+
});
|
|
128
|
+
// deserialize pages and return
|
|
129
|
+
return {
|
|
130
|
+
items: rankedPages.map(page => serialization_1.PageData.deserialize(page, strapiUrl, resultProps)),
|
|
131
|
+
page: pagination === 'all' ? 1 : pagination.page,
|
|
132
|
+
pageCount: pagination === 'all' ? 1 : Math.ceil(filteredRankedPageIds.length / pagination.pageSize),
|
|
133
|
+
totalItemCount: filteredRankedPageIds.length
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async find(_a) {
|
|
137
|
+
var { pagination } = _a, args = __rest(_a, ["pagination"]);
|
|
138
|
+
// fetch all pages that match (as link data)
|
|
139
|
+
const client = this.provider.client;
|
|
140
|
+
const strapiUrl = client.baseURL;
|
|
141
|
+
const collection = client.collection('pages');
|
|
142
|
+
const resultProps = funnel_core_1.Schema.Page.Data.Props.all;
|
|
143
|
+
const _b = await Strapi_1.Strapi.paginate(Object.assign({ collection,
|
|
144
|
+
pagination, fields: serialization_1.PageData.getStrapiFilter(resultProps), sort: args.version === 'published'
|
|
145
|
+
? ['publishedOn:desc', 'updatedAt:desc']
|
|
146
|
+
: ['updatedAt:desc'], populate: serialization_1.PageData.Populate.full }, getPageQueryParams(args))), { items } = _b, paginated = __rest(_b, ["items"]);
|
|
147
|
+
// transform to DTOs
|
|
148
|
+
return Object.assign({ items: items.map(item => serialization_1.PageData.deserialize(item, strapiUrl, resultProps)) }, paginated);
|
|
149
|
+
}
|
|
150
|
+
async getGroup({ brand, groupId, type, slug, region, language, version }) {
|
|
151
|
+
// create base result
|
|
152
|
+
const result = {
|
|
153
|
+
group: { groupId: groupId !== null && groupId !== void 0 ? groupId : funnel_core_1.Schema.Page.GroupId.empty, brand, type, slug, region, instances: [] }
|
|
154
|
+
};
|
|
155
|
+
// fetch baseline page (fail if it doesn't exist)
|
|
156
|
+
const client = this.provider.client;
|
|
157
|
+
const collection = client.collection('pages');
|
|
158
|
+
const { items: baselineItems = [] } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.Props.id) }, getPageQueryParams({ version, brand, groupId, type, slug, region })));
|
|
159
|
+
const [baselinePage] = baselineItems;
|
|
160
|
+
if (!baselinePage) {
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
// FIXME: fail if multiple group ids come back in the result
|
|
164
|
+
// fetch all pages (as summaries) using the groupId to target
|
|
165
|
+
const { items = [] } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.AsGroup.Instance.props) }, getPageQueryParams({ version, brand, groupId: baselinePage.groupId })));
|
|
166
|
+
// add items if any
|
|
167
|
+
const { group } = result;
|
|
168
|
+
for (const item of items) {
|
|
169
|
+
// connect groupId + preset (should all be the same, so it's ok to pave over)
|
|
170
|
+
group.groupId = item.groupId;
|
|
171
|
+
// add instance
|
|
172
|
+
const instance = serialization_1.PageData.deserialize(item, client.baseURL, funnel_core_1.Schema.Page.Data.AsGroup.Instance.props);
|
|
173
|
+
group.instances.push(instance);
|
|
174
|
+
// set page if language matches
|
|
175
|
+
if (instance.language === language) {
|
|
176
|
+
result.page = await this.get({ id: instance.id, version });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// return result
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
async get(args) {
|
|
183
|
+
// get page by id
|
|
184
|
+
const client = this.provider.client;
|
|
185
|
+
const strapiUrl = client.baseURL;
|
|
186
|
+
const collection = client.collection('pages');
|
|
187
|
+
const resultProps = funnel_core_1.Schema.Page.Data.Props.all;
|
|
188
|
+
let data;
|
|
189
|
+
if ('id' in args) {
|
|
190
|
+
// find entry by document id
|
|
191
|
+
const { data: rawData } = await collection.findOne(args.id, {
|
|
192
|
+
fields: serialization_1.PageData.getStrapiFilter(resultProps),
|
|
193
|
+
status: args.version,
|
|
194
|
+
populate: serialization_1.PageData.Populate.full
|
|
195
|
+
});
|
|
196
|
+
// skip if there's no entry
|
|
197
|
+
if (!rawData) {
|
|
198
|
+
console.debug(`[StrapiPageClient/getPage] no "${args.version}" entry found for id ${args.id}`);
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
// or capture it
|
|
202
|
+
data = rawData;
|
|
203
|
+
}
|
|
204
|
+
// or by querying type (including region, and language)
|
|
205
|
+
else {
|
|
206
|
+
// lookup entry from collection (might be a miss)
|
|
207
|
+
const { data: rawData } = await collection.find(Object.assign({ fields: serialization_1.PageData.getStrapiFilter(resultProps), sort: ['updatedAt:desc'], populate: serialization_1.PageData.Populate.full }, getPageQueryParams(args)));
|
|
208
|
+
// skip if there's no entry
|
|
209
|
+
if (rawData.length === 0) {
|
|
210
|
+
console.warn(`[StrapiPageClient/getStaticPage] no "${args.version}" entry found for type ${args.type} in region ${args.region}/${args.language}`);
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
// or capture entry
|
|
214
|
+
data = rawData[0];
|
|
215
|
+
}
|
|
216
|
+
// convert and return
|
|
217
|
+
return serialization_1.PageData.deserialize(data, strapiUrl, resultProps);
|
|
218
|
+
}
|
|
219
|
+
async create(args) {
|
|
220
|
+
// resolve current user (or throw)
|
|
221
|
+
const { client, users } = this.provider;
|
|
222
|
+
const strapiUrl = client.baseURL;
|
|
223
|
+
const user = await users.me();
|
|
224
|
+
if (!user) {
|
|
225
|
+
throw new funnel_core_1.NotAuthenticatedError();
|
|
226
|
+
}
|
|
227
|
+
// create a new language of an existing page
|
|
228
|
+
if (funnel_core_1.Schema.Page.Data.AsNewLanguage.filter(args)) {
|
|
229
|
+
// fetch all pages in group (summaries only)
|
|
230
|
+
const existingPages = await this.getSummaries({
|
|
231
|
+
version: 'draft',
|
|
232
|
+
brand: args.brand,
|
|
233
|
+
groupId: args.groupId
|
|
234
|
+
});
|
|
235
|
+
// throw if there are no pages
|
|
236
|
+
if (existingPages.length === 0) {
|
|
237
|
+
throw new funnel_core_1.ArgumentError(`Page group "${args.groupId}" no longer exists in "${args.brand}"`);
|
|
238
|
+
}
|
|
239
|
+
// return existing page if it's there
|
|
240
|
+
let existingPage = existingPages.find(existing => existing.language === args.language);
|
|
241
|
+
if (existingPage) {
|
|
242
|
+
return this.getGroup(Object.assign(Object.assign({}, existingPage), { version: 'draft' }));
|
|
243
|
+
}
|
|
244
|
+
// bind data + update url
|
|
245
|
+
existingPage = existingPages[0];
|
|
246
|
+
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign({ type: existingPage.type, slug: existingPage.slug, url: existingPage.url, region: existingPage.region, name: existingPage.name, tags: existingPage.tags }, args));
|
|
247
|
+
draft.sync();
|
|
248
|
+
// resolve change set (rebind)
|
|
249
|
+
const { provider } = this;
|
|
250
|
+
const changeSet = await provider.changeSets.resolve();
|
|
251
|
+
// create page
|
|
252
|
+
try {
|
|
253
|
+
// connect page to changeset
|
|
254
|
+
draft.data.changeSetId = changeSet.id;
|
|
255
|
+
// create data model based on existing page
|
|
256
|
+
const { data } = await client.collection('pages')
|
|
257
|
+
.create(serialization_1.PageData.serialize(draft.data), {
|
|
258
|
+
status: 'draft',
|
|
259
|
+
populate: serialization_1.PageData.Populate.full
|
|
260
|
+
});
|
|
261
|
+
// transform the deserialized entry
|
|
262
|
+
const page = serialization_1.PageData.deserialize(data, strapiUrl, funnel_core_1.Schema.Page.Data.Props.all);
|
|
263
|
+
// add page to changeset
|
|
264
|
+
await provider.changeSets.update({
|
|
265
|
+
id: changeSet.id,
|
|
266
|
+
changes: [
|
|
267
|
+
...changeSet.changes,
|
|
268
|
+
{
|
|
269
|
+
__type: 'page',
|
|
270
|
+
type: 'create',
|
|
271
|
+
schema: page.type,
|
|
272
|
+
id: page.id,
|
|
273
|
+
name: page.name,
|
|
274
|
+
region: page.region,
|
|
275
|
+
language: page.language,
|
|
276
|
+
slug: page.slug,
|
|
277
|
+
errors: page.errors,
|
|
278
|
+
attribution: [
|
|
279
|
+
{ userId: user.id, updatedOn: Date.now() }
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
]
|
|
283
|
+
});
|
|
284
|
+
// return new page
|
|
285
|
+
return {
|
|
286
|
+
group: {
|
|
287
|
+
groupId: page.groupId,
|
|
288
|
+
brand: page.brand,
|
|
289
|
+
type: page.type,
|
|
290
|
+
region: page.region,
|
|
291
|
+
slug: page.slug,
|
|
292
|
+
instances: [
|
|
293
|
+
...existingPages.map(({ id, url, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn }) => ({ id, url, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn })),
|
|
294
|
+
{
|
|
295
|
+
id: page.id,
|
|
296
|
+
url: page.url,
|
|
297
|
+
language: page.language,
|
|
298
|
+
name: page.name,
|
|
299
|
+
slug: page.slug,
|
|
300
|
+
tags: page.tags,
|
|
301
|
+
state: page.state,
|
|
302
|
+
errors: page.errors,
|
|
303
|
+
createdOn: page.createdOn,
|
|
304
|
+
updatedOn: page.updatedOn,
|
|
305
|
+
publishedOn: page.publishedOn
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
page
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// remove
|
|
313
|
+
catch (e) {
|
|
314
|
+
// discard if it had no changes
|
|
315
|
+
if (changeSet.changes.length === 0) {
|
|
316
|
+
await provider.changeSets.delete(changeSet.id);
|
|
317
|
+
}
|
|
318
|
+
// throw error
|
|
319
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// or create a net new page
|
|
323
|
+
else {
|
|
324
|
+
// get page's template
|
|
325
|
+
const site = funnel_core_1.Schema.Site.current();
|
|
326
|
+
const schema = site.regions[args.region][args.type];
|
|
327
|
+
// check slug if dynamic page
|
|
328
|
+
if (schema.variant === 'dynamic') {
|
|
329
|
+
// make sure there is a slug for a dynamic page
|
|
330
|
+
if (args.slug === undefined) {
|
|
331
|
+
throw new funnel_core_1.ArgumentError(`A "${args.type}" Page must provide a slug when created`);
|
|
332
|
+
}
|
|
333
|
+
// validate slug
|
|
334
|
+
const validateSlugResult = await this.validateSlug(Object.assign(Object.assign({}, args), { slug: args.slug }));
|
|
335
|
+
if (validateSlugResult.status !== 'available') {
|
|
336
|
+
throw new errors_1.SlugValidationError({ slug: args.slug, reason: validateSlugResult });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// fetch all pages matching brand/type/region
|
|
340
|
+
const { group: existingGroup, page: existingPage } = await this.getGroup({
|
|
341
|
+
version: 'draft',
|
|
342
|
+
brand: args.brand,
|
|
343
|
+
type: args.type,
|
|
344
|
+
region: args.region,
|
|
345
|
+
slug: args.slug,
|
|
346
|
+
language: args.language
|
|
347
|
+
});
|
|
348
|
+
// return existing page if it's there
|
|
349
|
+
if (existingPage) {
|
|
350
|
+
return { group: existingGroup, page: existingPage };
|
|
351
|
+
}
|
|
352
|
+
// bind data + update url
|
|
353
|
+
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign(Object.assign({}, args), { groupId: existingGroup.groupId === funnel_core_1.Schema.Page.GroupId.empty
|
|
354
|
+
? funnel_core_1.Value.uuid()
|
|
355
|
+
: existingGroup.groupId, url: '' }));
|
|
356
|
+
draft.sync();
|
|
357
|
+
// resolve change set (rebind)
|
|
358
|
+
const { provider } = this;
|
|
359
|
+
const changeSet = await provider.changeSets.resolve();
|
|
360
|
+
// create page
|
|
361
|
+
try {
|
|
362
|
+
// connect page to changeset
|
|
363
|
+
draft.data.changeSetId = changeSet.id;
|
|
364
|
+
// create page
|
|
365
|
+
const { data } = await client.collection('pages')
|
|
366
|
+
.create(serialization_1.PageData.serialize(draft.data), {
|
|
367
|
+
status: 'draft',
|
|
368
|
+
populate: serialization_1.PageData.Populate.full
|
|
369
|
+
});
|
|
370
|
+
// transform the deserialized entry
|
|
371
|
+
const page = serialization_1.PageData.deserialize(data, strapiUrl, funnel_core_1.Schema.Page.Data.Props.all);
|
|
372
|
+
// add page to changeset
|
|
373
|
+
await provider.changeSets.update({
|
|
374
|
+
id: changeSet.id,
|
|
375
|
+
changes: [
|
|
376
|
+
...changeSet.changes,
|
|
377
|
+
{
|
|
378
|
+
__type: 'page',
|
|
379
|
+
type: 'create',
|
|
380
|
+
schema: page.type,
|
|
381
|
+
id: page.id,
|
|
382
|
+
name: page.name,
|
|
383
|
+
region: page.region,
|
|
384
|
+
language: page.language,
|
|
385
|
+
slug: page.slug,
|
|
386
|
+
errors: page.errors,
|
|
387
|
+
attribution: [
|
|
388
|
+
{ userId: user.id, updatedOn: Date.now() }
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
});
|
|
393
|
+
// return page
|
|
394
|
+
return {
|
|
395
|
+
group: {
|
|
396
|
+
groupId: page.groupId,
|
|
397
|
+
brand: page.brand,
|
|
398
|
+
type: page.type,
|
|
399
|
+
region: args.region,
|
|
400
|
+
slug: page.slug,
|
|
401
|
+
instances: [
|
|
402
|
+
...existingGroup.instances,
|
|
403
|
+
{
|
|
404
|
+
id: page.id,
|
|
405
|
+
url: page.url,
|
|
406
|
+
language: page.language,
|
|
407
|
+
name: page.name,
|
|
408
|
+
slug: page.slug,
|
|
409
|
+
tags: page.tags,
|
|
410
|
+
state: page.state,
|
|
411
|
+
errors: page.errors,
|
|
412
|
+
createdOn: page.createdOn,
|
|
413
|
+
updatedOn: page.updatedOn,
|
|
414
|
+
publishedOn: page.publishedOn
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
},
|
|
418
|
+
page
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
// remove
|
|
422
|
+
catch (e) {
|
|
423
|
+
// discard page if it had no changes
|
|
424
|
+
if (changeSet.changes.length === 0) {
|
|
425
|
+
await provider.changeSets.delete(changeSet.id);
|
|
426
|
+
}
|
|
427
|
+
// throw error
|
|
428
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async duplicate({ source: pageId, targetPage, targetLanguage, targetSlug }) {
|
|
433
|
+
var _a;
|
|
434
|
+
// resolve current user (or throw)
|
|
435
|
+
const { client, users } = this.provider;
|
|
436
|
+
const strapiUrl = client.baseURL;
|
|
437
|
+
const user = await users.me();
|
|
438
|
+
if (!user) {
|
|
439
|
+
throw new funnel_core_1.NotAuthenticatedError();
|
|
440
|
+
}
|
|
441
|
+
// get page by id
|
|
442
|
+
const pageCollection = client.collection('pages');
|
|
443
|
+
const { data: sourceData } = await pageCollection.findOne(pageId, {
|
|
444
|
+
fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.Props.all),
|
|
445
|
+
status: 'draft',
|
|
446
|
+
populate: serialization_1.PageData.Populate.full
|
|
447
|
+
});
|
|
448
|
+
const sourcePage = sourceData;
|
|
449
|
+
// throw if there's no page
|
|
450
|
+
if (!sourcePage) {
|
|
451
|
+
throw new funnel_core_1.NotFoundError(`Unable to resolve page with id "${pageId}"`);
|
|
452
|
+
}
|
|
453
|
+
// TODO: check schema to see if language is possible
|
|
454
|
+
// make sure target language doesn't already exist if we are targeting the current group
|
|
455
|
+
if (targetPage === 'current') {
|
|
456
|
+
const { data: pagesWithTargetLanguage } = await pageCollection.find(Object.assign({ fields: ['documentId'] }, getPageQueryParams({ version: 'draft', groupId: sourcePage.groupId, language: targetLanguage })));
|
|
457
|
+
if (pagesWithTargetLanguage.length > 0) {
|
|
458
|
+
throw new funnel_core_1.InvalidOperationError(`There is already a page in group "${sourcePage.groupId}" with ${targetLanguage} language`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
// make sure a static page isn't getting duplicated and that the slug is good
|
|
462
|
+
else if (targetPage === 'new') {
|
|
463
|
+
// get source page's schema
|
|
464
|
+
const site = funnel_core_1.Schema.Site.current();
|
|
465
|
+
const schema = site.regions[sourcePage.region][sourcePage.type];
|
|
466
|
+
// cannot duplicate a static page
|
|
467
|
+
if (schema.variant === 'static') {
|
|
468
|
+
throw new funnel_core_1.InvalidOperationError(`cannot duplicate a static page "${sourcePage.name}"`);
|
|
469
|
+
}
|
|
470
|
+
// slug must be provided
|
|
471
|
+
if (targetSlug === undefined) {
|
|
472
|
+
throw new funnel_core_1.ArgumentError('slug must be provided when duplicating a page');
|
|
473
|
+
}
|
|
474
|
+
// validate slug
|
|
475
|
+
const validateSlugResult = await this.validateSlug({
|
|
476
|
+
brand: sourcePage.brand,
|
|
477
|
+
type: sourcePage.type,
|
|
478
|
+
region: sourcePage.region,
|
|
479
|
+
slug: targetSlug
|
|
480
|
+
});
|
|
481
|
+
if (validateSlugResult.status !== 'available') {
|
|
482
|
+
throw new errors_1.SlugValidationError({
|
|
483
|
+
slug: targetSlug,
|
|
484
|
+
reason: validateSlugResult
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// get refs from source page
|
|
489
|
+
const { assetRefs, pageRefs, collectionRefs } = sourcePage;
|
|
490
|
+
// target refs and body
|
|
491
|
+
let targetPageRefIds;
|
|
492
|
+
let targetCollectionRefIds;
|
|
493
|
+
let targetBody;
|
|
494
|
+
// if we are targeting a different language then we need to "translate" the references
|
|
495
|
+
if (targetLanguage !== sourcePage.lang) {
|
|
496
|
+
// fetch target language refs
|
|
497
|
+
const { pageIdMappings, collectionIdMappings } = await Strapi_1.Strapi.translateReferences({
|
|
498
|
+
client,
|
|
499
|
+
targetLanguage,
|
|
500
|
+
pageRefs,
|
|
501
|
+
collectionRefs
|
|
502
|
+
});
|
|
503
|
+
console.debug('[StrapiPageClient] duplicate: calculated mappings (source to target)', { pageIdMappings, collectionIdMappings });
|
|
504
|
+
// set target values
|
|
505
|
+
targetPageRefIds = pageIdMappings.map(mapping => mapping.targetId);
|
|
506
|
+
targetCollectionRefIds = collectionIdMappings.map(mapping => mapping.targetId);
|
|
507
|
+
targetBody = {
|
|
508
|
+
discover: Strapi_1.Strapi.updateRefs({ value: sourcePage.discover, pageIdMappings, collectionIdMappings }),
|
|
509
|
+
preview: Strapi_1.Strapi.updateRefs({ value: sourcePage.preview, pageIdMappings, collectionIdMappings }),
|
|
510
|
+
content: Strapi_1.Strapi.updateRefs({ value: sourcePage.content, pageIdMappings, collectionIdMappings }),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
// otherwise we can keep everything the same as the source page
|
|
514
|
+
else {
|
|
515
|
+
// set target values
|
|
516
|
+
targetPageRefIds = pageRefs.map(ref => ref.documentId);
|
|
517
|
+
targetCollectionRefIds = collectionRefs.map(ref => ref.documentId);
|
|
518
|
+
targetBody = {
|
|
519
|
+
discover: sourcePage.discover,
|
|
520
|
+
preview: sourcePage.preview,
|
|
521
|
+
content: sourcePage.content
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
// resolve change set (rebind)
|
|
525
|
+
const { provider } = this;
|
|
526
|
+
const changeSet = await provider.changeSets.resolve();
|
|
527
|
+
// create duplicate page
|
|
528
|
+
try {
|
|
529
|
+
// create target page using content of source
|
|
530
|
+
const { data: dupData } = await pageCollection.create(Object.assign({ groupId: targetPage === 'current'
|
|
531
|
+
? sourcePage.groupId
|
|
532
|
+
: funnel_core_1.Value.uuid(), type: sourcePage.type, brand: sourcePage.brand, region: sourcePage.region, lang: targetLanguage, slug: targetSlug !== null && targetSlug !== void 0 ? targetSlug : sourcePage.slug, name: sourcePage.name, tags: sourcePage.tags, url: sourcePage.url, state: 'draft', errors: sourcePage.errors, assetRefs: { set: assetRefs.map(ref => ref.documentId) }, pageRefs: { set: targetPageRefIds }, collectionRefs: { set: targetCollectionRefIds } }, targetBody), { status: 'draft', populate: serialization_1.PageData.Populate.full });
|
|
533
|
+
const dupPageData = dupData;
|
|
534
|
+
console.debug('[StrapiPageClient] duplicate: created duplicate page', { dupPageData });
|
|
535
|
+
// touch new duplicated page to update url/name
|
|
536
|
+
let dupPage = serialization_1.PageData.deserialize(dupPageData, strapiUrl, funnel_core_1.Schema.Page.Data.Props.all);
|
|
537
|
+
const dupPageModel = funnel_core_1.Schema.PageModel.from(dupPage);
|
|
538
|
+
dupPageModel.sync();
|
|
539
|
+
// connect page to changeset
|
|
540
|
+
dupPage.changeSetId = changeSet.id;
|
|
541
|
+
// update duplicate page with updated url/name
|
|
542
|
+
const update = serialization_1.PageData.serialize(dupPage);
|
|
543
|
+
const { data: updatedData } = await pageCollection.update(dupPage.id, update, { status: 'draft' });
|
|
544
|
+
dupPage = serialization_1.PageData.deserialize(updatedData, strapiUrl, funnel_core_1.Schema.Page.Data.Props.all);
|
|
545
|
+
console.debug('[StrapiPageClient] duplicate: touched duplicated page');
|
|
546
|
+
// add page to changeset
|
|
547
|
+
await provider.changeSets.update({
|
|
548
|
+
id: changeSet.id,
|
|
549
|
+
changes: [
|
|
550
|
+
...changeSet.changes,
|
|
551
|
+
{
|
|
552
|
+
__type: 'page',
|
|
553
|
+
type: 'create',
|
|
554
|
+
schema: dupPage.type,
|
|
555
|
+
id: dupPage.id,
|
|
556
|
+
name: dupPage.name,
|
|
557
|
+
region: dupPage.region,
|
|
558
|
+
language: dupPage.language,
|
|
559
|
+
slug: dupPage.slug,
|
|
560
|
+
errors: dupPage.errors,
|
|
561
|
+
attribution: [
|
|
562
|
+
{ userId: user.id, updatedOn: Date.now() }
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
});
|
|
567
|
+
// return group for duplicated page
|
|
568
|
+
return this.getGroup({
|
|
569
|
+
brand: dupPage.brand,
|
|
570
|
+
groupId: dupPage.groupId,
|
|
571
|
+
type: dupPage.type,
|
|
572
|
+
slug: (_a = dupPage.slug) !== null && _a !== void 0 ? _a : undefined,
|
|
573
|
+
region: dupPage.region,
|
|
574
|
+
language: dupPage.language,
|
|
575
|
+
version: 'draft'
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
// handle errors
|
|
579
|
+
catch (e) {
|
|
580
|
+
// discard changeset if it had no changes
|
|
581
|
+
if (changeSet.changes.length === 0) {
|
|
582
|
+
await provider.changeSets.delete(changeSet.id);
|
|
583
|
+
}
|
|
584
|
+
// throw error
|
|
585
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
async touch({ id: pageId, version: status }) {
|
|
589
|
+
// get latest version of page
|
|
590
|
+
const client = this.provider.client;
|
|
591
|
+
const strapiUrl = client.baseURL;
|
|
592
|
+
const collection = client.collection('pages');
|
|
593
|
+
const resultProps = funnel_core_1.Schema.Page.Data.Props.all;
|
|
594
|
+
const { data: currentData } = await collection.findOne(pageId, {
|
|
595
|
+
status,
|
|
596
|
+
populate: serialization_1.PageData.Populate.full
|
|
597
|
+
});
|
|
598
|
+
// TODO: switch to isometric error so we can catch it on client-side
|
|
599
|
+
// throw if page doesn't exist
|
|
600
|
+
if (!currentData) {
|
|
601
|
+
throw new funnel_core_1.NotFoundError();
|
|
602
|
+
}
|
|
603
|
+
// deserialize page (we'll be updating this version)
|
|
604
|
+
const page = serialization_1.PageData.deserialize(currentData, strapiUrl, resultProps);
|
|
605
|
+
// merge changes (the original page will have changed)
|
|
606
|
+
const model = funnel_core_1.Schema.PageModel.from(page);
|
|
607
|
+
model.sync();
|
|
608
|
+
console.debug(`[StrapiPageClient/touch] saving updated page`);
|
|
609
|
+
// save page
|
|
610
|
+
const update = serialization_1.PageData.serialize(page);
|
|
611
|
+
const { data: updatedData } = await collection.update(page.id, update, {
|
|
612
|
+
status,
|
|
613
|
+
populate: serialization_1.PageData.Populate.full
|
|
614
|
+
});
|
|
615
|
+
console.debug(`[StrapiPageClient/update] returning final page`);
|
|
616
|
+
// return page ref
|
|
617
|
+
return serialization_1.PageData.deserializeRef(updatedData);
|
|
618
|
+
}
|
|
619
|
+
async update({ id: pageId, slug: pageSlug, publication: pagePublication, errors, updates }) {
|
|
620
|
+
// resolve current user (or throw)
|
|
621
|
+
const { client, users } = this.provider;
|
|
622
|
+
const strapiUrl = client.baseURL;
|
|
623
|
+
const user = await users.me();
|
|
624
|
+
if (!user) {
|
|
625
|
+
throw new funnel_core_1.NotAuthenticatedError();
|
|
626
|
+
}
|
|
627
|
+
// get latest version of page
|
|
628
|
+
const collection = client.collection('pages');
|
|
629
|
+
const resultProps = funnel_core_1.Schema.Page.Data.Props.all;
|
|
630
|
+
const { data: currentData } = await collection.findOne(pageId, {
|
|
631
|
+
status: 'draft',
|
|
632
|
+
populate: serialization_1.PageData.Populate.full
|
|
633
|
+
});
|
|
634
|
+
// TODO: validate page is able to be updated (e.g. not archived, etc.)
|
|
635
|
+
// throw if page doesn't exist
|
|
636
|
+
if (!currentData) {
|
|
637
|
+
throw new funnel_core_1.NotFoundError();
|
|
638
|
+
}
|
|
639
|
+
// deserialize page (we'll be updating this version)
|
|
640
|
+
let page = serialization_1.PageData.deserialize(currentData, strapiUrl, resultProps);
|
|
641
|
+
// update slug
|
|
642
|
+
if (pageSlug && page.slug) {
|
|
643
|
+
console.debug(`[StrapiPageClient/update] updating page slug from "${page.slug}" to ${pageSlug}`);
|
|
644
|
+
// validate slug before updating
|
|
645
|
+
const validateSlugResult = await this.validateSlug({
|
|
646
|
+
brand: page.brand,
|
|
647
|
+
type: page.type,
|
|
648
|
+
region: page.region,
|
|
649
|
+
groupId: page.groupId,
|
|
650
|
+
slug: pageSlug
|
|
651
|
+
});
|
|
652
|
+
if (validateSlugResult.status !== 'available') {
|
|
653
|
+
throw new errors_1.SlugValidationError({ slug: pageSlug, reason: validateSlugResult });
|
|
654
|
+
}
|
|
655
|
+
page.slug = pageSlug;
|
|
656
|
+
}
|
|
657
|
+
// update publication
|
|
658
|
+
if (pagePublication !== undefined) {
|
|
659
|
+
page.publication = pagePublication !== null && pagePublication !== void 0 ? pagePublication : -1;
|
|
660
|
+
}
|
|
661
|
+
// set errors
|
|
662
|
+
page.errors = errors;
|
|
663
|
+
console.debug(`[StrapiPageClient/update] applying ${updates.length} page updates`);
|
|
664
|
+
// merge changes (the original page will have changed)
|
|
665
|
+
const model = funnel_core_1.Schema.PageModel.from(page);
|
|
666
|
+
model.update(updates);
|
|
667
|
+
console.debug(`[StrapiPageClient/update] saving updated page`);
|
|
668
|
+
// resolve change set (rebind)
|
|
669
|
+
const { provider } = this;
|
|
670
|
+
const changeSet = await provider.changeSets.resolve({ id: page.changeSetId, fallbackToGlobal: true });
|
|
671
|
+
page.changeSetId = changeSet.id;
|
|
672
|
+
// save page
|
|
673
|
+
const update = serialization_1.PageData.serialize(page);
|
|
674
|
+
console.debug(`[StrapiPageClient/update] sending update`, JSON.stringify(update, undefined, ' '));
|
|
675
|
+
const { data: updatedData } = await collection.update(page.id, Object.assign(Object.assign({}, update), { state: 'draft' }), {
|
|
676
|
+
status: 'draft',
|
|
677
|
+
populate: serialization_1.PageData.Populate.full
|
|
678
|
+
});
|
|
679
|
+
page = serialization_1.PageData.deserialize(updatedData, strapiUrl, resultProps);
|
|
680
|
+
// update changeset
|
|
681
|
+
changeSet.addPageChange(user.id, {
|
|
682
|
+
__type: 'page',
|
|
683
|
+
id: page.id,
|
|
684
|
+
name: page.name,
|
|
685
|
+
schema: page.type,
|
|
686
|
+
region: page.region,
|
|
687
|
+
language: page.language,
|
|
688
|
+
slug: page.slug,
|
|
689
|
+
type: page.publishedOn ? 'update' : 'create',
|
|
690
|
+
errors: page.errors
|
|
691
|
+
});
|
|
692
|
+
provider.changeSets.update(changeSet.toData())
|
|
693
|
+
.catch(console.error);
|
|
694
|
+
// return page
|
|
695
|
+
return page;
|
|
696
|
+
}
|
|
697
|
+
async replace({ page, version, skipSync = false }) {
|
|
698
|
+
console.debug(`[StrapiPageClient/replace] replacing page`);
|
|
699
|
+
// get latest version of page
|
|
700
|
+
const client = this.provider.client;
|
|
701
|
+
const strapiUrl = client.baseURL;
|
|
702
|
+
const collection = client.collection('pages');
|
|
703
|
+
// sync changes (the original page will have changed)
|
|
704
|
+
const model = funnel_core_1.Schema.PageModel.from(page);
|
|
705
|
+
if (!skipSync) {
|
|
706
|
+
model.sync();
|
|
707
|
+
}
|
|
708
|
+
// save page
|
|
709
|
+
const update = serialization_1.PageData.serialize(page);
|
|
710
|
+
const { data: updatedData } = await collection.update(page.id, update, {
|
|
711
|
+
status: version,
|
|
712
|
+
populate: serialization_1.PageData.Populate.full
|
|
713
|
+
});
|
|
714
|
+
console.debug(`[StrapiPageClient/replace] returning final page`);
|
|
715
|
+
// return page
|
|
716
|
+
return serialization_1.PageData.deserialize(updatedData, strapiUrl);
|
|
717
|
+
}
|
|
718
|
+
async unpublish(pageId) {
|
|
719
|
+
// get page
|
|
720
|
+
const page = await this.get({ id: pageId, version: 'draft' });
|
|
721
|
+
// throw if there's no page
|
|
722
|
+
if (!page) {
|
|
723
|
+
throw new funnel_core_1.NotFoundError('Unable to resolve page');
|
|
724
|
+
}
|
|
725
|
+
// or throw if it's already draft
|
|
726
|
+
else if (!page.publishedOn) {
|
|
727
|
+
throw new funnel_core_1.InvalidOperationError('Page is not published');
|
|
728
|
+
}
|
|
729
|
+
// unpublish the document
|
|
730
|
+
await this.provider.customRequest({
|
|
731
|
+
method: 'POST',
|
|
732
|
+
command: 'unpublish',
|
|
733
|
+
data: JSON.stringify({
|
|
734
|
+
collection: 'page',
|
|
735
|
+
documentId: page.id
|
|
736
|
+
}),
|
|
737
|
+
onError: ({ pageRefs, collectionRefs }) => {
|
|
738
|
+
// throw dependants error if we got any refs
|
|
739
|
+
if (pageRefs || collectionRefs) {
|
|
740
|
+
const client = this.provider.client;
|
|
741
|
+
const strapiUrl = client.baseURL;
|
|
742
|
+
throw new errors_1.LinkedDependantsError({
|
|
743
|
+
message: 'This collection cannot be unpublished because it would break dependencies',
|
|
744
|
+
pages: pageRefs.map(data => serialization_1.PageData.deserialize(data, strapiUrl, funnel_core_1.Schema.Page.Data.AsLink.props)),
|
|
745
|
+
collections: collectionRefs.map(data => serialization_1.CollectionData.deserialize(data, strapiUrl, funnel_core_1.Schema.Collection.Data.AsLink.props))
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
// or assume the page isn't published
|
|
749
|
+
else {
|
|
750
|
+
throw new funnel_core_1.NotFoundError();
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
// transform dto
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
async getDependants({ id: pageId, version }) {
|
|
758
|
+
// get client
|
|
759
|
+
const client = this.provider.client;
|
|
760
|
+
// pages are the only direct dependants currently
|
|
761
|
+
const strapiUrl = client.baseURL;
|
|
762
|
+
const collection = client.collection('pages');
|
|
763
|
+
const { items: pages = [] } = await Strapi_1.Strapi.paginate({
|
|
764
|
+
collection,
|
|
765
|
+
pagination: 'all',
|
|
766
|
+
filters: {
|
|
767
|
+
pageRefs: {
|
|
768
|
+
documentId: pageId
|
|
769
|
+
}
|
|
770
|
+
},
|
|
771
|
+
status: version
|
|
772
|
+
});
|
|
773
|
+
// return
|
|
774
|
+
return {
|
|
775
|
+
pages: pages.map(page => serialization_1.PageData.deserialize(page, strapiUrl, funnel_core_1.Schema.Page.Data.AsLink.props))
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async getDependencies({ id: pageId, version }) {
|
|
779
|
+
// get page by id
|
|
780
|
+
const client = this.provider.client;
|
|
781
|
+
const strapiUrl = client.baseURL;
|
|
782
|
+
const collection = client.collection('pages');
|
|
783
|
+
const { data } = await collection.findOne(pageId, {
|
|
784
|
+
status: version,
|
|
785
|
+
populate: ['pageRefs', 'collectionRefs']
|
|
786
|
+
});
|
|
787
|
+
const page = data;
|
|
788
|
+
// throw if not found
|
|
789
|
+
if (!page) {
|
|
790
|
+
throw new funnel_core_1.NotFoundError(`cannot find page with id "${pageId}"`);
|
|
791
|
+
}
|
|
792
|
+
// return
|
|
793
|
+
return {
|
|
794
|
+
pages: page.pageRefs.map(pageRef => serialization_1.PageData.deserialize(pageRef, strapiUrl, funnel_core_1.Schema.Page.Data.AsLink.props)),
|
|
795
|
+
collections: page.collectionRefs.map(collectionRef => serialization_1.CollectionData.deserialize(collectionRef, strapiUrl, funnel_core_1.Schema.Collection.Data.AsLink.props))
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
async validateSlug({ brand, type, region, slug, groupId }) {
|
|
799
|
+
// TODO: check if slug is a valid format
|
|
800
|
+
// setup collection
|
|
801
|
+
const client = this.provider.client;
|
|
802
|
+
const collection = client.collection('pages');
|
|
803
|
+
// fetch pages with the same slug with same brand, type, and region
|
|
804
|
+
const { items } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.AsLink.props) }, getPageQueryParams({ version: 'draft', brand, type, region, slug })));
|
|
805
|
+
// ignore pages in same group (if group specified)
|
|
806
|
+
const matchedPages = groupId !== undefined
|
|
807
|
+
? items.filter(item => item.groupId !== groupId)
|
|
808
|
+
: items;
|
|
809
|
+
// available if no pages matched
|
|
810
|
+
if (matchedPages.length === 0) {
|
|
811
|
+
return { status: 'available' };
|
|
812
|
+
}
|
|
813
|
+
// otherwise not available
|
|
814
|
+
else {
|
|
815
|
+
return {
|
|
816
|
+
status: 'unavailable',
|
|
817
|
+
takenBy: serialization_1.PageData.deserializeRef(matchedPages[0])
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
exports.StrapiPageClient = StrapiPageClient;
|
|
823
|
+
// helper
|
|
824
|
+
function getPageQueryParams(query) {
|
|
825
|
+
// build filters
|
|
826
|
+
const { ids = [], groupId, brand, type, slug, region, language, name, tags = [], tagsMatch = 'any', version } = query;
|
|
827
|
+
const filters = [];
|
|
828
|
+
// filter ids
|
|
829
|
+
if (ids.length > 0) {
|
|
830
|
+
filters.push({ documentId: { $in: ids } });
|
|
831
|
+
}
|
|
832
|
+
// filter group
|
|
833
|
+
if (groupId) {
|
|
834
|
+
filters.push({ groupId: { $eq: groupId } });
|
|
835
|
+
}
|
|
836
|
+
// filter brand
|
|
837
|
+
if (brand) {
|
|
838
|
+
filters.push({ brand: { $eq: brand } });
|
|
839
|
+
}
|
|
840
|
+
// filter type
|
|
841
|
+
const normalizedType = type
|
|
842
|
+
? Array.isArray(type)
|
|
843
|
+
? type
|
|
844
|
+
: [type]
|
|
845
|
+
: [];
|
|
846
|
+
if (normalizedType.length > 0) {
|
|
847
|
+
filters.push({ type: { $in: type } });
|
|
848
|
+
}
|
|
849
|
+
// filter slug
|
|
850
|
+
if (slug) {
|
|
851
|
+
filters.push({ slug: { $eq: slug } });
|
|
852
|
+
}
|
|
853
|
+
// filter region
|
|
854
|
+
if (region) {
|
|
855
|
+
filters.push({ region: { $eq: region } });
|
|
856
|
+
}
|
|
857
|
+
// filter language
|
|
858
|
+
if (language) {
|
|
859
|
+
filters.push({ lang: { $eq: language } });
|
|
860
|
+
}
|
|
861
|
+
// filter name
|
|
862
|
+
if (name) {
|
|
863
|
+
filters.push({ name: { $contains: name } });
|
|
864
|
+
}
|
|
865
|
+
// filter tags
|
|
866
|
+
if (tags.length === 1) {
|
|
867
|
+
filters.push({ tags: { $contains: `"${tags[0]}"` } });
|
|
868
|
+
}
|
|
869
|
+
else if (tags.length > 1) {
|
|
870
|
+
const operator = tagsMatch === 'any' ? '$or' : '$and';
|
|
871
|
+
filters.push({
|
|
872
|
+
[operator]: tags
|
|
873
|
+
.filter((tag) => !!tag)
|
|
874
|
+
.map((tag) => ({ tags: { $contains: `"${tag}"` } }))
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
// return query
|
|
878
|
+
return {
|
|
879
|
+
filters: filters.length > 0 ? { $and: filters } : undefined,
|
|
880
|
+
status: version
|
|
881
|
+
};
|
|
882
|
+
}
|