multi-content-type-relation 2.1.2 → 2.2.1
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/README.md +6 -0
- package/dist/_chunks/{index-DdX2rVzB.mjs → index-BGSdnZnr.mjs} +37 -12
- package/dist/_chunks/index-Bu99PZdl.js +470 -0
- package/dist/_chunks/{index-BtldAbIW.js → index-CEXSrD4g.js} +40 -15
- package/dist/_chunks/index-DEkcD0zR.mjs +470 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/Input/InputContentSuggestions.d.ts +1 -2
- package/dist/admin/src/components/Input/TableItem.d.ts +2 -3
- package/dist/admin/src/helpers/content.d.ts +1 -1
- package/dist/server/index.js +130 -61
- package/dist/server/index.mjs +130 -61
- package/dist/server/src/controllers/controller.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/index.d.ts +1 -0
- package/dist/server/src/interface.d.ts +2 -0
- package/package.json +2 -1
- package/dist/_chunks/index-CyBD50Lc.js +0 -3567
- package/dist/_chunks/index-DGcImy9s.mjs +0 -3565
package/dist/server/index.js
CHANGED
|
@@ -40,28 +40,35 @@ const middleware = async (ctx, next) => {
|
|
|
40
40
|
await next();
|
|
41
41
|
if (!ctx.body) return;
|
|
42
42
|
if (!ctx.body.data) return;
|
|
43
|
+
let hasSyncedRelations = false;
|
|
43
44
|
if ([
|
|
44
45
|
"collection-types.create",
|
|
45
46
|
"collection-types.update",
|
|
46
47
|
"single-types.createOrUpdate"
|
|
47
|
-
].includes(ctx?.state?.route?.handler)) {
|
|
48
|
+
].includes(ctx?.state?.route?.handler) && !hasSyncedRelations) {
|
|
48
49
|
const [, _, __, rest] = ctx?.request.url.split("/");
|
|
49
50
|
const contentType = rest.split("?")[0];
|
|
50
51
|
const isDraftAndPublish = strapi.contentTypes[contentType].options?.draftAndPublish;
|
|
51
52
|
if (isDraftAndPublish) {
|
|
52
|
-
log(`[MIDDLEWARE] ${contentType}is draft and publish`);
|
|
53
|
+
log(`[MIDDLEWARE] ${contentType} is draft and publish`);
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
const documentId = ctx.body.data.documentId;
|
|
56
|
-
|
|
57
|
+
const locale = ctx.body.data.locale;
|
|
58
|
+
log(`[MIDDLEWARE] ${ctx?.state?.route?.handler} Syncing MCTR relation for ${contentType}, documentId: ${documentId}`);
|
|
59
|
+
syncMctrRelation(documentId, contentType, locale);
|
|
60
|
+
hasSyncedRelations = true;
|
|
57
61
|
}
|
|
58
62
|
if (["collection-types.publish", "single-types.publish"].includes(
|
|
59
63
|
ctx?.state?.route?.handler
|
|
60
|
-
)) {
|
|
64
|
+
) && !hasSyncedRelations) {
|
|
61
65
|
const [, _, __, rest] = ctx?.request.url.split("/");
|
|
62
66
|
const contentType = rest.split("?")[0];
|
|
63
67
|
const documentId = ctx.body.data.documentId;
|
|
64
|
-
|
|
68
|
+
const locale = ctx.body.data.locale;
|
|
69
|
+
syncMctrRelation(documentId, contentType, locale);
|
|
70
|
+
log(`[MIDDLEWARE] ${ctx?.state?.route?.handler} Syncing MCTR relation for ${contentType}, documentId: ${documentId}`);
|
|
71
|
+
hasSyncedRelations = true;
|
|
65
72
|
}
|
|
66
73
|
if (!ctx?.request?.url?.startsWith("/api")) return;
|
|
67
74
|
if (ctx.request.method !== "GET") return;
|
|
@@ -70,7 +77,7 @@ const middleware = async (ctx, next) => {
|
|
|
70
77
|
const handler = ctx.state.route.handler;
|
|
71
78
|
const contentTypes2 = Object.keys(strapi.contentTypes);
|
|
72
79
|
log(`[MIDDLEWARE] URL: ${ctx.request.url} (${ctx.request.method})`);
|
|
73
|
-
log(`[MIDDLEWARE] Strapi Route: ${
|
|
80
|
+
log(`[MIDDLEWARE] Strapi Route: ${ctx.state.route}`);
|
|
74
81
|
if (typeof handler !== "string") return;
|
|
75
82
|
const validHandler = contentTypes2.filter((contentType) => contentType.startsWith("api::")).some(
|
|
76
83
|
(contentType) => handler.includes(`${contentType}.findOne`) || handler.includes(`${contentType}.findMany`) || handler.includes(`${contentType}.find`)
|
|
@@ -107,9 +114,9 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
107
114
|
const field = JSON.parse(value);
|
|
108
115
|
if (!Array.isArray(field)) continue;
|
|
109
116
|
for (const item of field) {
|
|
110
|
-
if (
|
|
117
|
+
if (!item.uid && typeof item.uid !== "string" || !item.documentId)
|
|
111
118
|
continue;
|
|
112
|
-
const compositeID = `${item.uid}####${item.documentId}`;
|
|
119
|
+
const compositeID = `${item.uid}####${item.documentId}${item.locale ? `####${item.locale}` : ""}`;
|
|
113
120
|
eligibleProperties.add(key);
|
|
114
121
|
if (contentsToFetch.has(compositeID)) continue;
|
|
115
122
|
else contentsToFetch.add(compositeID);
|
|
@@ -124,8 +131,12 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
124
131
|
);
|
|
125
132
|
const promises = [];
|
|
126
133
|
for (const item of Array.from(contentsToFetch)) {
|
|
127
|
-
const [uid, documentId] = item.split("####");
|
|
128
|
-
const
|
|
134
|
+
const [uid, documentId, locale] = item.split("####");
|
|
135
|
+
const options = { documentId, populate: "*", status: "published" };
|
|
136
|
+
if (locale) {
|
|
137
|
+
options.locale = locale;
|
|
138
|
+
}
|
|
139
|
+
const promise = strapi.documents(uid).findOne(options).then(async (response) => {
|
|
129
140
|
if (!response) return { uid, response };
|
|
130
141
|
if (configuration.recursive.enabled && currentDepth < configuration.recursive.maxDepth) {
|
|
131
142
|
const hydratedResponse = await hydrateMRCT(
|
|
@@ -165,9 +176,16 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
165
176
|
const hydratedArray = [];
|
|
166
177
|
const unhydratedField = JSON.parse(flattenedProperties[key]);
|
|
167
178
|
for (const item of unhydratedField) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
let matchingContent = null;
|
|
180
|
+
if (item.locale) {
|
|
181
|
+
matchingContent = filteredLinkedEntries.find(
|
|
182
|
+
(linkedEntry) => item.uid === linkedEntry.uid && item.documentId === linkedEntry.response.documentId && item.locale === linkedEntry.response.locale
|
|
183
|
+
);
|
|
184
|
+
} else {
|
|
185
|
+
matchingContent = filteredLinkedEntries.find(
|
|
186
|
+
(linkedEntry) => item.uid === linkedEntry.uid && item.documentId === linkedEntry.response.documentId
|
|
187
|
+
);
|
|
188
|
+
}
|
|
171
189
|
if (matchingContent) {
|
|
172
190
|
hydratedArray.push({ uid: matchingContent.uid, ...matchingContent.response });
|
|
173
191
|
}
|
|
@@ -180,26 +198,13 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
180
198
|
...newContent
|
|
181
199
|
};
|
|
182
200
|
};
|
|
183
|
-
const syncMctrRelation = async (documentId, uid) => {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
189
|
-
if (mctrDocuments.length !== 0) {
|
|
190
|
-
log(`[SYNC] Delete MCTR relations for ${documentId}`);
|
|
191
|
-
await Promise.all(
|
|
192
|
-
mctrDocuments.map(async ({ documentId: documentId2 }) => {
|
|
193
|
-
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").delete({
|
|
194
|
-
documentId: documentId2
|
|
195
|
-
});
|
|
196
|
-
})
|
|
197
|
-
);
|
|
201
|
+
const syncMctrRelation = async (documentId, uid, locale) => {
|
|
202
|
+
const configuration = getPluginConfiguration();
|
|
203
|
+
if (configuration.disableRevertRelations) {
|
|
204
|
+
log(`[SYNC] Revert relations are disabled, discarding sync`);
|
|
205
|
+
return;
|
|
198
206
|
}
|
|
199
|
-
log(`[SYNC]
|
|
200
|
-
const document = await strapi.documents(uid).findOne({
|
|
201
|
-
documentId
|
|
202
|
-
});
|
|
207
|
+
log(`[SYNC] Syncing MCTR relation for ${documentId}, uid: ${uid}, locale: ${locale}`);
|
|
203
208
|
const contentTypeKey = Object.keys(strapi.contentTypes).find(
|
|
204
209
|
(ct) => strapi.contentTypes[ct].uid === uid
|
|
205
210
|
);
|
|
@@ -208,30 +213,67 @@ const syncMctrRelation = async (documentId, uid) => {
|
|
|
208
213
|
const mctrFields = Object.keys(contentType.attributes).filter(
|
|
209
214
|
(field) => contentType.attributes[field].customField === "plugin::multi-content-type-relation.multi-content-type-relation"
|
|
210
215
|
);
|
|
211
|
-
if (mctrFields.length === 0)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
216
|
+
if (mctrFields.length === 0) {
|
|
217
|
+
log(`[SYNC] No MCTR fields found for ${documentId}, discarding sync`);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
let mctrRelationDocumentId = documentId;
|
|
221
|
+
if (locale) {
|
|
222
|
+
mctrRelationDocumentId = `${documentId}####${locale}`;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const mctrDocuments = await strapi.documents("plugin::multi-content-type-relation.mctr-relation").findMany({
|
|
226
|
+
filters: {
|
|
227
|
+
sourceDocId: mctrRelationDocumentId
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
log(`[SYNC] MCTR relations for ${mctrRelationDocumentId}: ${JSON.stringify(mctrDocuments, null, 2)}`);
|
|
231
|
+
if (mctrDocuments.length !== 0) {
|
|
232
|
+
log(`[SYNC] Delete MCTR relations for ${mctrRelationDocumentId}`);
|
|
233
|
+
await Promise.all(
|
|
234
|
+
mctrDocuments.map(async ({ documentId: documentId2 }) => {
|
|
235
|
+
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").delete({
|
|
236
|
+
documentId: documentId2
|
|
237
|
+
});
|
|
238
|
+
})
|
|
239
|
+
);
|
|
223
240
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
sourceDocId: documentId,
|
|
231
|
-
target: targetJSON
|
|
241
|
+
log(`[SYNC] Find document ${documentId}`);
|
|
242
|
+
const options = {
|
|
243
|
+
documentId
|
|
244
|
+
};
|
|
245
|
+
if (locale) {
|
|
246
|
+
options.locale = locale;
|
|
232
247
|
}
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
const document = await strapi.documents(uid).findOne(options);
|
|
249
|
+
log(`[SYNC] MCTR fields for ${documentId}: ${JSON.stringify(mctrFields, null, 2)}`);
|
|
250
|
+
const targetJSON = [];
|
|
251
|
+
mctrFields.forEach(async (field) => {
|
|
252
|
+
const fieldValue = document[field];
|
|
253
|
+
if (!fieldValue) return;
|
|
254
|
+
try {
|
|
255
|
+
const mctrField = JSON.parse(fieldValue);
|
|
256
|
+
mctrField.forEach((item) => {
|
|
257
|
+
targetJSON.push(`${field}##${item.uid}##${item.documentId}${locale ? `####${locale}` : ""}`);
|
|
258
|
+
});
|
|
259
|
+
} catch (e) {
|
|
260
|
+
log(`[SYNC] Error parsing field ${field} ${fieldValue}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
log(`[SYNC] Target JSON for ${documentId}: ${JSON.stringify(targetJSON, null, 2)}`);
|
|
264
|
+
if (targetJSON.length === 0) return;
|
|
265
|
+
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").create({
|
|
266
|
+
data: {
|
|
267
|
+
sourceUID: uid,
|
|
268
|
+
sourceDocId: mctrRelationDocumentId,
|
|
269
|
+
target: targetJSON
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
log(`[SYNC] MCTR relation created for ${documentId}`);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
log(`[SYNC] Error creating MCTR relation for ${documentId}: ${error}`);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
235
277
|
};
|
|
236
278
|
const middlewares = {
|
|
237
279
|
middleware
|
|
@@ -279,7 +321,7 @@ const schema = {
|
|
|
279
321
|
},
|
|
280
322
|
pluginOptions: {
|
|
281
323
|
"content-manager": {
|
|
282
|
-
visible:
|
|
324
|
+
visible: false
|
|
283
325
|
},
|
|
284
326
|
"content-type-builder": {
|
|
285
327
|
visible: false
|
|
@@ -361,11 +403,15 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
361
403
|
const body = ctx.request.body;
|
|
362
404
|
const entries = body.entries;
|
|
363
405
|
const promises = entries.map((entry) => {
|
|
364
|
-
|
|
406
|
+
const findOneOptions = {
|
|
365
407
|
documentId: entry.documentId,
|
|
366
408
|
populate: "*",
|
|
367
409
|
status: "published"
|
|
368
|
-
}
|
|
410
|
+
};
|
|
411
|
+
if (entry.locale) {
|
|
412
|
+
findOneOptions.locale = entry.locale;
|
|
413
|
+
}
|
|
414
|
+
return strapi2.documents(entry.uid).findOne(findOneOptions).then((result) => {
|
|
369
415
|
return {
|
|
370
416
|
uid: entry.uid,
|
|
371
417
|
result
|
|
@@ -396,6 +442,7 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
396
442
|
let documentId = body.documentId;
|
|
397
443
|
const uid = body.uid;
|
|
398
444
|
const isSingleType = body.isSingleType;
|
|
445
|
+
const locale = body.locale;
|
|
399
446
|
if (isSingleType) {
|
|
400
447
|
const document = await strapi2.documents(uid).findFirst({
|
|
401
448
|
populate: "*",
|
|
@@ -407,13 +454,19 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
407
454
|
const mctrRelations = await strapi2.documents("plugin::multi-content-type-relation.mctr-relation").findMany({
|
|
408
455
|
filters: {
|
|
409
456
|
target: {
|
|
410
|
-
$containsi: `${uid}##${documentId}`
|
|
457
|
+
$containsi: `${uid}##${documentId}${locale ? `####${locale}` : ""}`
|
|
411
458
|
}
|
|
412
459
|
}
|
|
413
460
|
});
|
|
414
461
|
const relations = await Promise.all(
|
|
415
462
|
mctrRelations.map(async (relation) => {
|
|
416
|
-
|
|
463
|
+
let sourceDocumentId = relation.sourceDocId;
|
|
464
|
+
let locale2 = null;
|
|
465
|
+
if (sourceDocumentId.includes("####")) {
|
|
466
|
+
const [documentId2, sourceLocale] = sourceDocumentId.split("####");
|
|
467
|
+
locale2 = sourceLocale;
|
|
468
|
+
sourceDocumentId = documentId2;
|
|
469
|
+
}
|
|
417
470
|
const sourceUid = relation.sourceUID;
|
|
418
471
|
const target = relation.target.find(
|
|
419
472
|
(target2) => target2.includes(`${uid}##${documentId}`)
|
|
@@ -424,11 +477,15 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
424
477
|
);
|
|
425
478
|
if (!contentTypeName) return null;
|
|
426
479
|
const contentType = strapi2.contentTypes[contentTypeName];
|
|
427
|
-
const
|
|
480
|
+
const findOneOptions = {
|
|
428
481
|
documentId: sourceDocumentId,
|
|
429
482
|
populate: "*",
|
|
430
483
|
status: "published"
|
|
431
|
-
}
|
|
484
|
+
};
|
|
485
|
+
if (locale2) {
|
|
486
|
+
findOneOptions.locale = locale2;
|
|
487
|
+
}
|
|
488
|
+
const document = await strapi2.documents(sourceUid).findOne(findOneOptions);
|
|
432
489
|
const searchableField = strapi2.plugin("multi-content-type-relation").service("service").getFirstStringFieldInContentType(contentType);
|
|
433
490
|
return {
|
|
434
491
|
title: document[searchableField],
|
|
@@ -441,6 +498,10 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
441
498
|
})
|
|
442
499
|
);
|
|
443
500
|
return relations.filter(Boolean);
|
|
501
|
+
},
|
|
502
|
+
getConfiguration: async function() {
|
|
503
|
+
const configuration = getPluginConfiguration();
|
|
504
|
+
return configuration;
|
|
444
505
|
}
|
|
445
506
|
});
|
|
446
507
|
const controllers = {
|
|
@@ -480,6 +541,14 @@ const routes = [
|
|
|
480
541
|
config: {
|
|
481
542
|
policies: []
|
|
482
543
|
}
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
method: "GET",
|
|
547
|
+
path: "/get-configuration",
|
|
548
|
+
handler: "controller.getConfiguration",
|
|
549
|
+
config: {
|
|
550
|
+
policies: []
|
|
551
|
+
}
|
|
483
552
|
}
|
|
484
553
|
];
|
|
485
554
|
const service = ({ strapi: strapi2 }) => ({
|
package/dist/server/index.mjs
CHANGED
|
@@ -39,28 +39,35 @@ const middleware = async (ctx, next) => {
|
|
|
39
39
|
await next();
|
|
40
40
|
if (!ctx.body) return;
|
|
41
41
|
if (!ctx.body.data) return;
|
|
42
|
+
let hasSyncedRelations = false;
|
|
42
43
|
if ([
|
|
43
44
|
"collection-types.create",
|
|
44
45
|
"collection-types.update",
|
|
45
46
|
"single-types.createOrUpdate"
|
|
46
|
-
].includes(ctx?.state?.route?.handler)) {
|
|
47
|
+
].includes(ctx?.state?.route?.handler) && !hasSyncedRelations) {
|
|
47
48
|
const [, _, __, rest] = ctx?.request.url.split("/");
|
|
48
49
|
const contentType = rest.split("?")[0];
|
|
49
50
|
const isDraftAndPublish = strapi.contentTypes[contentType].options?.draftAndPublish;
|
|
50
51
|
if (isDraftAndPublish) {
|
|
51
|
-
log(`[MIDDLEWARE] ${contentType}is draft and publish`);
|
|
52
|
+
log(`[MIDDLEWARE] ${contentType} is draft and publish`);
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
55
|
const documentId = ctx.body.data.documentId;
|
|
55
|
-
|
|
56
|
+
const locale = ctx.body.data.locale;
|
|
57
|
+
log(`[MIDDLEWARE] ${ctx?.state?.route?.handler} Syncing MCTR relation for ${contentType}, documentId: ${documentId}`);
|
|
58
|
+
syncMctrRelation(documentId, contentType, locale);
|
|
59
|
+
hasSyncedRelations = true;
|
|
56
60
|
}
|
|
57
61
|
if (["collection-types.publish", "single-types.publish"].includes(
|
|
58
62
|
ctx?.state?.route?.handler
|
|
59
|
-
)) {
|
|
63
|
+
) && !hasSyncedRelations) {
|
|
60
64
|
const [, _, __, rest] = ctx?.request.url.split("/");
|
|
61
65
|
const contentType = rest.split("?")[0];
|
|
62
66
|
const documentId = ctx.body.data.documentId;
|
|
63
|
-
|
|
67
|
+
const locale = ctx.body.data.locale;
|
|
68
|
+
syncMctrRelation(documentId, contentType, locale);
|
|
69
|
+
log(`[MIDDLEWARE] ${ctx?.state?.route?.handler} Syncing MCTR relation for ${contentType}, documentId: ${documentId}`);
|
|
70
|
+
hasSyncedRelations = true;
|
|
64
71
|
}
|
|
65
72
|
if (!ctx?.request?.url?.startsWith("/api")) return;
|
|
66
73
|
if (ctx.request.method !== "GET") return;
|
|
@@ -69,7 +76,7 @@ const middleware = async (ctx, next) => {
|
|
|
69
76
|
const handler = ctx.state.route.handler;
|
|
70
77
|
const contentTypes2 = Object.keys(strapi.contentTypes);
|
|
71
78
|
log(`[MIDDLEWARE] URL: ${ctx.request.url} (${ctx.request.method})`);
|
|
72
|
-
log(`[MIDDLEWARE] Strapi Route: ${
|
|
79
|
+
log(`[MIDDLEWARE] Strapi Route: ${ctx.state.route}`);
|
|
73
80
|
if (typeof handler !== "string") return;
|
|
74
81
|
const validHandler = contentTypes2.filter((contentType) => contentType.startsWith("api::")).some(
|
|
75
82
|
(contentType) => handler.includes(`${contentType}.findOne`) || handler.includes(`${contentType}.findMany`) || handler.includes(`${contentType}.find`)
|
|
@@ -106,9 +113,9 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
106
113
|
const field = JSON.parse(value);
|
|
107
114
|
if (!Array.isArray(field)) continue;
|
|
108
115
|
for (const item of field) {
|
|
109
|
-
if (
|
|
116
|
+
if (!item.uid && typeof item.uid !== "string" || !item.documentId)
|
|
110
117
|
continue;
|
|
111
|
-
const compositeID = `${item.uid}####${item.documentId}`;
|
|
118
|
+
const compositeID = `${item.uid}####${item.documentId}${item.locale ? `####${item.locale}` : ""}`;
|
|
112
119
|
eligibleProperties.add(key);
|
|
113
120
|
if (contentsToFetch.has(compositeID)) continue;
|
|
114
121
|
else contentsToFetch.add(compositeID);
|
|
@@ -123,8 +130,12 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
123
130
|
);
|
|
124
131
|
const promises = [];
|
|
125
132
|
for (const item of Array.from(contentsToFetch)) {
|
|
126
|
-
const [uid, documentId] = item.split("####");
|
|
127
|
-
const
|
|
133
|
+
const [uid, documentId, locale] = item.split("####");
|
|
134
|
+
const options = { documentId, populate: "*", status: "published" };
|
|
135
|
+
if (locale) {
|
|
136
|
+
options.locale = locale;
|
|
137
|
+
}
|
|
138
|
+
const promise = strapi.documents(uid).findOne(options).then(async (response) => {
|
|
128
139
|
if (!response) return { uid, response };
|
|
129
140
|
if (configuration.recursive.enabled && currentDepth < configuration.recursive.maxDepth) {
|
|
130
141
|
const hydratedResponse = await hydrateMRCT(
|
|
@@ -164,9 +175,16 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
164
175
|
const hydratedArray = [];
|
|
165
176
|
const unhydratedField = JSON.parse(flattenedProperties[key]);
|
|
166
177
|
for (const item of unhydratedField) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
178
|
+
let matchingContent = null;
|
|
179
|
+
if (item.locale) {
|
|
180
|
+
matchingContent = filteredLinkedEntries.find(
|
|
181
|
+
(linkedEntry) => item.uid === linkedEntry.uid && item.documentId === linkedEntry.response.documentId && item.locale === linkedEntry.response.locale
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
matchingContent = filteredLinkedEntries.find(
|
|
185
|
+
(linkedEntry) => item.uid === linkedEntry.uid && item.documentId === linkedEntry.response.documentId
|
|
186
|
+
);
|
|
187
|
+
}
|
|
170
188
|
if (matchingContent) {
|
|
171
189
|
hydratedArray.push({ uid: matchingContent.uid, ...matchingContent.response });
|
|
172
190
|
}
|
|
@@ -179,26 +197,13 @@ const hydrateMRCT = async (content, currentDepth, context) => {
|
|
|
179
197
|
...newContent
|
|
180
198
|
};
|
|
181
199
|
};
|
|
182
|
-
const syncMctrRelation = async (documentId, uid) => {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
});
|
|
188
|
-
if (mctrDocuments.length !== 0) {
|
|
189
|
-
log(`[SYNC] Delete MCTR relations for ${documentId}`);
|
|
190
|
-
await Promise.all(
|
|
191
|
-
mctrDocuments.map(async ({ documentId: documentId2 }) => {
|
|
192
|
-
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").delete({
|
|
193
|
-
documentId: documentId2
|
|
194
|
-
});
|
|
195
|
-
})
|
|
196
|
-
);
|
|
200
|
+
const syncMctrRelation = async (documentId, uid, locale) => {
|
|
201
|
+
const configuration = getPluginConfiguration();
|
|
202
|
+
if (configuration.disableRevertRelations) {
|
|
203
|
+
log(`[SYNC] Revert relations are disabled, discarding sync`);
|
|
204
|
+
return;
|
|
197
205
|
}
|
|
198
|
-
log(`[SYNC]
|
|
199
|
-
const document = await strapi.documents(uid).findOne({
|
|
200
|
-
documentId
|
|
201
|
-
});
|
|
206
|
+
log(`[SYNC] Syncing MCTR relation for ${documentId}, uid: ${uid}, locale: ${locale}`);
|
|
202
207
|
const contentTypeKey = Object.keys(strapi.contentTypes).find(
|
|
203
208
|
(ct) => strapi.contentTypes[ct].uid === uid
|
|
204
209
|
);
|
|
@@ -207,30 +212,67 @@ const syncMctrRelation = async (documentId, uid) => {
|
|
|
207
212
|
const mctrFields = Object.keys(contentType.attributes).filter(
|
|
208
213
|
(field) => contentType.attributes[field].customField === "plugin::multi-content-type-relation.multi-content-type-relation"
|
|
209
214
|
);
|
|
210
|
-
if (mctrFields.length === 0)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
215
|
+
if (mctrFields.length === 0) {
|
|
216
|
+
log(`[SYNC] No MCTR fields found for ${documentId}, discarding sync`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
let mctrRelationDocumentId = documentId;
|
|
220
|
+
if (locale) {
|
|
221
|
+
mctrRelationDocumentId = `${documentId}####${locale}`;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const mctrDocuments = await strapi.documents("plugin::multi-content-type-relation.mctr-relation").findMany({
|
|
225
|
+
filters: {
|
|
226
|
+
sourceDocId: mctrRelationDocumentId
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
log(`[SYNC] MCTR relations for ${mctrRelationDocumentId}: ${JSON.stringify(mctrDocuments, null, 2)}`);
|
|
230
|
+
if (mctrDocuments.length !== 0) {
|
|
231
|
+
log(`[SYNC] Delete MCTR relations for ${mctrRelationDocumentId}`);
|
|
232
|
+
await Promise.all(
|
|
233
|
+
mctrDocuments.map(async ({ documentId: documentId2 }) => {
|
|
234
|
+
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").delete({
|
|
235
|
+
documentId: documentId2
|
|
236
|
+
});
|
|
237
|
+
})
|
|
238
|
+
);
|
|
222
239
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
sourceDocId: documentId,
|
|
230
|
-
target: targetJSON
|
|
240
|
+
log(`[SYNC] Find document ${documentId}`);
|
|
241
|
+
const options = {
|
|
242
|
+
documentId
|
|
243
|
+
};
|
|
244
|
+
if (locale) {
|
|
245
|
+
options.locale = locale;
|
|
231
246
|
}
|
|
232
|
-
|
|
233
|
-
|
|
247
|
+
const document = await strapi.documents(uid).findOne(options);
|
|
248
|
+
log(`[SYNC] MCTR fields for ${documentId}: ${JSON.stringify(mctrFields, null, 2)}`);
|
|
249
|
+
const targetJSON = [];
|
|
250
|
+
mctrFields.forEach(async (field) => {
|
|
251
|
+
const fieldValue = document[field];
|
|
252
|
+
if (!fieldValue) return;
|
|
253
|
+
try {
|
|
254
|
+
const mctrField = JSON.parse(fieldValue);
|
|
255
|
+
mctrField.forEach((item) => {
|
|
256
|
+
targetJSON.push(`${field}##${item.uid}##${item.documentId}${locale ? `####${locale}` : ""}`);
|
|
257
|
+
});
|
|
258
|
+
} catch (e) {
|
|
259
|
+
log(`[SYNC] Error parsing field ${field} ${fieldValue}`);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
log(`[SYNC] Target JSON for ${documentId}: ${JSON.stringify(targetJSON, null, 2)}`);
|
|
263
|
+
if (targetJSON.length === 0) return;
|
|
264
|
+
await strapi.documents("plugin::multi-content-type-relation.mctr-relation").create({
|
|
265
|
+
data: {
|
|
266
|
+
sourceUID: uid,
|
|
267
|
+
sourceDocId: mctrRelationDocumentId,
|
|
268
|
+
target: targetJSON
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
log(`[SYNC] MCTR relation created for ${documentId}`);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
log(`[SYNC] Error creating MCTR relation for ${documentId}: ${error}`);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
234
276
|
};
|
|
235
277
|
const middlewares = {
|
|
236
278
|
middleware
|
|
@@ -278,7 +320,7 @@ const schema = {
|
|
|
278
320
|
},
|
|
279
321
|
pluginOptions: {
|
|
280
322
|
"content-manager": {
|
|
281
|
-
visible:
|
|
323
|
+
visible: false
|
|
282
324
|
},
|
|
283
325
|
"content-type-builder": {
|
|
284
326
|
visible: false
|
|
@@ -360,11 +402,15 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
360
402
|
const body = ctx.request.body;
|
|
361
403
|
const entries = body.entries;
|
|
362
404
|
const promises = entries.map((entry) => {
|
|
363
|
-
|
|
405
|
+
const findOneOptions = {
|
|
364
406
|
documentId: entry.documentId,
|
|
365
407
|
populate: "*",
|
|
366
408
|
status: "published"
|
|
367
|
-
}
|
|
409
|
+
};
|
|
410
|
+
if (entry.locale) {
|
|
411
|
+
findOneOptions.locale = entry.locale;
|
|
412
|
+
}
|
|
413
|
+
return strapi2.documents(entry.uid).findOne(findOneOptions).then((result) => {
|
|
368
414
|
return {
|
|
369
415
|
uid: entry.uid,
|
|
370
416
|
result
|
|
@@ -395,6 +441,7 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
395
441
|
let documentId = body.documentId;
|
|
396
442
|
const uid = body.uid;
|
|
397
443
|
const isSingleType = body.isSingleType;
|
|
444
|
+
const locale = body.locale;
|
|
398
445
|
if (isSingleType) {
|
|
399
446
|
const document = await strapi2.documents(uid).findFirst({
|
|
400
447
|
populate: "*",
|
|
@@ -406,13 +453,19 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
406
453
|
const mctrRelations = await strapi2.documents("plugin::multi-content-type-relation.mctr-relation").findMany({
|
|
407
454
|
filters: {
|
|
408
455
|
target: {
|
|
409
|
-
$containsi: `${uid}##${documentId}`
|
|
456
|
+
$containsi: `${uid}##${documentId}${locale ? `####${locale}` : ""}`
|
|
410
457
|
}
|
|
411
458
|
}
|
|
412
459
|
});
|
|
413
460
|
const relations = await Promise.all(
|
|
414
461
|
mctrRelations.map(async (relation) => {
|
|
415
|
-
|
|
462
|
+
let sourceDocumentId = relation.sourceDocId;
|
|
463
|
+
let locale2 = null;
|
|
464
|
+
if (sourceDocumentId.includes("####")) {
|
|
465
|
+
const [documentId2, sourceLocale] = sourceDocumentId.split("####");
|
|
466
|
+
locale2 = sourceLocale;
|
|
467
|
+
sourceDocumentId = documentId2;
|
|
468
|
+
}
|
|
416
469
|
const sourceUid = relation.sourceUID;
|
|
417
470
|
const target = relation.target.find(
|
|
418
471
|
(target2) => target2.includes(`${uid}##${documentId}`)
|
|
@@ -423,11 +476,15 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
423
476
|
);
|
|
424
477
|
if (!contentTypeName) return null;
|
|
425
478
|
const contentType = strapi2.contentTypes[contentTypeName];
|
|
426
|
-
const
|
|
479
|
+
const findOneOptions = {
|
|
427
480
|
documentId: sourceDocumentId,
|
|
428
481
|
populate: "*",
|
|
429
482
|
status: "published"
|
|
430
|
-
}
|
|
483
|
+
};
|
|
484
|
+
if (locale2) {
|
|
485
|
+
findOneOptions.locale = locale2;
|
|
486
|
+
}
|
|
487
|
+
const document = await strapi2.documents(sourceUid).findOne(findOneOptions);
|
|
431
488
|
const searchableField = strapi2.plugin("multi-content-type-relation").service("service").getFirstStringFieldInContentType(contentType);
|
|
432
489
|
return {
|
|
433
490
|
title: document[searchableField],
|
|
@@ -440,6 +497,10 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
440
497
|
})
|
|
441
498
|
);
|
|
442
499
|
return relations.filter(Boolean);
|
|
500
|
+
},
|
|
501
|
+
getConfiguration: async function() {
|
|
502
|
+
const configuration = getPluginConfiguration();
|
|
503
|
+
return configuration;
|
|
443
504
|
}
|
|
444
505
|
});
|
|
445
506
|
const controllers = {
|
|
@@ -479,6 +540,14 @@ const routes = [
|
|
|
479
540
|
config: {
|
|
480
541
|
policies: []
|
|
481
542
|
}
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
method: "GET",
|
|
546
|
+
path: "/get-configuration",
|
|
547
|
+
handler: "controller.getConfiguration",
|
|
548
|
+
config: {
|
|
549
|
+
policies: []
|
|
550
|
+
}
|
|
482
551
|
}
|
|
483
552
|
];
|
|
484
553
|
const service = ({ strapi: strapi2 }) => ({
|
|
@@ -21,8 +21,10 @@ export type SelectedEntry = {
|
|
|
21
21
|
export type FormattedStrapiEntry = {
|
|
22
22
|
uid: string;
|
|
23
23
|
documentId: string;
|
|
24
|
+
locale?: string;
|
|
24
25
|
};
|
|
25
26
|
export type Configuration = {
|
|
27
|
+
disableRevertRelations: boolean;
|
|
26
28
|
recursive: {
|
|
27
29
|
enabled: boolean;
|
|
28
30
|
maxDepth: number;
|