@strapi/content-manager 0.0.0-experimental.62ce06180fe9a772eaeb3d43d238b26644f39f7c → 0.0.0-experimental.646ad2aaf2b8f9970409242af8d77b0512d19bd1
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/LICENSE +18 -3
- package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js → ComponentConfigurationPage-D1SEOQBu.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js.map → ComponentConfigurationPage-D1SEOQBu.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs → ComponentConfigurationPage-oqdZo6l8.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs.map → ComponentConfigurationPage-oqdZo6l8.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js → EditConfigurationPage-BP94U6vG.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js.map → EditConfigurationPage-BP94U6vG.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs → EditConfigurationPage-DVLmpXPs.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs.map → EditConfigurationPage-DVLmpXPs.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DxyAOItK.js → EditViewPage-BfAywbBE.js} +30 -9
- package/dist/_chunks/EditViewPage-BfAywbBE.js.map +1 -0
- package/dist/_chunks/{EditViewPage-ClIueJnM.mjs → EditViewPage-Cvjs7D6M.mjs} +30 -9
- package/dist/_chunks/EditViewPage-Cvjs7D6M.mjs.map +1 -0
- package/dist/_chunks/{Field-BZBYmvaf.mjs → Field-CJrfStLX.mjs} +517 -153
- package/dist/_chunks/Field-CJrfStLX.mjs.map +1 -0
- package/dist/_chunks/{Field-C0Y_SR9e.js → Field-DC7FM64m.js} +519 -155
- package/dist/_chunks/Field-DC7FM64m.js.map +1 -0
- package/dist/_chunks/{Form-DwvGnISS.js → Form-Ahp2hi7E.js} +36 -17
- package/dist/_chunks/Form-Ahp2hi7E.js.map +1 -0
- package/dist/_chunks/{Form-jwRSC2kV.mjs → Form-BTgUlCEm.mjs} +36 -17
- package/dist/_chunks/Form-BTgUlCEm.mjs.map +1 -0
- package/dist/_chunks/{History-Cda0Yjzz.js → History-DZ9T1ZL6.js} +63 -25
- package/dist/_chunks/History-DZ9T1ZL6.js.map +1 -0
- package/dist/_chunks/{History-BgzAIj0G.mjs → History-Drr6mxnK.mjs} +64 -26
- package/dist/_chunks/History-Drr6mxnK.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-C29EF97r.js → ListConfigurationPage-B8bYMcVE.js} +20 -8
- package/dist/_chunks/ListConfigurationPage-B8bYMcVE.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-GH55qfoT.mjs → ListConfigurationPage-C6calJtW.mjs} +20 -8
- package/dist/_chunks/ListConfigurationPage-C6calJtW.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CnRt0UT7.js → ListViewPage-BfiTNTUl.js} +61 -43
- package/dist/_chunks/ListViewPage-BfiTNTUl.js.map +1 -0
- package/dist/_chunks/{ListViewPage-QU03PFj1.mjs → ListViewPage-CQb0CL40.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CQb0CL40.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs → NoContentTypePage-C-BK38Ai.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs.map → NoContentTypePage-C-BK38Ai.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js → NoContentTypePage-wJwVyqoZ.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js.map → NoContentTypePage-wJwVyqoZ.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs → NoPermissionsPage-BBdxJ-4m.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs.map → NoPermissionsPage-BBdxJ-4m.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js → NoPermissionsPage-DKaXyuK9.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js.map → NoPermissionsPage-DKaXyuK9.js.map} +1 -1
- package/dist/_chunks/{Relations-BjpPPCKp.js → Relations-D7NskJzt.js} +69 -36
- package/dist/_chunks/Relations-D7NskJzt.js.map +1 -0
- package/dist/_chunks/{Relations-KMf5qEN0.mjs → Relations-DApDLUXv.mjs} +70 -37
- package/dist/_chunks/Relations-DApDLUXv.mjs.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-Bm0D0IWz.js} +17 -15
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-DKV44jRb.mjs} +17 -15
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-6kKXK7y8.mjs → index-Bz1SCyIj.mjs} +1005 -686
- package/dist/_chunks/index-Bz1SCyIj.mjs.map +1 -0
- package/dist/_chunks/{index-D9ZwczCV.js → index-D3u7haqj.js} +998 -678
- package/dist/_chunks/index-D3u7haqj.js.map +1 -0
- package/dist/_chunks/{layout-BJfBoBiF.js → layout-C_0aK53L.js} +25 -12
- package/dist/_chunks/layout-C_0aK53L.js.map +1 -0
- package/dist/_chunks/{layout-B1Z-9koY.mjs → layout-PNlIceEV.mjs} +27 -14
- package/dist/_chunks/layout-PNlIceEV.mjs.map +1 -0
- package/dist/_chunks/{relations-CgZg7Pyx.mjs → relations-BAIQsBLx.mjs} +3 -7
- package/dist/_chunks/relations-BAIQsBLx.mjs.map +1 -0
- package/dist/_chunks/{relations-CMvjzyU3.js → relations-ClRXiXcM.js} +3 -7
- package/dist/_chunks/relations-ClRXiXcM.js.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +3 -2
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +32 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -17
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +245 -132
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +246 -133
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -8
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -4
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/_chunks/EditViewPage-ClIueJnM.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DxyAOItK.js.map +0 -1
- package/dist/_chunks/Field-BZBYmvaf.mjs.map +0 -1
- package/dist/_chunks/Field-C0Y_SR9e.js.map +0 -1
- package/dist/_chunks/Form-DwvGnISS.js.map +0 -1
- package/dist/_chunks/Form-jwRSC2kV.mjs.map +0 -1
- package/dist/_chunks/History-BgzAIj0G.mjs.map +0 -1
- package/dist/_chunks/History-Cda0Yjzz.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-C29EF97r.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-GH55qfoT.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-CnRt0UT7.js.map +0 -1
- package/dist/_chunks/ListViewPage-QU03PFj1.mjs.map +0 -1
- package/dist/_chunks/Relations-BjpPPCKp.js.map +0 -1
- package/dist/_chunks/Relations-KMf5qEN0.mjs.map +0 -1
- package/dist/_chunks/index-6kKXK7y8.mjs.map +0 -1
- package/dist/_chunks/index-D9ZwczCV.js.map +0 -1
- package/dist/_chunks/layout-B1Z-9koY.mjs.map +0 -1
- package/dist/_chunks/layout-BJfBoBiF.js.map +0 -1
- package/dist/_chunks/relations-CMvjzyU3.js.map +0 -1
- package/dist/_chunks/relations-CgZg7Pyx.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
package/dist/server/index.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import strapiUtils, { validateYupSchema, errors, async, contentTypes as contentTypes$1, yup as yup$1, validateYupSchemaSync, policy, traverse, setCreatorFields, isOperatorOfType, relations as relations$1, traverseEntity, pagination } from "@strapi/utils";
|
2
|
-
import { pick, omit, difference, intersection, pipe, propOr, isEqual, isEmpty, set, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat,
|
2
|
+
import { pick, omit, difference, castArray, intersection, pipe, propOr, isEqual, isEmpty, set, isNil as isNil$1, has, prop, assoc, mapValues, flow, uniq, uniqBy, concat, getOr, propEq, merge, groupBy } from "lodash/fp";
|
3
3
|
import "@strapi/types";
|
4
4
|
import * as yup from "yup";
|
5
5
|
import { scheduleJob } from "node-schedule";
|
@@ -173,7 +173,9 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
173
173
|
return strapi2.db.query("plugin::upload.file").findOne({ where: { id: versionRelationData.id } });
|
174
174
|
};
|
175
175
|
const localesService = strapi2.plugin("i18n")?.service("locales");
|
176
|
+
const i18nContentTypeService = strapi2.plugin("i18n")?.service("content-types");
|
176
177
|
const getDefaultLocale = async () => localesService ? localesService.getDefaultLocale() : null;
|
178
|
+
const isLocalizedContentType = (model) => i18nContentTypeService ? i18nContentTypeService.isLocalizedContentType(model) : false;
|
177
179
|
const getLocaleDictionary = async () => {
|
178
180
|
if (!localesService)
|
179
181
|
return {};
|
@@ -200,20 +202,25 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
200
202
|
const meta = await documentMetadataService.getMetadata(contentTypeUid, document);
|
201
203
|
return documentMetadataService.getStatus(document, meta.availableStatus);
|
202
204
|
};
|
203
|
-
const getDeepPopulate2 = (uid2) => {
|
205
|
+
const getDeepPopulate2 = (uid2, useDatabaseSyntax = false) => {
|
204
206
|
const model = strapi2.getModel(uid2);
|
205
207
|
const attributes = Object.entries(model.attributes);
|
208
|
+
const fieldSelector = useDatabaseSyntax ? "select" : "fields";
|
206
209
|
return attributes.reduce((acc, [attributeName, attribute]) => {
|
207
210
|
switch (attribute.type) {
|
208
211
|
case "relation": {
|
212
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
213
|
+
if (isMorphRelation) {
|
214
|
+
break;
|
215
|
+
}
|
209
216
|
const isVisible2 = contentTypes$1.isVisibleAttribute(model, attributeName);
|
210
217
|
if (isVisible2) {
|
211
|
-
acc[attributeName] = {
|
218
|
+
acc[attributeName] = { [fieldSelector]: ["documentId", "locale", "publishedAt"] };
|
212
219
|
}
|
213
220
|
break;
|
214
221
|
}
|
215
222
|
case "media": {
|
216
|
-
acc[attributeName] = {
|
223
|
+
acc[attributeName] = { [fieldSelector]: ["id"] };
|
217
224
|
break;
|
218
225
|
}
|
219
226
|
case "component": {
|
@@ -286,6 +293,7 @@ const createServiceUtils = ({ strapi: strapi2 }) => {
|
|
286
293
|
getRelationRestoreValue,
|
287
294
|
getMediaRestoreValue,
|
288
295
|
getDefaultLocale,
|
296
|
+
isLocalizedContentType,
|
289
297
|
getLocaleDictionary,
|
290
298
|
getRetentionDays,
|
291
299
|
getVersionStatus,
|
@@ -308,7 +316,13 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
308
316
|
});
|
309
317
|
},
|
310
318
|
async findVersionsPage(params) {
|
311
|
-
const
|
319
|
+
const model = strapi2.getModel(params.query.contentType);
|
320
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
321
|
+
const defaultLocale = await serviceUtils.getDefaultLocale();
|
322
|
+
let locale = null;
|
323
|
+
if (isLocalizedContentType) {
|
324
|
+
locale = params.query.locale || defaultLocale;
|
325
|
+
}
|
312
326
|
const [{ results, pagination: pagination2 }, localeDictionary] = await Promise.all([
|
313
327
|
query.findPage({
|
314
328
|
...params.query,
|
@@ -353,7 +367,12 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
353
367
|
if (userToPopulate == null) {
|
354
368
|
return null;
|
355
369
|
}
|
356
|
-
return strapi2.query("admin::user").findOne({
|
370
|
+
return strapi2.query("admin::user").findOne({
|
371
|
+
where: {
|
372
|
+
...userToPopulate.id ? { id: userToPopulate.id } : {},
|
373
|
+
...userToPopulate.documentId ? { documentId: userToPopulate.documentId } : {}
|
374
|
+
}
|
375
|
+
});
|
357
376
|
})
|
358
377
|
);
|
359
378
|
return {
|
@@ -464,6 +483,42 @@ const createHistoryService = ({ strapi: strapi2 }) => {
|
|
464
483
|
}
|
465
484
|
};
|
466
485
|
};
|
486
|
+
const shouldCreateHistoryVersion = (context) => {
|
487
|
+
if (!strapi.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
488
|
+
return false;
|
489
|
+
}
|
490
|
+
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
491
|
+
return false;
|
492
|
+
}
|
493
|
+
if (context.action === "update" && strapi.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
494
|
+
return false;
|
495
|
+
}
|
496
|
+
if (!context.contentType.uid.startsWith("api::")) {
|
497
|
+
return false;
|
498
|
+
}
|
499
|
+
return true;
|
500
|
+
};
|
501
|
+
const getSchemas = (uid2) => {
|
502
|
+
const attributesSchema = strapi.getModel(uid2).attributes;
|
503
|
+
const componentsSchemas = Object.keys(attributesSchema).reduce(
|
504
|
+
(currentComponentSchemas, key) => {
|
505
|
+
const fieldSchema = attributesSchema[key];
|
506
|
+
if (fieldSchema.type === "component") {
|
507
|
+
const componentSchema = strapi.getModel(fieldSchema.component).attributes;
|
508
|
+
return {
|
509
|
+
...currentComponentSchemas,
|
510
|
+
[fieldSchema.component]: componentSchema
|
511
|
+
};
|
512
|
+
}
|
513
|
+
return currentComponentSchemas;
|
514
|
+
},
|
515
|
+
{}
|
516
|
+
);
|
517
|
+
return {
|
518
|
+
schema: omit(FIELDS_TO_IGNORE, attributesSchema),
|
519
|
+
componentsSchemas
|
520
|
+
};
|
521
|
+
};
|
467
522
|
const createLifecyclesService = ({ strapi: strapi2 }) => {
|
468
523
|
const state = {
|
469
524
|
deleteExpiredJob: null,
|
@@ -476,63 +531,45 @@ const createLifecyclesService = ({ strapi: strapi2 }) => {
|
|
476
531
|
return;
|
477
532
|
}
|
478
533
|
strapi2.documents.use(async (context, next) => {
|
479
|
-
if (!strapi2.requestContext.get()?.request.url.startsWith("/content-manager")) {
|
480
|
-
return next();
|
481
|
-
}
|
482
|
-
if (context.action !== "create" && context.action !== "update" && context.action !== "clone" && context.action !== "publish" && context.action !== "unpublish" && context.action !== "discardDraft") {
|
483
|
-
return next();
|
484
|
-
}
|
485
|
-
if (context.action === "update" && strapi2.requestContext.get()?.request.url.endsWith("/actions/publish")) {
|
486
|
-
return next();
|
487
|
-
}
|
488
|
-
const contentTypeUid = context.contentType.uid;
|
489
|
-
if (!contentTypeUid.startsWith("api::")) {
|
490
|
-
return next();
|
491
|
-
}
|
492
534
|
const result = await next();
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
535
|
+
if (!shouldCreateHistoryVersion(context)) {
|
536
|
+
return result;
|
537
|
+
}
|
538
|
+
const documentId = context.action === "create" || context.action === "clone" ? result.documentId : context.params.documentId;
|
497
539
|
const defaultLocale = await serviceUtils.getDefaultLocale();
|
498
|
-
const
|
499
|
-
if (
|
500
|
-
|
501
|
-
"[Content manager history middleware]: An array of locales was provided, but only a single locale is supported for the findOne operation."
|
502
|
-
);
|
503
|
-
return next();
|
540
|
+
const locales = castArray(context.params?.locale || defaultLocale);
|
541
|
+
if (!locales.length) {
|
542
|
+
return result;
|
504
543
|
}
|
505
|
-
const
|
506
|
-
|
507
|
-
|
508
|
-
|
544
|
+
const uid2 = context.contentType.uid;
|
545
|
+
const schemas = getSchemas(uid2);
|
546
|
+
const model = strapi2.getModel(uid2);
|
547
|
+
const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);
|
548
|
+
const localeEntries = await strapi2.db.query(uid2).findMany({
|
549
|
+
where: {
|
550
|
+
documentId,
|
551
|
+
...isLocalizedContentType ? { locale: { $in: locales } } : {},
|
552
|
+
...contentTypes$1.hasDraftAndPublish(strapi2.contentTypes[uid2]) ? { publishedAt: null } : {}
|
553
|
+
},
|
554
|
+
populate: serviceUtils.getDeepPopulate(
|
555
|
+
uid2,
|
556
|
+
true
|
557
|
+
/* use database syntax */
|
558
|
+
)
|
509
559
|
});
|
510
|
-
const status = await serviceUtils.getVersionStatus(contentTypeUid, document);
|
511
|
-
const attributesSchema = strapi2.getModel(contentTypeUid).attributes;
|
512
|
-
const componentsSchemas = Object.keys(
|
513
|
-
attributesSchema
|
514
|
-
).reduce((currentComponentSchemas, key) => {
|
515
|
-
const fieldSchema = attributesSchema[key];
|
516
|
-
if (fieldSchema.type === "component") {
|
517
|
-
const componentSchema = strapi2.getModel(fieldSchema.component).attributes;
|
518
|
-
return {
|
519
|
-
...currentComponentSchemas,
|
520
|
-
[fieldSchema.component]: componentSchema
|
521
|
-
};
|
522
|
-
}
|
523
|
-
return currentComponentSchemas;
|
524
|
-
}, {});
|
525
560
|
await strapi2.db.transaction(async ({ onCommit }) => {
|
526
|
-
onCommit(() => {
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
561
|
+
onCommit(async () => {
|
562
|
+
for (const entry of localeEntries) {
|
563
|
+
const status = await serviceUtils.getVersionStatus(uid2, entry);
|
564
|
+
await getService(strapi2, "history").createVersion({
|
565
|
+
contentType: uid2,
|
566
|
+
data: omit(FIELDS_TO_IGNORE, entry),
|
567
|
+
relatedDocumentId: documentId,
|
568
|
+
locale: entry.locale,
|
569
|
+
status,
|
570
|
+
...schemas
|
571
|
+
});
|
572
|
+
}
|
536
573
|
});
|
537
574
|
});
|
538
575
|
return result;
|
@@ -1172,6 +1209,11 @@ const { createPolicy } = policy;
|
|
1172
1209
|
const hasPermissions = createPolicy({
|
1173
1210
|
name: "plugin::content-manager.hasPermissions",
|
1174
1211
|
validator: validateHasPermissionsInput,
|
1212
|
+
/**
|
1213
|
+
* NOTE: Action aliases are currently not checked at this level (policy).
|
1214
|
+
* This is currently the intended behavior to avoid changing the behavior of API related permissions.
|
1215
|
+
* If you want to add support for it, please create a dedicated RFC with a list of potential side effect this could have.
|
1216
|
+
*/
|
1175
1217
|
handler(ctx, config = {}) {
|
1176
1218
|
const { actions = [], hasAtLeastOne = false } = config;
|
1177
1219
|
const { userAbility } = ctx.state;
|
@@ -1565,9 +1607,11 @@ const multipleLocaleSchema = yup$1.lazy(
|
|
1565
1607
|
(value) => Array.isArray(value) ? yup$1.array().of(singleLocaleSchema.required()) : singleLocaleSchema
|
1566
1608
|
);
|
1567
1609
|
const statusSchema = yup$1.mixed().oneOf(["draft", "published"], "Invalid status");
|
1568
|
-
const getDocumentLocaleAndStatus = async (request, opts = { allowMultipleLocales: false }) => {
|
1610
|
+
const getDocumentLocaleAndStatus = async (request, model, opts = { allowMultipleLocales: false }) => {
|
1569
1611
|
const { allowMultipleLocales } = opts;
|
1570
|
-
const { locale, status, ...rest } = request || {};
|
1612
|
+
const { locale, status: providedStatus, ...rest } = request || {};
|
1613
|
+
const defaultStatus = contentTypes$1.hasDraftAndPublish(strapi.getModel(model)) ? void 0 : "published";
|
1614
|
+
const status = providedStatus !== void 0 ? providedStatus : defaultStatus;
|
1571
1615
|
const schema = yup$1.object().shape({
|
1572
1616
|
locale: allowMultipleLocales ? multipleLocaleSchema : singleLocaleSchema,
|
1573
1617
|
status: statusSchema
|
@@ -1615,7 +1659,7 @@ const createDocument = async (ctx, opts) => {
|
|
1615
1659
|
const setCreator = setCreatorFields({ user });
|
1616
1660
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1617
1661
|
const sanitizedBody = await sanitizeFn(body);
|
1618
|
-
const { locale, status
|
1662
|
+
const { locale, status } = await getDocumentLocaleAndStatus(body, model);
|
1619
1663
|
return documentManager2.create(model, {
|
1620
1664
|
data: sanitizedBody,
|
1621
1665
|
locale,
|
@@ -1634,7 +1678,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1634
1678
|
}
|
1635
1679
|
const permissionQuery = await permissionChecker2.sanitizedQuery.update(ctx.query);
|
1636
1680
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1637
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1681
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1638
1682
|
const [documentVersion, documentExists] = await Promise.all([
|
1639
1683
|
documentManager2.findOne(id, model, { populate, locale, status: "draft" }),
|
1640
1684
|
documentManager2.exists(model, id)
|
@@ -1650,7 +1694,7 @@ const updateDocument = async (ctx, opts) => {
|
|
1650
1694
|
throw new errors.ForbiddenError();
|
1651
1695
|
}
|
1652
1696
|
const pickPermittedFields = documentVersion ? permissionChecker2.sanitizeUpdateInput(documentVersion) : permissionChecker2.sanitizeCreateInput;
|
1653
|
-
const setCreator = setCreatorFields({ user, isEdition: true });
|
1697
|
+
const setCreator = documentVersion ? setCreatorFields({ user, isEdition: true }) : setCreatorFields({ user });
|
1654
1698
|
const sanitizeFn = async.pipe(pickPermittedFields, setCreator);
|
1655
1699
|
const sanitizedBody = await sanitizeFn(body);
|
1656
1700
|
return documentManager2.update(documentVersion?.documentId || id, model, {
|
@@ -1672,7 +1716,7 @@ const collectionTypes = {
|
|
1672
1716
|
}
|
1673
1717
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
1674
1718
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(1).countRelations({ toOne: false, toMany: true }).build();
|
1675
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
1719
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
1676
1720
|
const { results: documents, pagination: pagination2 } = await documentManager2.findPage(
|
1677
1721
|
{ ...permissionQuery, populate, locale, status },
|
1678
1722
|
model
|
@@ -1707,7 +1751,7 @@ const collectionTypes = {
|
|
1707
1751
|
}
|
1708
1752
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
1709
1753
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1710
|
-
const { locale, status
|
1754
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1711
1755
|
const version = await documentManager2.findOne(id, model, {
|
1712
1756
|
populate,
|
1713
1757
|
locale,
|
@@ -1722,7 +1766,7 @@ const collectionTypes = {
|
|
1722
1766
|
permissionChecker2,
|
1723
1767
|
model,
|
1724
1768
|
// @ts-expect-error TODO: fix
|
1725
|
-
{ id, locale, publishedAt: null },
|
1769
|
+
{ documentId: id, locale, publishedAt: null },
|
1726
1770
|
{ availableLocales: true, availableStatus: false }
|
1727
1771
|
);
|
1728
1772
|
ctx.body = { data: {}, meta };
|
@@ -1774,7 +1818,7 @@ const collectionTypes = {
|
|
1774
1818
|
}
|
1775
1819
|
const permissionQuery = await permissionChecker2.sanitizedQuery.create(ctx.query);
|
1776
1820
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1777
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1821
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1778
1822
|
const document = await documentManager2.findOne(id, model, {
|
1779
1823
|
populate,
|
1780
1824
|
locale,
|
@@ -1819,7 +1863,7 @@ const collectionTypes = {
|
|
1819
1863
|
}
|
1820
1864
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(ctx.query);
|
1821
1865
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1822
|
-
const { locale } = await getDocumentLocaleAndStatus(ctx.query);
|
1866
|
+
const { locale } = await getDocumentLocaleAndStatus(ctx.query, model);
|
1823
1867
|
const documentLocales = await documentManager2.findLocales(id, model, { populate, locale });
|
1824
1868
|
if (documentLocales.length === 0) {
|
1825
1869
|
return ctx.notFound();
|
@@ -1848,11 +1892,34 @@ const collectionTypes = {
|
|
1848
1892
|
const publishedDocument = await strapi.db.transaction(async () => {
|
1849
1893
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1850
1894
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1851
|
-
|
1895
|
+
let document;
|
1896
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1897
|
+
const isCreate = isNil$1(id);
|
1898
|
+
if (isCreate) {
|
1899
|
+
if (permissionChecker2.cannot.create()) {
|
1900
|
+
throw new errors.ForbiddenError();
|
1901
|
+
}
|
1902
|
+
document = await createDocument(ctx, { populate });
|
1903
|
+
}
|
1904
|
+
const isUpdate = !isCreate;
|
1905
|
+
if (isUpdate) {
|
1906
|
+
const documentExists = documentManager2.exists(model, id);
|
1907
|
+
if (!documentExists) {
|
1908
|
+
throw new errors.NotFoundError("Document not found");
|
1909
|
+
}
|
1910
|
+
document = await documentManager2.findOne(id, model, { populate, locale });
|
1911
|
+
if (!document) {
|
1912
|
+
if (permissionChecker2.cannot.create({ locale }) || permissionChecker2.cannot.publish({ locale })) {
|
1913
|
+
throw new errors.ForbiddenError();
|
1914
|
+
}
|
1915
|
+
document = await updateDocument(ctx);
|
1916
|
+
} else if (permissionChecker2.can.update(document)) {
|
1917
|
+
await updateDocument(ctx);
|
1918
|
+
}
|
1919
|
+
}
|
1852
1920
|
if (permissionChecker2.cannot.publish(document)) {
|
1853
1921
|
throw new errors.ForbiddenError();
|
1854
1922
|
}
|
1855
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
1856
1923
|
const publishResult = await documentManager2.publish(document.documentId, model, {
|
1857
1924
|
locale
|
1858
1925
|
// TODO: Allow setting creator fields on publish
|
@@ -1879,7 +1946,9 @@ const collectionTypes = {
|
|
1879
1946
|
}
|
1880
1947
|
const permissionQuery = await permissionChecker2.sanitizedQuery.publish(ctx.query);
|
1881
1948
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).populateDeep(Infinity).countRelations().build();
|
1882
|
-
const { locale } = await getDocumentLocaleAndStatus(body, {
|
1949
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1950
|
+
allowMultipleLocales: true
|
1951
|
+
});
|
1883
1952
|
const entityPromises = documentIds.map(
|
1884
1953
|
(documentId) => documentManager2.findLocales(documentId, model, { populate, locale, isPublished: false })
|
1885
1954
|
);
|
@@ -1906,7 +1975,9 @@ const collectionTypes = {
|
|
1906
1975
|
if (permissionChecker2.cannot.unpublish()) {
|
1907
1976
|
return ctx.forbidden();
|
1908
1977
|
}
|
1909
|
-
const { locale } = await getDocumentLocaleAndStatus(body
|
1978
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model, {
|
1979
|
+
allowMultipleLocales: true
|
1980
|
+
});
|
1910
1981
|
const entityPromises = documentIds.map(
|
1911
1982
|
(documentId) => documentManager2.findLocales(documentId, model, { locale, isPublished: true })
|
1912
1983
|
);
|
@@ -1939,7 +2010,7 @@ const collectionTypes = {
|
|
1939
2010
|
}
|
1940
2011
|
const permissionQuery = await permissionChecker2.sanitizedQuery.unpublish(ctx.query);
|
1941
2012
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1942
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2013
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1943
2014
|
const document = await documentManager2.findOne(id, model, {
|
1944
2015
|
populate,
|
1945
2016
|
locale,
|
@@ -1976,7 +2047,7 @@ const collectionTypes = {
|
|
1976
2047
|
}
|
1977
2048
|
const permissionQuery = await permissionChecker2.sanitizedQuery.discard(ctx.query);
|
1978
2049
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
1979
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2050
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
1980
2051
|
const document = await documentManager2.findOne(id, model, {
|
1981
2052
|
populate,
|
1982
2053
|
locale,
|
@@ -2007,7 +2078,7 @@ const collectionTypes = {
|
|
2007
2078
|
}
|
2008
2079
|
const permissionQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2009
2080
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2010
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2081
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2011
2082
|
const documentLocales = await documentManager2.findLocales(documentIds, model, {
|
2012
2083
|
populate,
|
2013
2084
|
locale
|
@@ -2034,7 +2105,7 @@ const collectionTypes = {
|
|
2034
2105
|
}
|
2035
2106
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(ctx.query);
|
2036
2107
|
const populate = await getService$1("populate-builder")(model).populateFromQuery(permissionQuery).build();
|
2037
|
-
const { locale, status
|
2108
|
+
const { locale, status } = await getDocumentLocaleAndStatus(ctx.query, model);
|
2038
2109
|
const entity = await documentManager2.findOne(id, model, { populate, locale, status });
|
2039
2110
|
if (!entity) {
|
2040
2111
|
return ctx.notFound();
|
@@ -2257,32 +2328,37 @@ const sanitizeMainField = (model, mainField, userAbility) => {
|
|
2257
2328
|
userAbility,
|
2258
2329
|
model: model.uid
|
2259
2330
|
});
|
2260
|
-
|
2331
|
+
const isMainFieldListable = isListable(model, mainField);
|
2332
|
+
const canReadMainField = permissionChecker2.can.read(null, mainField);
|
2333
|
+
if (!isMainFieldListable || !canReadMainField) {
|
2261
2334
|
return "id";
|
2262
2335
|
}
|
2263
|
-
if (
|
2264
|
-
|
2265
|
-
const userPermissionChecker = getService$1("permission-checker").create({
|
2266
|
-
userAbility,
|
2267
|
-
model: "plugin::users-permissions.user"
|
2268
|
-
});
|
2269
|
-
if (userPermissionChecker.can.read()) {
|
2270
|
-
return "name";
|
2271
|
-
}
|
2272
|
-
}
|
2273
|
-
return "id";
|
2336
|
+
if (model.uid === "plugin::users-permissions.role") {
|
2337
|
+
return "name";
|
2274
2338
|
}
|
2275
2339
|
return mainField;
|
2276
2340
|
};
|
2277
|
-
const addStatusToRelations = async (
|
2278
|
-
if (!contentTypes$1.hasDraftAndPublish(strapi.
|
2341
|
+
const addStatusToRelations = async (targetUid, relations2) => {
|
2342
|
+
if (!contentTypes$1.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
2279
2343
|
return relations2;
|
2280
2344
|
}
|
2281
2345
|
const documentMetadata2 = getService$1("document-metadata");
|
2282
|
-
|
2346
|
+
if (!relations2.length) {
|
2347
|
+
return relations2;
|
2348
|
+
}
|
2349
|
+
const firstRelation = relations2[0];
|
2350
|
+
const filters = {
|
2351
|
+
documentId: { $in: relations2.map((r) => r.documentId) },
|
2352
|
+
// NOTE: find the "opposite" status
|
2353
|
+
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true }
|
2354
|
+
};
|
2355
|
+
const availableStatus = await strapi.query(targetUid).findMany({
|
2356
|
+
select: ["id", "documentId", "locale", "updatedAt", "createdAt", "publishedAt"],
|
2357
|
+
filters
|
2358
|
+
});
|
2283
2359
|
return relations2.map((relation) => {
|
2284
|
-
const availableStatuses =
|
2285
|
-
(availableDocument) => availableDocument.documentId === relation.documentId
|
2360
|
+
const availableStatuses = availableStatus.filter(
|
2361
|
+
(availableDocument) => availableDocument.documentId === relation.documentId && (relation.locale ? availableDocument.locale === relation.locale : true)
|
2286
2362
|
);
|
2287
2363
|
return {
|
2288
2364
|
...relation,
|
@@ -2303,11 +2379,8 @@ const validateLocale = (sourceUid, targetUid, locale) => {
|
|
2303
2379
|
const isLocalized = strapi.plugin("i18n").service("content-types").isLocalizedContentType;
|
2304
2380
|
const isSourceLocalized = isLocalized(sourceModel);
|
2305
2381
|
const isTargetLocalized = isLocalized(targetModel);
|
2306
|
-
let validatedLocale = locale;
|
2307
|
-
if (!targetModel || !isTargetLocalized)
|
2308
|
-
validatedLocale = void 0;
|
2309
2382
|
return {
|
2310
|
-
locale
|
2383
|
+
locale,
|
2311
2384
|
isSourceLocalized,
|
2312
2385
|
isTargetLocalized
|
2313
2386
|
};
|
@@ -2410,7 +2483,7 @@ const relations = {
|
|
2410
2483
|
attribute,
|
2411
2484
|
fieldsToSelect,
|
2412
2485
|
mainField,
|
2413
|
-
source: { schema: sourceSchema },
|
2486
|
+
source: { schema: sourceSchema, isLocalized: isSourceLocalized },
|
2414
2487
|
target: { schema: targetSchema, isLocalized: isTargetLocalized },
|
2415
2488
|
sourceSchema,
|
2416
2489
|
targetSchema,
|
@@ -2432,7 +2505,8 @@ const relations = {
|
|
2432
2505
|
fieldsToSelect,
|
2433
2506
|
mainField,
|
2434
2507
|
source: {
|
2435
|
-
schema: { uid: sourceUid, modelType: sourceModelType }
|
2508
|
+
schema: { uid: sourceUid, modelType: sourceModelType },
|
2509
|
+
isLocalized: isSourceLocalized
|
2436
2510
|
},
|
2437
2511
|
target: {
|
2438
2512
|
schema: { uid: targetUid },
|
@@ -2470,12 +2544,16 @@ const relations = {
|
|
2470
2544
|
} else {
|
2471
2545
|
where.id = id;
|
2472
2546
|
}
|
2473
|
-
|
2474
|
-
|
2547
|
+
const publishedAt = getPublishedAtClause(status, targetUid);
|
2548
|
+
if (!isEmpty(publishedAt)) {
|
2549
|
+
where[`${alias}.published_at`] = publishedAt;
|
2475
2550
|
}
|
2476
|
-
if (
|
2551
|
+
if (isTargetLocalized && locale) {
|
2477
2552
|
where[`${alias}.locale`] = locale;
|
2478
2553
|
}
|
2554
|
+
if (isSourceLocalized && locale) {
|
2555
|
+
where.locale = locale;
|
2556
|
+
}
|
2479
2557
|
if ((idsToInclude?.length ?? 0) !== 0) {
|
2480
2558
|
where[`${alias}.id`].$notIn = idsToInclude;
|
2481
2559
|
}
|
@@ -2493,7 +2571,8 @@ const relations = {
|
|
2493
2571
|
id: { $notIn: uniq(idsToOmit) }
|
2494
2572
|
});
|
2495
2573
|
}
|
2496
|
-
const
|
2574
|
+
const dbQuery = strapi.get("query-params").transform(targetUid, queryParams);
|
2575
|
+
const res = await strapi.db.query(targetUid).findPage(dbQuery);
|
2497
2576
|
ctx.body = {
|
2498
2577
|
...res,
|
2499
2578
|
results: await addStatusToRelations(targetUid, res.results)
|
@@ -2508,29 +2587,39 @@ const relations = {
|
|
2508
2587
|
attribute,
|
2509
2588
|
targetField,
|
2510
2589
|
fieldsToSelect,
|
2511
|
-
|
2512
|
-
|
2513
|
-
}
|
2514
|
-
target: {
|
2515
|
-
schema: { uid: targetUid }
|
2516
|
-
}
|
2590
|
+
status,
|
2591
|
+
source: { schema: sourceSchema },
|
2592
|
+
target: { schema: targetSchema }
|
2517
2593
|
} = await this.extractAndValidateRequestInfo(ctx, id);
|
2594
|
+
const { uid: sourceUid } = sourceSchema;
|
2595
|
+
const { uid: targetUid } = targetSchema;
|
2518
2596
|
const permissionQuery = await getService$1("permission-checker").create({ userAbility, model: targetUid }).sanitizedQuery.read({ fields: fieldsToSelect });
|
2519
2597
|
const dbQuery = strapi.db.query(sourceUid);
|
2520
2598
|
const loadRelations = relations$1.isAnyToMany(attribute) ? (...args) => dbQuery.loadPages(...args) : (...args) => dbQuery.load(...args).then((res2) => ({ results: res2 ? [res2] : [] }));
|
2599
|
+
const filters = {};
|
2600
|
+
if (sourceSchema?.options?.draftAndPublish) {
|
2601
|
+
if (targetSchema?.options?.draftAndPublish) {
|
2602
|
+
if (status === "published") {
|
2603
|
+
filters.publishedAt = { $notNull: true };
|
2604
|
+
} else {
|
2605
|
+
filters.publishedAt = { $null: true };
|
2606
|
+
}
|
2607
|
+
}
|
2608
|
+
} else if (targetSchema?.options?.draftAndPublish) {
|
2609
|
+
filters.publishedAt = { $null: true };
|
2610
|
+
}
|
2521
2611
|
const res = await loadRelations({ id: entryId }, targetField, {
|
2522
|
-
select: ["id", "documentId", "locale", "publishedAt"],
|
2612
|
+
select: ["id", "documentId", "locale", "publishedAt", "updatedAt"],
|
2523
2613
|
ordering: "desc",
|
2524
2614
|
page: ctx.request.query.page,
|
2525
|
-
pageSize: ctx.request.query.pageSize
|
2615
|
+
pageSize: ctx.request.query.pageSize,
|
2616
|
+
filters
|
2526
2617
|
});
|
2527
2618
|
const loadedIds = res.results.map((item) => item.id);
|
2528
2619
|
addFiltersClause(permissionQuery, { id: { $in: loadedIds } });
|
2529
2620
|
const sanitizedRes = await loadRelations({ id: entryId }, targetField, {
|
2530
2621
|
...strapi.get("query-params").transform(targetUid, permissionQuery),
|
2531
|
-
ordering: "desc"
|
2532
|
-
page: ctx.request.query.page,
|
2533
|
-
pageSize: ctx.request.query.pageSize
|
2622
|
+
ordering: "desc"
|
2534
2623
|
});
|
2535
2624
|
const relationsUnion = uniqBy("id", concat(sanitizedRes.results, res.results));
|
2536
2625
|
ctx.body = {
|
@@ -2562,7 +2651,7 @@ const createOrUpdateDocument = async (ctx, opts) => {
|
|
2562
2651
|
throw new errors.ForbiddenError();
|
2563
2652
|
}
|
2564
2653
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.update(query);
|
2565
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2654
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2566
2655
|
const [documentVersion, otherDocumentVersion] = await Promise.all([
|
2567
2656
|
findDocument(sanitizedQuery, model, { locale, status: "draft" }),
|
2568
2657
|
// Find the first document to check if it exists
|
@@ -2603,7 +2692,7 @@ const singleTypes = {
|
|
2603
2692
|
return ctx.forbidden();
|
2604
2693
|
}
|
2605
2694
|
const permissionQuery = await permissionChecker2.sanitizedQuery.read(query);
|
2606
|
-
const { locale, status } = await getDocumentLocaleAndStatus(query);
|
2695
|
+
const { locale, status } = await getDocumentLocaleAndStatus(query, model);
|
2607
2696
|
const version = await findDocument(permissionQuery, model, { locale, status });
|
2608
2697
|
if (!version) {
|
2609
2698
|
if (permissionChecker2.cannot.create()) {
|
@@ -2617,7 +2706,7 @@ const singleTypes = {
|
|
2617
2706
|
permissionChecker2,
|
2618
2707
|
model,
|
2619
2708
|
// @ts-expect-error - fix types
|
2620
|
-
{
|
2709
|
+
{ documentId: document.documentId, locale, publishedAt: null },
|
2621
2710
|
{ availableLocales: true, availableStatus: false }
|
2622
2711
|
);
|
2623
2712
|
ctx.body = { data: {}, meta };
|
@@ -2648,7 +2737,7 @@ const singleTypes = {
|
|
2648
2737
|
}
|
2649
2738
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.delete(query);
|
2650
2739
|
const populate = await buildPopulateFromQuery(sanitizedQuery, model);
|
2651
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2740
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2652
2741
|
const documentLocales = await documentManager2.findLocales(void 0, model, {
|
2653
2742
|
populate,
|
2654
2743
|
locale
|
@@ -2685,7 +2774,7 @@ const singleTypes = {
|
|
2685
2774
|
if (permissionChecker2.cannot.publish(document)) {
|
2686
2775
|
throw new errors.ForbiddenError();
|
2687
2776
|
}
|
2688
|
-
const { locale } = await getDocumentLocaleAndStatus(document);
|
2777
|
+
const { locale } = await getDocumentLocaleAndStatus(document, model);
|
2689
2778
|
const publishResult = await documentManager2.publish(document.documentId, model, { locale });
|
2690
2779
|
return publishResult.at(0);
|
2691
2780
|
});
|
@@ -2708,7 +2797,7 @@ const singleTypes = {
|
|
2708
2797
|
return ctx.forbidden();
|
2709
2798
|
}
|
2710
2799
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.unpublish(query);
|
2711
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2800
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2712
2801
|
const document = await findDocument(sanitizedQuery, model, { locale });
|
2713
2802
|
if (!document) {
|
2714
2803
|
return ctx.notFound();
|
@@ -2740,7 +2829,7 @@ const singleTypes = {
|
|
2740
2829
|
return ctx.forbidden();
|
2741
2830
|
}
|
2742
2831
|
const sanitizedQuery = await permissionChecker2.sanitizedQuery.discard(query);
|
2743
|
-
const { locale } = await getDocumentLocaleAndStatus(body);
|
2832
|
+
const { locale } = await getDocumentLocaleAndStatus(body, model);
|
2744
2833
|
const document = await findDocument(sanitizedQuery, model, { locale, status: "published" });
|
2745
2834
|
if (!document) {
|
2746
2835
|
return ctx.notFound();
|
@@ -2760,7 +2849,7 @@ const singleTypes = {
|
|
2760
2849
|
const { query } = ctx.request;
|
2761
2850
|
const documentManager2 = getService$1("document-manager");
|
2762
2851
|
const permissionChecker2 = getService$1("permission-checker").create({ userAbility, model });
|
2763
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2852
|
+
const { locale } = await getDocumentLocaleAndStatus(query, model);
|
2764
2853
|
if (permissionChecker2.cannot.read()) {
|
2765
2854
|
return ctx.forbidden();
|
2766
2855
|
}
|
@@ -2781,7 +2870,7 @@ const uid$1 = {
|
|
2781
2870
|
async generateUID(ctx) {
|
2782
2871
|
const { contentTypeUID, field, data } = await validateGenerateUIDInput(ctx.request.body);
|
2783
2872
|
const { query = {} } = ctx.request;
|
2784
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2873
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2785
2874
|
await validateUIDField(contentTypeUID, field);
|
2786
2875
|
const uidService = getService$1("uid");
|
2787
2876
|
ctx.body = {
|
@@ -2793,7 +2882,7 @@ const uid$1 = {
|
|
2793
2882
|
ctx.request.body
|
2794
2883
|
);
|
2795
2884
|
const { query = {} } = ctx.request;
|
2796
|
-
const { locale } = await getDocumentLocaleAndStatus(query);
|
2885
|
+
const { locale } = await getDocumentLocaleAndStatus(query, contentTypeUID);
|
2797
2886
|
await validateUIDField(contentTypeUID, field);
|
2798
2887
|
const uidService = getService$1("uid");
|
2799
2888
|
const isAvailable = await uidService.checkUIDAvailability({
|
@@ -3436,12 +3525,27 @@ const createPermissionChecker = (strapi2) => ({ userAbility, model }) => {
|
|
3436
3525
|
ability: userAbility,
|
3437
3526
|
model
|
3438
3527
|
});
|
3439
|
-
const
|
3528
|
+
const { actionProvider } = strapi2.service("admin::permission");
|
3529
|
+
const toSubject = (entity) => {
|
3530
|
+
return entity ? permissionsManager.toSubject(entity, model) : model;
|
3531
|
+
};
|
3440
3532
|
const can = (action, entity, field) => {
|
3441
|
-
|
3533
|
+
const subject = toSubject(entity);
|
3534
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3535
|
+
return (
|
3536
|
+
// Test the original action to see if it passes
|
3537
|
+
userAbility.can(action, subject, field) || // Else try every known alias if at least one of them succeed, then the user "can"
|
3538
|
+
aliases.some((alias) => userAbility.can(alias, subject, field))
|
3539
|
+
);
|
3442
3540
|
};
|
3443
3541
|
const cannot = (action, entity, field) => {
|
3444
|
-
|
3542
|
+
const subject = toSubject(entity);
|
3543
|
+
const aliases = actionProvider.unstable_aliases(action, model);
|
3544
|
+
return (
|
3545
|
+
// Test both the original action
|
3546
|
+
userAbility.cannot(action, subject, field) && // and every known alias, if all of them fail (cannot), then the user truly "cannot"
|
3547
|
+
aliases.every((alias) => userAbility.cannot(alias, subject, field))
|
3548
|
+
);
|
3445
3549
|
};
|
3446
3550
|
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {
|
3447
3551
|
return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });
|
@@ -3718,6 +3822,10 @@ const getDeepPopulateDraftCount = (uid2) => {
|
|
3718
3822
|
const attribute = model.attributes[attributeName];
|
3719
3823
|
switch (attribute.type) {
|
3720
3824
|
case "relation": {
|
3825
|
+
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
3826
|
+
if (isMorphRelation) {
|
3827
|
+
break;
|
3828
|
+
}
|
3721
3829
|
if (isVisibleAttribute$1(model, attributeName)) {
|
3722
3830
|
populateAcc[attributeName] = {
|
3723
3831
|
count: true,
|
@@ -3969,7 +4077,9 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
3969
4077
|
*/
|
3970
4078
|
async getAvailableLocales(uid2, version, allVersions, validatableFields = []) {
|
3971
4079
|
const versionsByLocale = groupBy("locale", allVersions);
|
3972
|
-
|
4080
|
+
if (version.locale) {
|
4081
|
+
delete versionsByLocale[version.locale];
|
4082
|
+
}
|
3973
4083
|
const model = strapi2.getModel(uid2);
|
3974
4084
|
const keysToKeep = [...AVAILABLE_LOCALES_FIELDS, ...validatableFields];
|
3975
4085
|
const traversalFunction = async (localeVersion) => traverseEntity(
|
@@ -4095,7 +4205,13 @@ const documentMetadata = ({ strapi: strapi2 }) => ({
|
|
4095
4205
|
*/
|
4096
4206
|
async formatDocumentWithMetadata(uid2, document, opts = {}) {
|
4097
4207
|
if (!document) {
|
4098
|
-
return
|
4208
|
+
return {
|
4209
|
+
data: document,
|
4210
|
+
meta: {
|
4211
|
+
availableLocales: [],
|
4212
|
+
availableStatus: []
|
4213
|
+
}
|
4214
|
+
};
|
4099
4215
|
}
|
4100
4216
|
const hasDraftAndPublish = contentTypes$1.hasDraftAndPublish(strapi2.getModel(uid2));
|
4101
4217
|
if (!hasDraftAndPublish) {
|
@@ -4203,10 +4319,7 @@ const documentManager = ({ strapi: strapi2 }) => {
|
|
4203
4319
|
async clone(id, body, uid2) {
|
4204
4320
|
const populate = await buildDeepPopulate(uid2);
|
4205
4321
|
const params = {
|
4206
|
-
data:
|
4207
|
-
...omitIdField(body),
|
4208
|
-
[PUBLISHED_AT_ATTRIBUTE]: null
|
4209
|
-
},
|
4322
|
+
data: omitIdField(body),
|
4210
4323
|
populate
|
4211
4324
|
};
|
4212
4325
|
return strapi2.documents(uid2).clone({ ...params, documentId: id }).then((result) => result?.entries.at(0));
|