@strapi/core 5.51.0 → 5.51.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/dist/package.json.js +13 -13
- package/dist/package.json.mjs +13 -13
- package/dist/services/document-service/entries.d.ts.map +1 -1
- package/dist/services/document-service/entries.js +16 -2
- package/dist/services/document-service/entries.js.map +1 -1
- package/dist/services/document-service/entries.mjs +16 -2
- package/dist/services/document-service/entries.mjs.map +1 -1
- package/dist/services/entity-validator/index.d.ts +1 -0
- package/dist/services/entity-validator/index.d.ts.map +1 -1
- package/dist/services/entity-validator/index.js +152 -25
- package/dist/services/entity-validator/index.js.map +1 -1
- package/dist/services/entity-validator/index.mjs +152 -25
- package/dist/services/entity-validator/index.mjs.map +1 -1
- package/package.json +13 -13
package/dist/package.json.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var name = "@strapi/core";
|
|
6
|
-
var version = "5.51.
|
|
6
|
+
var version = "5.51.1";
|
|
7
7
|
var description = "Core of Strapi";
|
|
8
8
|
var homepage = "https://strapi.io";
|
|
9
9
|
var bugs = {
|
|
@@ -65,15 +65,15 @@ var dependencies = {
|
|
|
65
65
|
"@koa/router": "12.0.2",
|
|
66
66
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
67
67
|
"@paralleldrive/cuid2": "2.2.2",
|
|
68
|
-
"@strapi/admin": "5.51.
|
|
69
|
-
"@strapi/database": "5.51.
|
|
70
|
-
"@strapi/generators": "5.51.
|
|
71
|
-
"@strapi/logger": "5.51.
|
|
72
|
-
"@strapi/openapi": "5.51.
|
|
73
|
-
"@strapi/permissions": "5.51.
|
|
74
|
-
"@strapi/types": "5.51.
|
|
75
|
-
"@strapi/typescript-utils": "5.51.
|
|
76
|
-
"@strapi/utils": "5.51.
|
|
68
|
+
"@strapi/admin": "5.51.1",
|
|
69
|
+
"@strapi/database": "5.51.1",
|
|
70
|
+
"@strapi/generators": "5.51.1",
|
|
71
|
+
"@strapi/logger": "5.51.1",
|
|
72
|
+
"@strapi/openapi": "5.51.1",
|
|
73
|
+
"@strapi/permissions": "5.51.1",
|
|
74
|
+
"@strapi/types": "5.51.1",
|
|
75
|
+
"@strapi/typescript-utils": "5.51.1",
|
|
76
|
+
"@strapi/utils": "5.51.1",
|
|
77
77
|
"@vercel/stega": "0.1.2",
|
|
78
78
|
bcryptjs: "2.4.3",
|
|
79
79
|
boxen: "5.1.2",
|
|
@@ -137,12 +137,12 @@ var devDependencies = {
|
|
|
137
137
|
"@types/mime-types": "2.1.1",
|
|
138
138
|
"@types/node": "20.19.41",
|
|
139
139
|
"@types/node-schedule": "2.1.7",
|
|
140
|
-
"eslint-config-custom": "5.51.
|
|
140
|
+
"eslint-config-custom": "5.51.1",
|
|
141
141
|
jest: "29.6.0",
|
|
142
142
|
supertest: "7.2.2",
|
|
143
|
-
tsconfig: "5.51.
|
|
143
|
+
tsconfig: "5.51.1",
|
|
144
144
|
vitest: "catalog:",
|
|
145
|
-
"vitest-config": "5.51.
|
|
145
|
+
"vitest-config": "5.51.1"
|
|
146
146
|
};
|
|
147
147
|
var engines = {
|
|
148
148
|
node: ">=20.0.0 <=26.x.x",
|
package/dist/package.json.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "@strapi/core";
|
|
2
|
-
var version = "5.51.
|
|
2
|
+
var version = "5.51.1";
|
|
3
3
|
var description = "Core of Strapi";
|
|
4
4
|
var homepage = "https://strapi.io";
|
|
5
5
|
var bugs = {
|
|
@@ -61,15 +61,15 @@ var dependencies = {
|
|
|
61
61
|
"@koa/router": "12.0.2",
|
|
62
62
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
63
63
|
"@paralleldrive/cuid2": "2.2.2",
|
|
64
|
-
"@strapi/admin": "5.51.
|
|
65
|
-
"@strapi/database": "5.51.
|
|
66
|
-
"@strapi/generators": "5.51.
|
|
67
|
-
"@strapi/logger": "5.51.
|
|
68
|
-
"@strapi/openapi": "5.51.
|
|
69
|
-
"@strapi/permissions": "5.51.
|
|
70
|
-
"@strapi/types": "5.51.
|
|
71
|
-
"@strapi/typescript-utils": "5.51.
|
|
72
|
-
"@strapi/utils": "5.51.
|
|
64
|
+
"@strapi/admin": "5.51.1",
|
|
65
|
+
"@strapi/database": "5.51.1",
|
|
66
|
+
"@strapi/generators": "5.51.1",
|
|
67
|
+
"@strapi/logger": "5.51.1",
|
|
68
|
+
"@strapi/openapi": "5.51.1",
|
|
69
|
+
"@strapi/permissions": "5.51.1",
|
|
70
|
+
"@strapi/types": "5.51.1",
|
|
71
|
+
"@strapi/typescript-utils": "5.51.1",
|
|
72
|
+
"@strapi/utils": "5.51.1",
|
|
73
73
|
"@vercel/stega": "0.1.2",
|
|
74
74
|
bcryptjs: "2.4.3",
|
|
75
75
|
boxen: "5.1.2",
|
|
@@ -133,12 +133,12 @@ var devDependencies = {
|
|
|
133
133
|
"@types/mime-types": "2.1.1",
|
|
134
134
|
"@types/node": "20.19.41",
|
|
135
135
|
"@types/node-schedule": "2.1.7",
|
|
136
|
-
"eslint-config-custom": "5.51.
|
|
136
|
+
"eslint-config-custom": "5.51.1",
|
|
137
137
|
jest: "29.6.0",
|
|
138
138
|
supertest: "7.2.2",
|
|
139
|
-
tsconfig: "5.51.
|
|
139
|
+
tsconfig: "5.51.1",
|
|
140
140
|
vitest: "catalog:",
|
|
141
|
-
"vitest-config": "5.51.
|
|
141
|
+
"vitest-config": "5.51.1"
|
|
142
142
|
};
|
|
143
143
|
var engines = {
|
|
144
144
|
node: ">=20.0.0 <=26.x.x",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../src/services/document-service/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../../src/services/document-service/entries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAkClD,QAAA,MAAM,oBAAoB,GACxB,KAAK,GAAG,CAAC,WAAW,EACpB,iBAAiB,OAAO,CAAC,eAAe,CAAC,eAAe;sBAId,GAAG;iBAwEd,MAAM,UAAgB,GAAG;4BAUd,GAAG,WAAiB,GAAG;qBA6B9B,GAAG,WAAiB,GAAG;0BAqBlB,GAAG,WAAiB,GAAG;CA4BhE,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -9,6 +9,18 @@ var params = require('./params.js');
|
|
|
9
9
|
var index = require('./attributes/index.js');
|
|
10
10
|
var data = require('./transform/data.js');
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Reads and validates the `api.documents.strictRelations` flag.
|
|
14
|
+
* false/undefined => legacy behaviour (relational required constraints not enforced),
|
|
15
|
+
* true => enforce required media and relations on non-draft writes.
|
|
16
|
+
* Mirrors the validation of `api.documents.strictParams` (see repository.ts).
|
|
17
|
+
*/ const isStrictRelationsEnabled = ()=>{
|
|
18
|
+
const rawStrictRelations = strapi.config.get('api.documents.strictRelations', undefined);
|
|
19
|
+
if (rawStrictRelations !== undefined && rawStrictRelations !== false && rawStrictRelations !== true) {
|
|
20
|
+
throw new strapiUtils.errors.ValidationError(`Invalid config.api.documents.strictRelations value: "${rawStrictRelations}". Expected boolean (true or false).`);
|
|
21
|
+
}
|
|
22
|
+
return rawStrictRelations === true;
|
|
23
|
+
};
|
|
12
24
|
const createEntriesService = (uid, entityValidator)=>{
|
|
13
25
|
const contentType = strapi.contentType(uid);
|
|
14
26
|
async function createEntry(params$1 = {}) {
|
|
@@ -63,7 +75,8 @@ const createEntriesService = (uid, entityValidator)=>{
|
|
|
63
75
|
const validData = await entityValidator.validateEntityCreation(contentType, data, {
|
|
64
76
|
// Note: publishedAt value will always be set when DP is disabled
|
|
65
77
|
isDraft: !params$1?.data?.publishedAt,
|
|
66
|
-
locale: params$1?.locale
|
|
78
|
+
locale: params$1?.locale,
|
|
79
|
+
strictRelations: isStrictRelationsEnabled()
|
|
67
80
|
});
|
|
68
81
|
// Component handling
|
|
69
82
|
const componentData = await components.createComponents(uid, validData);
|
|
@@ -95,7 +108,8 @@ const createEntriesService = (uid, entityValidator)=>{
|
|
|
95
108
|
const query$1 = query.transformParamsToQuery(uid, params.pickSelectionParams(restParams)); // select / populate
|
|
96
109
|
const validData = await entityValidator.validateEntityUpdate(contentType, data, {
|
|
97
110
|
isDraft: !params$1?.data?.publishedAt,
|
|
98
|
-
locale: params$1?.locale
|
|
111
|
+
locale: params$1?.locale,
|
|
112
|
+
strictRelations: isStrictRelationsEnabled()
|
|
99
113
|
}, entryToUpdate);
|
|
100
114
|
// Component handling
|
|
101
115
|
const componentData = await components.updateComponents(uid, entryToUpdate, validData);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.js","sources":["../../../src/services/document-service/entries.ts"],"sourcesContent":["import type { UID, Modules } from '@strapi/types';\nimport { async, errors } from '@strapi/utils';\nimport { assoc, omit } from 'lodash/fp';\n\nimport * as components from './components';\n\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { transformParamsToQuery } from './transform/query';\nimport { pickSelectionParams } from './params';\nimport { applyTransforms } from './attributes';\nimport { clearTransformDataRequestCache, transformData } from './transform/data';\n\nconst createEntriesService = (\n uid: UID.ContentType,\n entityValidator: Modules.EntityValidator.EntityValidator\n) => {\n const contentType = strapi.contentType(uid);\n\n async function createEntry(params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n // Validation\n if (!data) {\n throw new Error('Create requires data attribute');\n }\n\n // Check for uniqueness based on documentId and locale (if localized)\n if (data.documentId) {\n const i18nService = strapi.plugin('i18n')?.service('content-types');\n const isLocalized = i18nService?.isLocalizedContentType(contentType) ?? false;\n const hasDraftAndPublish = contentType.options?.draftAndPublish === true;\n\n const whereClause: Record<string, unknown> = { documentId: data.documentId };\n\n if (isLocalized) {\n whereClause.locale = data.locale;\n }\n\n let publishedStateDescription = '';\n\n if (hasDraftAndPublish) {\n if (data.publishedAt) {\n // Current entry is published, check for existing published entry\n whereClause.publishedAt = { $notNull: true };\n publishedStateDescription = 'published';\n } else {\n // Current entry is a draft, check for existing draft entry\n whereClause.publishedAt = { $null: true };\n publishedStateDescription = 'draft';\n }\n }\n\n const existingEntry = await strapi.db.query(uid).findOne({\n select: ['id'],\n where: whereClause,\n });\n\n if (existingEntry) {\n let errorMsg = `A ${publishedStateDescription} entry with documentId \"${data.documentId}\"`;\n if (isLocalized && data.locale) {\n errorMsg += ` and locale \"${data.locale}\"`;\n }\n errorMsg += ` already exists for UID \"${uid}\". This combination must be unique.`;\n throw new errors.ApplicationError(errorMsg);\n }\n }\n\n const validData = await entityValidator.validateEntityCreation(contentType, data, {\n // Note: publishedAt value will always be set when DP is disabled\n isDraft: !params?.data?.publishedAt,\n locale: params?.locale,\n });\n\n // Component handling\n const componentData = await components.createComponents(uid, validData);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n const doc = await strapi.db.query(uid).create({ ...query, data: entryData });\n\n return doc;\n }\n\n async function deleteEntry(id: number, query = {} as any) {\n const componentsToDelete = await components.getComponents(uid, { id });\n\n const deletedEntry = await strapi.db.query(uid).delete({ ...query, where: { id } });\n\n await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });\n\n return deletedEntry;\n }\n\n async function updateEntry(entryToUpdate: any, params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n const validData = await entityValidator.validateEntityUpdate(\n contentType,\n data,\n {\n isDraft: !params?.data?.publishedAt, // Always update the draft version\n locale: params?.locale,\n },\n entryToUpdate\n );\n // Component handling\n const componentData = await components.updateComponents(uid, entryToUpdate, validData as any);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n return strapi.db\n .query(uid)\n .update({ ...query, where: { id: entryToUpdate.id }, data: entryData });\n }\n\n async function publishEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', new Date()),\n (draft) => {\n const opts = {\n uid,\n locale: draft.locale,\n status: 'published',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(draft, opts);\n },\n // Create the published entry\n (draft) => createEntry({ ...params, data: draft, locale: draft.locale, status: 'published' })\n )(entry);\n }\n\n async function discardDraftEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', null),\n (entry) => {\n const opts = {\n uid,\n locale: entry.locale,\n status: 'draft',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(entry, opts);\n },\n // Create the draft entry\n (data) => createEntry({ ...params, locale: data.locale, data, status: 'draft' })\n )(entry);\n }\n\n return {\n create: createEntry,\n delete: deleteEntry,\n update: updateEntry,\n publish: publishEntry,\n discardDraft: discardDraftEntry,\n };\n};\n\nexport { createEntriesService };\n"],"names":["createEntriesService","uid","entityValidator","contentType","strapi","createEntry","params","data","restParams","transformParamsDocumentId","query","transformParamsToQuery","pickSelectionParams","Error","documentId","i18nService","plugin","service","isLocalized","isLocalizedContentType","hasDraftAndPublish","options","draftAndPublish","whereClause","locale","publishedStateDescription","publishedAt","$notNull","$null","existingEntry","db","findOne","select","where","errorMsg","errors","ApplicationError","validData","validateEntityCreation","isDraft","componentData","components","dataWithComponents","entryData","applyTransforms","doc","create","deleteEntry","id","componentsToDelete","deletedEntry","delete","loadComponents","updateEntry","entryToUpdate","validateEntityUpdate","update","publishEntry","entry","clearTransformDataRequestCache","async","pipe","omit","assoc","Date","draft","opts","status","allowMissingId","useRequestCache","transformData","discardDraftEntry","publish","discardDraft"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entries.js","sources":["../../../src/services/document-service/entries.ts"],"sourcesContent":["import type { UID, Modules } from '@strapi/types';\nimport { async, errors } from '@strapi/utils';\nimport { assoc, omit } from 'lodash/fp';\n\nimport * as components from './components';\n\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { transformParamsToQuery } from './transform/query';\nimport { pickSelectionParams } from './params';\nimport { applyTransforms } from './attributes';\nimport { clearTransformDataRequestCache, transformData } from './transform/data';\n\n/**\n * Reads and validates the `api.documents.strictRelations` flag.\n * false/undefined => legacy behaviour (relational required constraints not enforced),\n * true => enforce required media and relations on non-draft writes.\n * Mirrors the validation of `api.documents.strictParams` (see repository.ts).\n */\nconst isStrictRelationsEnabled = (): boolean => {\n const rawStrictRelations: unknown = strapi.config.get('api.documents.strictRelations', undefined);\n\n if (\n rawStrictRelations !== undefined &&\n rawStrictRelations !== false &&\n rawStrictRelations !== true\n ) {\n throw new errors.ValidationError(\n `Invalid config.api.documents.strictRelations value: \"${rawStrictRelations}\". Expected boolean (true or false).`\n );\n }\n\n return rawStrictRelations === true;\n};\n\nconst createEntriesService = (\n uid: UID.ContentType,\n entityValidator: Modules.EntityValidator.EntityValidator\n) => {\n const contentType = strapi.contentType(uid);\n\n async function createEntry(params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n // Validation\n if (!data) {\n throw new Error('Create requires data attribute');\n }\n\n // Check for uniqueness based on documentId and locale (if localized)\n if (data.documentId) {\n const i18nService = strapi.plugin('i18n')?.service('content-types');\n const isLocalized = i18nService?.isLocalizedContentType(contentType) ?? false;\n const hasDraftAndPublish = contentType.options?.draftAndPublish === true;\n\n const whereClause: Record<string, unknown> = { documentId: data.documentId };\n\n if (isLocalized) {\n whereClause.locale = data.locale;\n }\n\n let publishedStateDescription = '';\n\n if (hasDraftAndPublish) {\n if (data.publishedAt) {\n // Current entry is published, check for existing published entry\n whereClause.publishedAt = { $notNull: true };\n publishedStateDescription = 'published';\n } else {\n // Current entry is a draft, check for existing draft entry\n whereClause.publishedAt = { $null: true };\n publishedStateDescription = 'draft';\n }\n }\n\n const existingEntry = await strapi.db.query(uid).findOne({\n select: ['id'],\n where: whereClause,\n });\n\n if (existingEntry) {\n let errorMsg = `A ${publishedStateDescription} entry with documentId \"${data.documentId}\"`;\n if (isLocalized && data.locale) {\n errorMsg += ` and locale \"${data.locale}\"`;\n }\n errorMsg += ` already exists for UID \"${uid}\". This combination must be unique.`;\n throw new errors.ApplicationError(errorMsg);\n }\n }\n\n const validData = await entityValidator.validateEntityCreation(contentType, data, {\n // Note: publishedAt value will always be set when DP is disabled\n isDraft: !params?.data?.publishedAt,\n locale: params?.locale,\n strictRelations: isStrictRelationsEnabled(),\n });\n\n // Component handling\n const componentData = await components.createComponents(uid, validData);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n const doc = await strapi.db.query(uid).create({ ...query, data: entryData });\n\n return doc;\n }\n\n async function deleteEntry(id: number, query = {} as any) {\n const componentsToDelete = await components.getComponents(uid, { id });\n\n const deletedEntry = await strapi.db.query(uid).delete({ ...query, where: { id } });\n\n await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });\n\n return deletedEntry;\n }\n\n async function updateEntry(entryToUpdate: any, params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n const validData = await entityValidator.validateEntityUpdate(\n contentType,\n data,\n {\n isDraft: !params?.data?.publishedAt, // Always update the draft version\n locale: params?.locale,\n strictRelations: isStrictRelationsEnabled(),\n },\n entryToUpdate\n );\n // Component handling\n const componentData = await components.updateComponents(uid, entryToUpdate, validData as any);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n return strapi.db\n .query(uid)\n .update({ ...query, where: { id: entryToUpdate.id }, data: entryData });\n }\n\n async function publishEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', new Date()),\n (draft) => {\n const opts = {\n uid,\n locale: draft.locale,\n status: 'published',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(draft, opts);\n },\n // Create the published entry\n (draft) => createEntry({ ...params, data: draft, locale: draft.locale, status: 'published' })\n )(entry);\n }\n\n async function discardDraftEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', null),\n (entry) => {\n const opts = {\n uid,\n locale: entry.locale,\n status: 'draft',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(entry, opts);\n },\n // Create the draft entry\n (data) => createEntry({ ...params, locale: data.locale, data, status: 'draft' })\n )(entry);\n }\n\n return {\n create: createEntry,\n delete: deleteEntry,\n update: updateEntry,\n publish: publishEntry,\n discardDraft: discardDraftEntry,\n };\n};\n\nexport { createEntriesService };\n"],"names":["isStrictRelationsEnabled","rawStrictRelations","strapi","config","get","undefined","errors","ValidationError","createEntriesService","uid","entityValidator","contentType","createEntry","params","data","restParams","transformParamsDocumentId","query","transformParamsToQuery","pickSelectionParams","Error","documentId","i18nService","plugin","service","isLocalized","isLocalizedContentType","hasDraftAndPublish","options","draftAndPublish","whereClause","locale","publishedStateDescription","publishedAt","$notNull","$null","existingEntry","db","findOne","select","where","errorMsg","ApplicationError","validData","validateEntityCreation","isDraft","strictRelations","componentData","components","dataWithComponents","entryData","applyTransforms","doc","create","deleteEntry","id","componentsToDelete","deletedEntry","delete","loadComponents","updateEntry","entryToUpdate","validateEntityUpdate","update","publishEntry","entry","clearTransformDataRequestCache","async","pipe","omit","assoc","Date","draft","opts","status","allowMissingId","useRequestCache","transformData","discardDraftEntry","publish","discardDraft"],"mappings":"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"}
|
|
@@ -7,6 +7,18 @@ import { pickSelectionParams } from './params.mjs';
|
|
|
7
7
|
import { applyTransforms } from './attributes/index.mjs';
|
|
8
8
|
import { clearTransformDataRequestCache, transformData } from './transform/data.mjs';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Reads and validates the `api.documents.strictRelations` flag.
|
|
12
|
+
* false/undefined => legacy behaviour (relational required constraints not enforced),
|
|
13
|
+
* true => enforce required media and relations on non-draft writes.
|
|
14
|
+
* Mirrors the validation of `api.documents.strictParams` (see repository.ts).
|
|
15
|
+
*/ const isStrictRelationsEnabled = ()=>{
|
|
16
|
+
const rawStrictRelations = strapi.config.get('api.documents.strictRelations', undefined);
|
|
17
|
+
if (rawStrictRelations !== undefined && rawStrictRelations !== false && rawStrictRelations !== true) {
|
|
18
|
+
throw new errors.ValidationError(`Invalid config.api.documents.strictRelations value: "${rawStrictRelations}". Expected boolean (true or false).`);
|
|
19
|
+
}
|
|
20
|
+
return rawStrictRelations === true;
|
|
21
|
+
};
|
|
10
22
|
const createEntriesService = (uid, entityValidator)=>{
|
|
11
23
|
const contentType = strapi.contentType(uid);
|
|
12
24
|
async function createEntry(params = {}) {
|
|
@@ -61,7 +73,8 @@ const createEntriesService = (uid, entityValidator)=>{
|
|
|
61
73
|
const validData = await entityValidator.validateEntityCreation(contentType, data, {
|
|
62
74
|
// Note: publishedAt value will always be set when DP is disabled
|
|
63
75
|
isDraft: !params?.data?.publishedAt,
|
|
64
|
-
locale: params?.locale
|
|
76
|
+
locale: params?.locale,
|
|
77
|
+
strictRelations: isStrictRelationsEnabled()
|
|
65
78
|
});
|
|
66
79
|
// Component handling
|
|
67
80
|
const componentData = await createComponents(uid, validData);
|
|
@@ -93,7 +106,8 @@ const createEntriesService = (uid, entityValidator)=>{
|
|
|
93
106
|
const query = transformParamsToQuery(uid, pickSelectionParams(restParams)); // select / populate
|
|
94
107
|
const validData = await entityValidator.validateEntityUpdate(contentType, data, {
|
|
95
108
|
isDraft: !params?.data?.publishedAt,
|
|
96
|
-
locale: params?.locale
|
|
109
|
+
locale: params?.locale,
|
|
110
|
+
strictRelations: isStrictRelationsEnabled()
|
|
97
111
|
}, entryToUpdate);
|
|
98
112
|
// Component handling
|
|
99
113
|
const componentData = await updateComponents(uid, entryToUpdate, validData);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entries.mjs","sources":["../../../src/services/document-service/entries.ts"],"sourcesContent":["import type { UID, Modules } from '@strapi/types';\nimport { async, errors } from '@strapi/utils';\nimport { assoc, omit } from 'lodash/fp';\n\nimport * as components from './components';\n\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { transformParamsToQuery } from './transform/query';\nimport { pickSelectionParams } from './params';\nimport { applyTransforms } from './attributes';\nimport { clearTransformDataRequestCache, transformData } from './transform/data';\n\nconst createEntriesService = (\n uid: UID.ContentType,\n entityValidator: Modules.EntityValidator.EntityValidator\n) => {\n const contentType = strapi.contentType(uid);\n\n async function createEntry(params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n // Validation\n if (!data) {\n throw new Error('Create requires data attribute');\n }\n\n // Check for uniqueness based on documentId and locale (if localized)\n if (data.documentId) {\n const i18nService = strapi.plugin('i18n')?.service('content-types');\n const isLocalized = i18nService?.isLocalizedContentType(contentType) ?? false;\n const hasDraftAndPublish = contentType.options?.draftAndPublish === true;\n\n const whereClause: Record<string, unknown> = { documentId: data.documentId };\n\n if (isLocalized) {\n whereClause.locale = data.locale;\n }\n\n let publishedStateDescription = '';\n\n if (hasDraftAndPublish) {\n if (data.publishedAt) {\n // Current entry is published, check for existing published entry\n whereClause.publishedAt = { $notNull: true };\n publishedStateDescription = 'published';\n } else {\n // Current entry is a draft, check for existing draft entry\n whereClause.publishedAt = { $null: true };\n publishedStateDescription = 'draft';\n }\n }\n\n const existingEntry = await strapi.db.query(uid).findOne({\n select: ['id'],\n where: whereClause,\n });\n\n if (existingEntry) {\n let errorMsg = `A ${publishedStateDescription} entry with documentId \"${data.documentId}\"`;\n if (isLocalized && data.locale) {\n errorMsg += ` and locale \"${data.locale}\"`;\n }\n errorMsg += ` already exists for UID \"${uid}\". This combination must be unique.`;\n throw new errors.ApplicationError(errorMsg);\n }\n }\n\n const validData = await entityValidator.validateEntityCreation(contentType, data, {\n // Note: publishedAt value will always be set when DP is disabled\n isDraft: !params?.data?.publishedAt,\n locale: params?.locale,\n });\n\n // Component handling\n const componentData = await components.createComponents(uid, validData);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n const doc = await strapi.db.query(uid).create({ ...query, data: entryData });\n\n return doc;\n }\n\n async function deleteEntry(id: number, query = {} as any) {\n const componentsToDelete = await components.getComponents(uid, { id });\n\n const deletedEntry = await strapi.db.query(uid).delete({ ...query, where: { id } });\n\n await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });\n\n return deletedEntry;\n }\n\n async function updateEntry(entryToUpdate: any, params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n const validData = await entityValidator.validateEntityUpdate(\n contentType,\n data,\n {\n isDraft: !params?.data?.publishedAt, // Always update the draft version\n locale: params?.locale,\n },\n entryToUpdate\n );\n // Component handling\n const componentData = await components.updateComponents(uid, entryToUpdate, validData as any);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n return strapi.db\n .query(uid)\n .update({ ...query, where: { id: entryToUpdate.id }, data: entryData });\n }\n\n async function publishEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', new Date()),\n (draft) => {\n const opts = {\n uid,\n locale: draft.locale,\n status: 'published',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(draft, opts);\n },\n // Create the published entry\n (draft) => createEntry({ ...params, data: draft, locale: draft.locale, status: 'published' })\n )(entry);\n }\n\n async function discardDraftEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', null),\n (entry) => {\n const opts = {\n uid,\n locale: entry.locale,\n status: 'draft',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(entry, opts);\n },\n // Create the draft entry\n (data) => createEntry({ ...params, locale: data.locale, data, status: 'draft' })\n )(entry);\n }\n\n return {\n create: createEntry,\n delete: deleteEntry,\n update: updateEntry,\n publish: publishEntry,\n discardDraft: discardDraftEntry,\n };\n};\n\nexport { createEntriesService };\n"],"names":["createEntriesService","uid","entityValidator","contentType","strapi","createEntry","params","data","restParams","transformParamsDocumentId","query","transformParamsToQuery","pickSelectionParams","Error","documentId","i18nService","plugin","service","isLocalized","isLocalizedContentType","hasDraftAndPublish","options","draftAndPublish","whereClause","locale","publishedStateDescription","publishedAt","$notNull","$null","existingEntry","db","findOne","select","where","errorMsg","errors","ApplicationError","validData","validateEntityCreation","isDraft","componentData","components","dataWithComponents","entryData","applyTransforms","doc","create","deleteEntry","id","componentsToDelete","deletedEntry","delete","loadComponents","updateEntry","entryToUpdate","validateEntityUpdate","update","publishEntry","entry","clearTransformDataRequestCache","async","pipe","omit","assoc","Date","draft","opts","status","allowMissingId","useRequestCache","transformData","discardDraftEntry","publish","discardDraft"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entries.mjs","sources":["../../../src/services/document-service/entries.ts"],"sourcesContent":["import type { UID, Modules } from '@strapi/types';\nimport { async, errors } from '@strapi/utils';\nimport { assoc, omit } from 'lodash/fp';\n\nimport * as components from './components';\n\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { transformParamsToQuery } from './transform/query';\nimport { pickSelectionParams } from './params';\nimport { applyTransforms } from './attributes';\nimport { clearTransformDataRequestCache, transformData } from './transform/data';\n\n/**\n * Reads and validates the `api.documents.strictRelations` flag.\n * false/undefined => legacy behaviour (relational required constraints not enforced),\n * true => enforce required media and relations on non-draft writes.\n * Mirrors the validation of `api.documents.strictParams` (see repository.ts).\n */\nconst isStrictRelationsEnabled = (): boolean => {\n const rawStrictRelations: unknown = strapi.config.get('api.documents.strictRelations', undefined);\n\n if (\n rawStrictRelations !== undefined &&\n rawStrictRelations !== false &&\n rawStrictRelations !== true\n ) {\n throw new errors.ValidationError(\n `Invalid config.api.documents.strictRelations value: \"${rawStrictRelations}\". Expected boolean (true or false).`\n );\n }\n\n return rawStrictRelations === true;\n};\n\nconst createEntriesService = (\n uid: UID.ContentType,\n entityValidator: Modules.EntityValidator.EntityValidator\n) => {\n const contentType = strapi.contentType(uid);\n\n async function createEntry(params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n // Validation\n if (!data) {\n throw new Error('Create requires data attribute');\n }\n\n // Check for uniqueness based on documentId and locale (if localized)\n if (data.documentId) {\n const i18nService = strapi.plugin('i18n')?.service('content-types');\n const isLocalized = i18nService?.isLocalizedContentType(contentType) ?? false;\n const hasDraftAndPublish = contentType.options?.draftAndPublish === true;\n\n const whereClause: Record<string, unknown> = { documentId: data.documentId };\n\n if (isLocalized) {\n whereClause.locale = data.locale;\n }\n\n let publishedStateDescription = '';\n\n if (hasDraftAndPublish) {\n if (data.publishedAt) {\n // Current entry is published, check for existing published entry\n whereClause.publishedAt = { $notNull: true };\n publishedStateDescription = 'published';\n } else {\n // Current entry is a draft, check for existing draft entry\n whereClause.publishedAt = { $null: true };\n publishedStateDescription = 'draft';\n }\n }\n\n const existingEntry = await strapi.db.query(uid).findOne({\n select: ['id'],\n where: whereClause,\n });\n\n if (existingEntry) {\n let errorMsg = `A ${publishedStateDescription} entry with documentId \"${data.documentId}\"`;\n if (isLocalized && data.locale) {\n errorMsg += ` and locale \"${data.locale}\"`;\n }\n errorMsg += ` already exists for UID \"${uid}\". This combination must be unique.`;\n throw new errors.ApplicationError(errorMsg);\n }\n }\n\n const validData = await entityValidator.validateEntityCreation(contentType, data, {\n // Note: publishedAt value will always be set when DP is disabled\n isDraft: !params?.data?.publishedAt,\n locale: params?.locale,\n strictRelations: isStrictRelationsEnabled(),\n });\n\n // Component handling\n const componentData = await components.createComponents(uid, validData);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n const doc = await strapi.db.query(uid).create({ ...query, data: entryData });\n\n return doc;\n }\n\n async function deleteEntry(id: number, query = {} as any) {\n const componentsToDelete = await components.getComponents(uid, { id });\n\n const deletedEntry = await strapi.db.query(uid).delete({ ...query, where: { id } });\n\n await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });\n\n return deletedEntry;\n }\n\n async function updateEntry(entryToUpdate: any, params = {} as any) {\n const { data, ...restParams } = await transformParamsDocumentId(uid, params);\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate\n\n const validData = await entityValidator.validateEntityUpdate(\n contentType,\n data,\n {\n isDraft: !params?.data?.publishedAt, // Always update the draft version\n locale: params?.locale,\n strictRelations: isStrictRelationsEnabled(),\n },\n entryToUpdate\n );\n // Component handling\n const componentData = await components.updateComponents(uid, entryToUpdate, validData as any);\n const dataWithComponents = components.assignComponentData(\n contentType,\n componentData,\n validData\n );\n\n const entryData = applyTransforms(contentType, dataWithComponents);\n\n return strapi.db\n .query(uid)\n .update({ ...query, where: { id: entryToUpdate.id }, data: entryData });\n }\n\n async function publishEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', new Date()),\n (draft) => {\n const opts = {\n uid,\n locale: draft.locale,\n status: 'published',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(draft, opts);\n },\n // Create the published entry\n (draft) => createEntry({ ...params, data: draft, locale: draft.locale, status: 'published' })\n )(entry);\n }\n\n async function discardDraftEntry(entry: any, params = {} as any) {\n clearTransformDataRequestCache();\n\n return async.pipe(\n omit('id'),\n assoc('publishedAt', null),\n (entry) => {\n const opts = {\n uid,\n locale: entry.locale,\n status: 'draft',\n allowMissingId: true,\n useRequestCache: false,\n };\n return transformData(entry, opts);\n },\n // Create the draft entry\n (data) => createEntry({ ...params, locale: data.locale, data, status: 'draft' })\n )(entry);\n }\n\n return {\n create: createEntry,\n delete: deleteEntry,\n update: updateEntry,\n publish: publishEntry,\n discardDraft: discardDraftEntry,\n };\n};\n\nexport { createEntriesService };\n"],"names":["isStrictRelationsEnabled","rawStrictRelations","strapi","config","get","undefined","errors","ValidationError","createEntriesService","uid","entityValidator","contentType","createEntry","params","data","restParams","transformParamsDocumentId","query","transformParamsToQuery","pickSelectionParams","Error","documentId","i18nService","plugin","service","isLocalized","isLocalizedContentType","hasDraftAndPublish","options","draftAndPublish","whereClause","locale","publishedStateDescription","publishedAt","$notNull","$null","existingEntry","db","findOne","select","where","errorMsg","ApplicationError","validData","validateEntityCreation","isDraft","strictRelations","componentData","components","dataWithComponents","entryData","applyTransforms","doc","create","deleteEntry","id","componentsToDelete","deletedEntry","delete","loadComponents","updateEntry","entryToUpdate","validateEntityUpdate","update","publishEntry","entry","clearTransformDataRequestCache","async","pipe","omit","assoc","Date","draft","opts","status","allowMissingId","useRequestCache","transformData","discardDraftEntry","publish","discardDraft"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/entity-validator/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAO,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/entity-validator/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAO,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAclE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE;QAEb,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;QAErB,EAAE,CAAC,EAAE,MAAM,CAAC;QAGZ,OAAO,CAAC,EAAE,gBAAgB,CAAC;KAC5B,CAAC;IAEF,eAAe,EAAE,MAAM,EAAE,CAAC;IAG1B,cAAc,EAAE,OAAO,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;IACjD,sBAAsB,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;CAC/E,CAAC;AAWF,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA0tBD,QAAA,MAAM,eAAe,EAAE,OAAO,CAAC,eAAe,CAAC,eAG9C,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -13,6 +13,7 @@ var strapiUtils__default = /*#__PURE__*/_interopDefault(strapiUtils);
|
|
|
13
13
|
|
|
14
14
|
const { yup, validateYupSchema } = strapiUtils__default.default;
|
|
15
15
|
const { isMediaAttribute, isScalarAttribute, getWritableAttributes } = strapiUtils__default.default.contentTypes;
|
|
16
|
+
const { isAnyToOne } = strapiUtils__default.default.relations;
|
|
16
17
|
const { ValidationError } = strapiUtils__default.default.errors;
|
|
17
18
|
const isInteger = (value)=>Number.isInteger(value);
|
|
18
19
|
const addMinMax = (validator, { attr, updatedAttribute })=>{
|
|
@@ -56,7 +57,7 @@ const addDefault = (createOrUpdate)=>{
|
|
|
56
57
|
};
|
|
57
58
|
};
|
|
58
59
|
const preventCast = (validator)=>validator.transform((val, originalVal)=>originalVal);
|
|
59
|
-
const createComponentValidator = (createOrUpdate)=>({ attr, updatedAttribute, componentContext },
|
|
60
|
+
const createComponentValidator = (createOrUpdate)=>({ attr, updatedAttribute, componentContext }, options)=>{
|
|
60
61
|
const model = strapi.getModel(attr.component);
|
|
61
62
|
if (!model) {
|
|
62
63
|
throw new Error('Validation failed: Model not found');
|
|
@@ -67,16 +68,14 @@ const createComponentValidator = (createOrUpdate)=>({ attr, updatedAttribute, co
|
|
|
67
68
|
componentContext,
|
|
68
69
|
model,
|
|
69
70
|
data: item
|
|
70
|
-
},
|
|
71
|
-
isDraft
|
|
72
|
-
}).notNull()));
|
|
71
|
+
}, options).notNull()));
|
|
73
72
|
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
74
73
|
attr: {
|
|
75
74
|
required: true
|
|
76
75
|
},
|
|
77
76
|
updatedAttribute
|
|
78
77
|
});
|
|
79
|
-
if (!isDraft) {
|
|
78
|
+
if (!options.isDraft) {
|
|
80
79
|
validator = addMinMax(validator, {
|
|
81
80
|
attr,
|
|
82
81
|
updatedAttribute
|
|
@@ -88,18 +87,16 @@ const createComponentValidator = (createOrUpdate)=>({ attr, updatedAttribute, co
|
|
|
88
87
|
model,
|
|
89
88
|
data: updatedAttribute.value,
|
|
90
89
|
componentContext
|
|
91
|
-
},
|
|
92
|
-
isDraft
|
|
93
|
-
});
|
|
90
|
+
}, options);
|
|
94
91
|
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
95
92
|
attr: {
|
|
96
|
-
required: !isDraft && attr.required
|
|
93
|
+
required: !options.isDraft && attr.required
|
|
97
94
|
},
|
|
98
95
|
updatedAttribute
|
|
99
96
|
});
|
|
100
97
|
return validator;
|
|
101
98
|
};
|
|
102
|
-
const createDzValidator = (createOrUpdate)=>({ attr, updatedAttribute, componentContext },
|
|
99
|
+
const createDzValidator = (createOrUpdate)=>({ attr, updatedAttribute, componentContext }, options)=>{
|
|
103
100
|
let validator;
|
|
104
101
|
validator = yup.array().of(yup.lazy((item)=>{
|
|
105
102
|
const model = strapi.getModel(fp.prop('__component', item));
|
|
@@ -110,9 +107,7 @@ const createDzValidator = (createOrUpdate)=>({ attr, updatedAttribute, component
|
|
|
110
107
|
model,
|
|
111
108
|
data: item,
|
|
112
109
|
componentContext
|
|
113
|
-
},
|
|
114
|
-
isDraft
|
|
115
|
-
})) : schema;
|
|
110
|
+
}, options)) : schema;
|
|
116
111
|
}));
|
|
117
112
|
validator = addRequiredValidation(createOrUpdate)(validator, {
|
|
118
113
|
attr: {
|
|
@@ -120,7 +115,7 @@ const createDzValidator = (createOrUpdate)=>({ attr, updatedAttribute, component
|
|
|
120
115
|
},
|
|
121
116
|
updatedAttribute
|
|
122
117
|
});
|
|
123
|
-
if (!isDraft) {
|
|
118
|
+
if (!options.isDraft) {
|
|
124
119
|
validator = addMinMax(validator, {
|
|
125
120
|
attr,
|
|
126
121
|
updatedAttribute
|
|
@@ -128,15 +123,143 @@ const createDzValidator = (createOrUpdate)=>({ attr, updatedAttribute, component
|
|
|
128
123
|
}
|
|
129
124
|
return validator;
|
|
130
125
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
/**
|
|
127
|
+
* A relation/media value can be supplied in several shapes: a bare id, an array of ids,
|
|
128
|
+
* or a connect/set object (`{ connect: [...] }` / `{ set: [...] }`). This normalises all
|
|
129
|
+
* of them to "does this attach at least one entry?" so required validation is consistent
|
|
130
|
+
* regardless of the input shape (mirrors `buildRelationsStore`'s source extraction).
|
|
131
|
+
*/ const hasRelationValue = (value)=>{
|
|
132
|
+
if (_.isNil(value)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (Array.isArray(value)) {
|
|
136
|
+
return value.length > 0;
|
|
137
|
+
}
|
|
138
|
+
if (fp.isObject(value)) {
|
|
139
|
+
const connect = value.connect;
|
|
140
|
+
const set = value.set;
|
|
141
|
+
if (!_.isNil(connect)) {
|
|
142
|
+
return Array.isArray(connect) ? connect.length > 0 : true;
|
|
143
|
+
}
|
|
144
|
+
if (!_.isNil(set)) {
|
|
145
|
+
return Array.isArray(set) ? set.length > 0 : true;
|
|
146
|
+
}
|
|
147
|
+
// Any other object shape (e.g. a bare `{ id }`) counts as a value.
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* A disconnect-only update payload removes entries without adding or replacing any:
|
|
154
|
+
* actual removals in `disconnect`, no `set`, and no effective additions in `connect`.
|
|
155
|
+
* `connect` counts as "no additions" when absent OR an empty array — the Content Manager
|
|
156
|
+
* initializes every relation as `{ connect: [], disconnect: [] }` and keeps `connect: []`
|
|
157
|
+
* in place when the user only removes entries, so `{ connect: [], disconnect: [id] }`
|
|
158
|
+
* is the shape real admin saves produce. A payload with empty `disconnect` (nothing
|
|
159
|
+
* removed) is NOT disconnect-only — it's the CM's untouched-relation no-op.
|
|
160
|
+
*/ const isDisconnectOnly = (value)=>{
|
|
161
|
+
if (!fp.isObject(value)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
const { connect, set, disconnect } = value;
|
|
165
|
+
if (!_.isNil(set)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const hasAdditions = !_.isNil(connect) && (!Array.isArray(connect) || connect.length > 0);
|
|
169
|
+
if (hasAdditions) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
return !_.isNil(disconnect) && (!Array.isArray(disconnect) || disconnect.length > 0);
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Decides whether a required media/relation value should be rejected as empty,
|
|
176
|
+
* mirroring the scalar `required` semantics:
|
|
177
|
+
*
|
|
178
|
+
* - creation (`notNil` analogue): an absent key is a failure — the field must be
|
|
179
|
+
* populated, so anything without a value (`undefined`/`null`/`[]`/empty `set`/`connect`)
|
|
180
|
+
* is rejected.
|
|
181
|
+
* - update (`notNull` analogue): an absent key keeps the existing value, so it passes.
|
|
182
|
+
* Only reject when the request is present AND leaves the field empty. A bare
|
|
183
|
+
* `{ connect: [] }` (no `set`) neither adds nor removes anything → treated as a no-op
|
|
184
|
+
* that passes; `{ set: [] }` / `null` / `[]` explicitly empty the field → rejected.
|
|
185
|
+
*
|
|
186
|
+
* `isToOne` marks a to-one relation / single media, which can hold at most one entry.
|
|
187
|
+
* For those, a disconnect-only update (`{ disconnect: [...] }` with no `connect`/`set`)
|
|
188
|
+
* always leaves the field empty — no DB read needed — so it is rejected on non-draft
|
|
189
|
+
* updates. To-many fields can still hold other entries after a disconnect, so their
|
|
190
|
+
* resulting state can't be known without a DB read and they fall through to a pass
|
|
191
|
+
* (publish re-validates the populated draft for D&P types; documented limitation for
|
|
192
|
+
* non-D&P, tied to the null→[] follow-up).
|
|
193
|
+
*
|
|
194
|
+
* On creation there are no existing rows, so a disconnect-only payload attaches nothing
|
|
195
|
+
* and always leaves the field empty — for both to-one and to-many — so it is rejected
|
|
196
|
+
* regardless of `isToOne`.
|
|
197
|
+
*/ const relationRequiredFails = (createOrUpdate, value, isToOne)=>{
|
|
198
|
+
if (createOrUpdate === 'creation') {
|
|
199
|
+
// No existing rows on create, so a disconnect attaches nothing and the field stays
|
|
200
|
+
// empty for both to-one and to-many — reject it before the generic value check, which
|
|
201
|
+
// would otherwise treat the bare `{ disconnect: [...] }` object as a present value.
|
|
202
|
+
if (isDisconnectOnly(value)) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (createOrUpdate === 'update') {
|
|
207
|
+
// Absent key on update = keep the existing value.
|
|
208
|
+
if (value === undefined) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
if (isDisconnectOnly(value)) {
|
|
212
|
+
// A disconnect on a to-one/single field deterministically empties it; on a to-many
|
|
213
|
+
// field the resulting state depends on the current DB rows, so we can't reject here.
|
|
214
|
+
return isToOne;
|
|
215
|
+
}
|
|
216
|
+
// A connect-only empty is a no-op, not an emptying operation.
|
|
217
|
+
if (fp.isObject(value) && !_.isNil(value.connect)) {
|
|
218
|
+
const connect = value.connect;
|
|
219
|
+
const hasSet = !_.isNil(value.set);
|
|
220
|
+
if (!hasSet && Array.isArray(connect) && connect.length === 0) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
137
224
|
}
|
|
138
|
-
return
|
|
225
|
+
return !hasRelationValue(value);
|
|
139
226
|
};
|
|
227
|
+
const createMediaAttributeValidator = (createOrUpdate)=>({ attr, updatedAttribute }, options)=>{
|
|
228
|
+
// Media values arrive in several shapes (a bare id, an array of ids, or a
|
|
229
|
+
// `{ connect }` / `{ set }` object on update). `yup.mixed()` accepts all of them;
|
|
230
|
+
// coercing `multiple` media to `yup.array()` would reject the connect/set object
|
|
231
|
+
// syntax that update requests legitimately send. Required-ness is asserted below
|
|
232
|
+
// via `relationRequiredFails`, which understands every shape.
|
|
233
|
+
let validator = yup.mixed();
|
|
234
|
+
// Relational required constraints are only enforced under the strictRelations flag,
|
|
235
|
+
// and never for drafts (mirrors scalar `required` handling via `!isDraft`).
|
|
236
|
+
if (options.strictRelations && !options.isDraft && attr.required) {
|
|
237
|
+
// A media value can arrive as an id, an array, or a connect/set object, so a simple
|
|
238
|
+
// `.notNil()`/`.min()` is not enough — normalise the shape before asserting.
|
|
239
|
+
// Single media holds at most one file, so a disconnect-only update always empties it.
|
|
240
|
+
const isToOne = !attr.multiple;
|
|
241
|
+
validator = validator.test('required-media', `${updatedAttribute.name} must be defined.`, ()=>!relationRequiredFails(createOrUpdate, updatedAttribute.value, isToOne));
|
|
242
|
+
}
|
|
243
|
+
return validator;
|
|
244
|
+
};
|
|
245
|
+
const createRelationValidator = (createOrUpdate)=>({ attr, updatedAttribute }, options)=>{
|
|
246
|
+
let validator;
|
|
247
|
+
if (Array.isArray(updatedAttribute.value)) {
|
|
248
|
+
validator = yup.array().of(yup.mixed());
|
|
249
|
+
} else {
|
|
250
|
+
validator = yup.mixed();
|
|
251
|
+
}
|
|
252
|
+
// Relational required constraints are only enforced under the strictRelations flag,
|
|
253
|
+
// and never for drafts (mirrors scalar `required` handling via `!isDraft`).
|
|
254
|
+
if (options.strictRelations && !options.isDraft && attr.required) {
|
|
255
|
+
// A relation value can arrive as an id, an array, or a connect/set object, so a
|
|
256
|
+
// simple `.notNil()`/`.min()` is not enough — normalise the shape before asserting.
|
|
257
|
+
// A to-one relation holds at most one target, so a disconnect-only update always empties it.
|
|
258
|
+
const isToOne = isAnyToOne(attr);
|
|
259
|
+
validator = validator.test('required-relation', `${updatedAttribute.name} must be defined.`, ()=>!relationRequiredFails(createOrUpdate, updatedAttribute.value, isToOne));
|
|
260
|
+
}
|
|
261
|
+
return validator;
|
|
262
|
+
};
|
|
140
263
|
const createScalarAttributeValidator = (createOrUpdate)=>(metas, options)=>{
|
|
141
264
|
let validator;
|
|
142
265
|
if (fp.has(metas.attr.type, validators.Validators)) {
|
|
@@ -163,7 +286,10 @@ const createAttributeValidator = (createOrUpdate)=>(metas, options)=>{
|
|
|
163
286
|
}
|
|
164
287
|
}
|
|
165
288
|
if (isMediaAttribute(metas.attr)) {
|
|
166
|
-
validator =
|
|
289
|
+
validator = createMediaAttributeValidator(createOrUpdate)({
|
|
290
|
+
attr: metas.attr,
|
|
291
|
+
updatedAttribute: metas.updatedAttribute
|
|
292
|
+
}, options);
|
|
167
293
|
} else if (isScalarAttribute(metas.attr)) {
|
|
168
294
|
validator = createScalarAttributeValidator(createOrUpdate)(metas, options);
|
|
169
295
|
} else {
|
|
@@ -204,10 +330,10 @@ const createAttributeValidator = (createOrUpdate)=>(metas, options)=>{
|
|
|
204
330
|
});
|
|
205
331
|
validator = createDzValidator(createOrUpdate)(metas, options);
|
|
206
332
|
} else if (metas.attr.type === 'relation') {
|
|
207
|
-
validator = createRelationValidator({
|
|
333
|
+
validator = createRelationValidator(createOrUpdate)({
|
|
208
334
|
attr: metas.attr,
|
|
209
335
|
updatedAttribute: metas.updatedAttribute
|
|
210
|
-
});
|
|
336
|
+
}, options);
|
|
211
337
|
}
|
|
212
338
|
validator = preventCast(validator);
|
|
213
339
|
}
|
|
@@ -258,7 +384,8 @@ const createValidateEntity = (createOrUpdate)=>{
|
|
|
258
384
|
}
|
|
259
385
|
}, {
|
|
260
386
|
isDraft: options?.isDraft ?? false,
|
|
261
|
-
locale: options?.locale ?? null
|
|
387
|
+
locale: options?.locale ?? null,
|
|
388
|
+
strictRelations: options?.strictRelations ?? false
|
|
262
389
|
}).test('relations-test', 'check that all relations exist', async function relationsValidation(data) {
|
|
263
390
|
try {
|
|
264
391
|
await checkRelationsExist(buildRelationsStore({
|