@strapi/content-manager 5.61.1 → 5.62.0
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/admin/components/ConfigurationForm/Fields.js +1 -1
- package/dist/admin/components/ConfigurationForm/Fields.js.map +1 -1
- package/dist/admin/components/ConfigurationForm/Fields.mjs +3 -3
- package/dist/admin/components/ConfigurationForm/Fields.mjs.map +1 -1
- package/dist/admin/features/I18nSharedFieldsLock.js +54 -0
- package/dist/admin/features/I18nSharedFieldsLock.js.map +1 -0
- package/dist/admin/features/I18nSharedFieldsLock.mjs +31 -0
- package/dist/admin/features/I18nSharedFieldsLock.mjs.map +1 -0
- package/dist/admin/history/components/VersionInputRenderer.js +7 -2
- package/dist/admin/history/components/VersionInputRenderer.js.map +1 -1
- package/dist/admin/history/components/VersionInputRenderer.mjs +7 -3
- package/dist/admin/history/components/VersionInputRenderer.mjs.map +1 -1
- package/dist/admin/hooks/useContentManagerInitData.js +27 -8
- package/dist/admin/hooks/useContentManagerInitData.js.map +1 -1
- package/dist/admin/hooks/useContentManagerInitData.mjs +29 -10
- package/dist/admin/hooks/useContentManagerInitData.mjs.map +1 -1
- package/dist/admin/hooks/useDocument.js +11 -13
- package/dist/admin/hooks/useDocument.js.map +1 -1
- package/dist/admin/hooks/useDocument.mjs +11 -13
- package/dist/admin/hooks/useDocument.mjs.map +1 -1
- package/dist/admin/hooks/useI18nFieldLock.js +169 -0
- package/dist/admin/hooks/useI18nFieldLock.js.map +1 -0
- package/dist/admin/hooks/useI18nFieldLock.mjs +140 -0
- package/dist/admin/hooks/useI18nFieldLock.mjs.map +1 -0
- package/dist/admin/hooks/usePersistentQueryParams.js +16 -3
- package/dist/admin/hooks/usePersistentQueryParams.js.map +1 -1
- package/dist/admin/hooks/usePersistentQueryParams.mjs +16 -3
- package/dist/admin/hooks/usePersistentQueryParams.mjs.map +1 -1
- package/dist/admin/index.js +5 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -0
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/modules/app.js +8 -1
- package/dist/admin/modules/app.js.map +1 -1
- package/dist/admin/modules/app.mjs +8 -2
- package/dist/admin/modules/app.mjs.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.js +129 -127
- package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.mjs +129 -127
- package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.js +11 -4
- package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.mjs +12 -5
- package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js +31 -21
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs +32 -22
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/AddComponentMenu.js +98 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/AddComponentMenu.js.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/AddComponentMenu.mjs +96 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/AddComponentMenu.mjs.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/ComponentCopyModal.js +1103 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/ComponentCopyModal.js.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/ComponentCopyModal.mjs +1077 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/ComponentCopyModal.mjs.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/CopiedComponents.js +211 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/CopiedComponents.js.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/CopiedComponents.mjs +183 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/CopiedComponents.mjs.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/Initializer.js +84 -41
- package/dist/admin/pages/EditView/components/FormInputs/Component/Initializer.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Initializer.mjs +86 -43
- package/dist/admin/pages/EditView/components/FormInputs/Component/Initializer.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.js +86 -20
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.mjs +89 -23
- package/dist/admin/pages/EditView/components/FormInputs/Component/Input.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js +5 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs +5 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js +142 -22
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs +143 -23
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/utils/componentCopy.js +402 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/utils/componentCopy.js.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/utils/componentCopy.mjs +389 -0
- package/dist/admin/pages/EditView/components/FormInputs/Component/utils/componentCopy.mjs.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js +84 -33
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs +85 -34
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.js +5 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.mjs +5 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +17 -4
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +18 -5
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js +54 -6
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs +54 -6
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +11 -9
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +12 -10
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +9 -4
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +9 -4
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.js +66 -63
- package/dist/admin/pages/EditView/components/FormLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.mjs +66 -63
- package/dist/admin/pages/EditView/components/FormLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js +7 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs +7 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
- package/dist/admin/pages/EditView/utils/data.js +14 -9
- package/dist/admin/pages/EditView/utils/data.js.map +1 -1
- package/dist/admin/pages/EditView/utils/data.mjs +14 -9
- package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
- package/dist/admin/pages/EditView/utils/forms.js +34 -0
- package/dist/admin/pages/EditView/utils/forms.js.map +1 -1
- package/dist/admin/pages/EditView/utils/forms.mjs +34 -1
- package/dist/admin/pages/EditView/utils/forms.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/DraggableCard.js +2 -1
- package/dist/admin/pages/ListConfiguration/components/DraggableCard.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/DraggableCard.mjs +2 -1
- package/dist/admin/pages/ListConfiguration/components/DraggableCard.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/EditFieldForm.js +7 -6
- package/dist/admin/pages/ListConfiguration/components/EditFieldForm.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/EditFieldForm.mjs +7 -6
- package/dist/admin/pages/ListConfiguration/components/EditFieldForm.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +11 -2
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +13 -4
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.js +15 -5
- package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.mjs +16 -7
- package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
- package/dist/admin/preview/components/InputPopover.js +18 -8
- package/dist/admin/preview/components/InputPopover.js.map +1 -1
- package/dist/admin/preview/components/InputPopover.mjs +19 -9
- package/dist/admin/preview/components/InputPopover.mjs.map +1 -1
- package/dist/admin/preview/pages/Preview.js +5 -16
- package/dist/admin/preview/pages/Preview.js.map +1 -1
- package/dist/admin/preview/pages/Preview.mjs +5 -16
- package/dist/admin/preview/pages/Preview.mjs.map +1 -1
- package/dist/admin/preview/utils/fieldUtils.js +2 -0
- package/dist/admin/preview/utils/fieldUtils.js.map +1 -1
- package/dist/admin/preview/utils/fieldUtils.mjs +2 -1
- package/dist/admin/preview/utils/fieldUtils.mjs.map +1 -1
- package/dist/admin/services/api.js +2 -1
- package/dist/admin/services/api.js.map +1 -1
- package/dist/admin/services/api.mjs +2 -1
- package/dist/admin/services/api.mjs.map +1 -1
- package/dist/admin/services/documents.js +21 -1
- package/dist/admin/services/documents.js.map +1 -1
- package/dist/admin/services/documents.mjs +21 -2
- package/dist/admin/services/documents.mjs.map +1 -1
- package/dist/admin/services/relations.js +47 -1
- package/dist/admin/services/relations.js.map +1 -1
- package/dist/admin/services/relations.mjs +47 -2
- package/dist/admin/services/relations.mjs.map +1 -1
- package/dist/admin/src/exports.d.ts +2 -0
- package/dist/admin/src/features/I18nSharedFieldsLock.d.ts +22 -0
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +7 -1
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useI18nFieldLock.d.ts +61 -0
- package/dist/admin/src/modules/app.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/AddComponentMenu.d.ts +15 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/ComponentCopyModal.d.ts +58 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/CopiedComponents.d.ts +41 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Initializer.d.ts +7 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/NonRepeatable.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Repeatable.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/utils/componentCopy.d.ts +115 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +6 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentPicker.d.ts +2 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +5 -1
- package/dist/admin/src/pages/EditView/utils/forms.d.ts +13 -2
- package/dist/admin/src/pages/ListView/components/Filters.d.ts +12 -3
- package/dist/admin/src/preview/services/preview.d.ts +1 -1
- package/dist/admin/src/preview/utils/fieldUtils.d.ts +1 -0
- 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 +25 -21
- package/dist/admin/src/services/homepage.d.ts +1 -1
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +5 -3
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/translations/en.json.js +41 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +41 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/controllers/relations.js +4 -2
- package/dist/server/controllers/relations.js.map +1 -1
- package/dist/server/controllers/relations.mjs +4 -2
- package/dist/server/controllers/relations.mjs.map +1 -1
- package/dist/server/controllers/utils/metadata.js +3 -1
- package/dist/server/controllers/utils/metadata.js.map +1 -1
- package/dist/server/controllers/utils/metadata.mjs +3 -1
- package/dist/server/controllers/utils/metadata.mjs.map +1 -1
- package/dist/server/history/services/utils.js +3 -1
- package/dist/server/history/services/utils.js.map +1 -1
- package/dist/server/history/services/utils.mjs +3 -1
- package/dist/server/history/services/utils.mjs.map +1 -1
- package/dist/server/homepage/services/homepage-query-utils.js +14 -0
- package/dist/server/homepage/services/homepage-query-utils.js.map +1 -1
- package/dist/server/homepage/services/homepage-query-utils.mjs +14 -1
- package/dist/server/homepage/services/homepage-query-utils.mjs.map +1 -1
- package/dist/server/homepage/services/homepage.js +1 -1
- package/dist/server/homepage/services/homepage.js.map +1 -1
- package/dist/server/homepage/services/homepage.mjs +2 -2
- package/dist/server/homepage/services/homepage.mjs.map +1 -1
- package/dist/server/mcp/sanitizers/shape-relations.js +1 -3
- package/dist/server/mcp/sanitizers/shape-relations.js.map +1 -1
- package/dist/server/mcp/sanitizers/shape-relations.mjs +1 -3
- package/dist/server/mcp/sanitizers/shape-relations.mjs.map +1 -1
- package/dist/server/mcp/schemas/output-schemas.js +2 -1
- package/dist/server/mcp/schemas/output-schemas.js.map +1 -1
- package/dist/server/mcp/schemas/output-schemas.mjs +2 -1
- package/dist/server/mcp/schemas/output-schemas.mjs.map +1 -1
- package/dist/server/services/document-manager.js +3 -2
- package/dist/server/services/document-manager.js.map +1 -1
- package/dist/server/services/document-manager.mjs +3 -2
- package/dist/server/services/document-manager.mjs.map +1 -1
- package/dist/server/services/document-metadata.js +92 -4
- package/dist/server/services/document-metadata.js.map +1 -1
- package/dist/server/services/document-metadata.mjs +92 -4
- package/dist/server/services/document-metadata.mjs.map +1 -1
- package/dist/server/services/permission-checker.js +20 -8
- package/dist/server/services/permission-checker.js.map +1 -1
- package/dist/server/services/permission-checker.mjs +20 -8
- package/dist/server/services/permission-checker.mjs.map +1 -1
- package/dist/server/services/uid.js +2 -1
- package/dist/server/services/uid.js.map +1 -1
- package/dist/server/services/uid.mjs +2 -1
- package/dist/server/services/uid.mjs.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +1 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/homepage/services/homepage-query-utils.d.ts +6 -0
- package/dist/server/src/homepage/services/homepage-query-utils.d.ts.map +1 -1
- package/dist/server/src/homepage/services/homepage.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +21 -7
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/sanitizers/shape-relations.d.ts.map +1 -1
- package/dist/server/src/mcp/schemas/output-schemas.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 +5 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +21 -7
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts +6 -5
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/uid.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +7 -0
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/single-types.d.ts +4 -0
- package/dist/shared/contracts/single-types.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-metadata.js","sources":["../../../server/src/services/document-metadata.ts"],"sourcesContent":["import { groupBy, pick } from 'lodash';\n\nimport { async, contentTypes } from '@strapi/utils';\nimport type { Core, UID, Modules } from '@strapi/types';\n\nimport type { DocumentMetadata } from '../../../shared/contracts/collection-types';\n\nconst { getScalarAttributes, getMediaAttributes } = contentTypes;\n\nexport interface DocumentVersion {\n id: string | number;\n documentId: Modules.Documents.ID;\n locale?: string;\n localizations?: DocumentVersion[];\n updatedAt?: string | null | Date;\n publishedAt?: string | null | Date;\n}\n\n// Scalar fields that can be used in a DB `select`\nconst AVAILABLE_STATUS_SCALAR_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n// Relation populate shared by both the fast path and the full path\nconst AVAILABLE_STATUS_POPULATE = {\n createdBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n updatedBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n};\n// All fields to pick from a hydrated result (scalars + populated relations + virtual)\nconst AVAILABLE_STATUS_FIELDS = [\n ...AVAILABLE_STATUS_SCALAR_FIELDS,\n 'createdBy',\n 'updatedBy',\n 'status',\n];\nconst AVAILABLE_LOCALES_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n\n/** Returns a DB filter that matches the opposite publish status. */\nconst oppositePublishStatus = (publishedAt: unknown) =>\n publishedAt !== null ? { $null: true } : { $notNull: true };\n\nconst CONTENT_MANAGER_STATUS = {\n PUBLISHED: 'published',\n DRAFT: 'draft',\n MODIFIED: 'modified',\n};\n\n/**\n * Controls the metadata properties to be returned\n *\n * If `availableLocales` is set to `true` (default), the returned metadata will include\n * the available locales of the document for its current status.\n *\n * If `availableStatus` is set to `true` (default), the returned metadata will include\n * the available status of the document for its current locale.\n */\nexport interface GetMetadataOptions {\n availableLocales?: boolean;\n availableStatus?: boolean;\n}\n\n/**\n * Checks if the provided document version has been modified after all other versions.\n */\nconst getIsVersionLatestModification = (\n version?: DocumentVersion,\n otherVersion?: DocumentVersion\n): boolean => {\n if (!version || !version.updatedAt) {\n return false;\n }\n\n const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;\n\n const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;\n\n return versionUpdatedAt > otherUpdatedAt;\n};\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Returns available locales of a document for the current status.\n *\n * The result is sorted with the default locale (as defined by the i18n plugin)\n * at index 0 when present. This is the canonical-source invariant relied on by\n * `useDocument.getInitialFormValues` in the admin: when creating a new locale\n * draft, non-localized scalar/media values are inherited from\n * `availableLocales[0]`. Putting the default locale first means inheritance\n * stays predictable when sibling locales have drifted on non-localized fields\n * (which can happen because the server only syncs non-localized fields at\n * locale-creation time, not on subsequent updates — see\n * `copyNonLocalizedFields` in document-service/internationalization.ts).\n */\n async getAvailableLocales(\n uid: UID.ContentType,\n version: DocumentVersion,\n allVersions: DocumentVersion[]\n ) {\n // Group all versions by locale\n const versionsByLocale = groupBy(allVersions, 'locale');\n\n // Delete the current locale\n if (version.locale) {\n delete versionsByLocale[version.locale];\n }\n\n // For each locale, get the ones with the same status\n // There will not be a draft and a version counterpart if the content\n // type does not have draft and publish\n const model = strapi.getModel(uid);\n\n const mappingResult = await async.map(\n Object.values(versionsByLocale),\n async (localeVersions: DocumentVersion[]) => {\n if (!contentTypes.hasDraftAndPublish(model)) {\n return localeVersions[0];\n }\n\n const draftVersion = localeVersions.find((v) => v.publishedAt === null);\n const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);\n\n if (!draftVersion) {\n return;\n }\n\n return {\n ...draftVersion,\n status: this.getStatus(draftVersion, otherVersions as any),\n };\n }\n );\n\n const filtered = mappingResult.filter(Boolean) as unknown as NonNullable<\n DocumentMetadata['availableLocales']\n >;\n\n // Sort the default locale first so `availableLocales[0]` is the canonical\n // source for non-localized field inheritance in the admin. Without a\n // localization provider there is no default locale and the order is kept.\n let defaultLocaleCode: string | null | undefined = null;\n try {\n defaultLocaleCode = await strapi.localization.getDefaultLocale();\n } catch {\n // The provider (e.g. its locale store lookup) errored — leave order untouched.\n }\n\n // The provider may resolve `undefined` at runtime when no default locale is stored\n if (defaultLocaleCode === null || defaultLocaleCode === undefined || defaultLocaleCode === '') {\n return filtered as DocumentMetadata['availableLocales'];\n }\n\n // Stable partition: move the default locale entry to the front, keep the\n // rest of the order intact.\n const defaultEntries = filtered.filter((entry) => entry.locale === defaultLocaleCode);\n const otherEntries = filtered.filter((entry) => entry.locale !== defaultLocaleCode);\n\n return [...defaultEntries, ...otherEntries] as DocumentMetadata['availableLocales'];\n },\n\n /**\n * Returns available status of a document for the current locale\n */\n getAvailableStatus(version: DocumentVersion, allVersions: DocumentVersion[]) {\n // Find the other status of the document\n const status =\n version.publishedAt !== null\n ? CONTENT_MANAGER_STATUS.DRAFT\n : CONTENT_MANAGER_STATUS.PUBLISHED;\n\n // Get version that match the current locale and not match the current status\n const availableStatus = allVersions.find((v) => {\n const matchLocale = v.locale === version.locale;\n const matchStatus = status === 'published' ? v.publishedAt !== null : v.publishedAt === null;\n return matchLocale && matchStatus;\n });\n\n if (!availableStatus) return availableStatus;\n\n // Pick status fields (at fields, status, by fields), use lodash\n return pick(availableStatus, AVAILABLE_STATUS_FIELDS);\n },\n\n /**\n * Get the available status of many documents, useful for batch operations\n * @param uid\n * @param documents\n * @returns\n */\n async getManyAvailableStatus(uid: UID.ContentType, documents: DocumentVersion[]) {\n if (!documents.length) return [];\n\n // The status and locale of all documents should be the same\n const status = documents[0].publishedAt !== null ? 'published' : 'draft';\n const locales = documents.map((d) => d.locale).filter(Boolean);\n\n const where: Record<string, any> = {\n documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },\n publishedAt: { $null: status === 'published' },\n };\n\n // If there is any locale to filter (if i18n is enabled)\n if (locales.length === documents.length) {\n where.locale = { $in: locales };\n } else if (locales.length) {\n /*\n * The batch mixes localized and non-localized versions, which happens when a\n * content type holds rows with a locale while others have none — for instance\n * after i18n is disabled on it, or when a locale is sent to a non-localized\n * content type through the API.\n *\n * `locales` only holds the locales that are actually set, so filtering on it\n * alone would drop the counterparts of every version whose locale is null, and\n * those versions would be reported as drafts even though they are published.\n */\n where.$or = [{ locale: { $in: locales } }, { locale: { $null: true } }];\n }\n\n return strapi.db.query(uid).findMany({\n where,\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n });\n },\n\n getStatus(version: DocumentVersion, otherDocumentStatuses?: DocumentMetadata['availableStatus']) {\n let draftVersion: DocumentVersion | undefined;\n let publishedVersion: DocumentVersion | undefined;\n\n if (version.publishedAt) {\n publishedVersion = version;\n } else {\n draftVersion = version;\n }\n\n const otherVersion = otherDocumentStatuses?.at(0);\n if (otherVersion?.publishedAt) {\n publishedVersion = otherVersion;\n } else if (otherVersion) {\n draftVersion = otherVersion;\n }\n\n if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;\n if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;\n\n /*\n * The document is modified if the draft version has been updated more\n * recently than the published version.\n */\n const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);\n return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;\n },\n\n // TODO is it necessary to return metadata on every page of the CM\n // We could refactor this so the locales are only loaded when they're\n // needed. e.g. in the bulk locale action modal.\n async getMetadata(\n uid: UID.ContentType,\n version: DocumentVersion,\n { availableLocales = true, availableStatus = true }: GetMetadataOptions = {}\n ) {\n const model = strapi.getModel(uid);\n const hasDnP = contentTypes.hasDraftAndPublish(model);\n const isLocalized = strapi.localization.isLocalizedContentType(model);\n\n if (!availableLocales && !availableStatus) {\n // Nothing to compute.\n return { availableLocales: [], availableStatus: [], versions: [] as DocumentVersion[] };\n }\n if (!isLocalized && !hasDnP) {\n // If there are no locales and no draft/publish, there's only ever 1 version of any document.\n return { availableLocales: [], availableStatus: [], versions: [] as DocumentVersion[] };\n }\n\n const onlyStatusIsRelevant = hasDnP && (!isLocalized || !availableLocales);\n if (onlyStatusIsRelevant) {\n const otherVersion = availableStatus\n ? await strapi.db.query(uid).findOne({\n where: {\n documentId: version.documentId,\n ...(version.locale ? { locale: version.locale } : {}),\n publishedAt: oppositePublishStatus(version.publishedAt),\n },\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n populate: AVAILABLE_STATUS_POPULATE,\n })\n : null;\n return {\n availableLocales: [],\n availableStatus: otherVersion ? [pick(otherVersion, AVAILABLE_STATUS_FIELDS)] : [],\n versions: [] as DocumentVersion[],\n };\n }\n\n // Full path for localized content types\n // TODO: Ignore publishedAt if availableStatus=false, and ignore locale if\n // i18n is disabled\n\n // Include non-translatable scalar and media fields in availableLocales for i18n prefilling\n let nonLocalizedFields: string[] = [];\n let nonLocalizedMediaFields: string[] = [];\n // Without a localization provider there are no non-localized attributes.\n try {\n if (model?.attributes !== undefined) {\n const allNonLocalized = strapi.localization.getNonLocalizedAttributes(model);\n // Get scalar and media attributes separately\n const scalarAttrs = getScalarAttributes(model);\n const mediaAttrs = getMediaAttributes(model);\n\n // Separate scalar fields (can be in fields array) from media fields (need to be populated)\n nonLocalizedFields = allNonLocalized.filter(\n (field) => field in model.attributes && scalarAttrs.includes(field)\n );\n nonLocalizedMediaFields = allNonLocalized.filter(\n (field) => field in model.attributes && mediaAttrs.includes(field)\n );\n }\n } catch {\n // The provider errored — fall back to no prefilled non-localized fields\n }\n\n // Build populate object for non-localized media fields\n const mediaPopulate = nonLocalizedMediaFields.reduce(\n (acc, field) => {\n acc[field] = {\n populate: {\n folder: true,\n },\n };\n return acc;\n },\n {} as Record<string, { populate: { folder: boolean } }>\n );\n\n const params = {\n populate: {\n ...mediaPopulate,\n ...AVAILABLE_STATUS_POPULATE,\n },\n fields: [...new Set([...AVAILABLE_LOCALES_FIELDS, ...nonLocalizedFields])],\n filters: {\n documentId: version.documentId,\n },\n };\n\n const dbParams = strapi.get('query-params').transform(uid, params);\n const versions = await strapi.db.query(uid).findMany(dbParams);\n\n // TODO: Remove use of available locales and use localizations instead\n const availableLocalesResult = availableLocales\n ? await this.getAvailableLocales(uid, version, versions)\n : [];\n\n const availableStatusResult = availableStatus\n ? this.getAvailableStatus(version, versions)\n : null;\n\n return {\n availableLocales: availableLocalesResult,\n availableStatus: availableStatusResult ? [availableStatusResult] : [],\n versions,\n };\n },\n\n /**\n * Returns associated metadata of a document:\n * - Available locales of the document for the current status\n * - Available status of the document for the current locale\n */\n async formatDocumentWithMetadata(\n uid: UID.ContentType,\n document: DocumentVersion,\n opts: GetMetadataOptions = {}\n ) {\n if (!document) {\n return {\n data: document,\n meta: {\n availableLocales: [],\n availableStatus: [],\n },\n };\n }\n\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(strapi.getModel(uid));\n\n // Ignore available status if the content type does not have draft and publish\n if (!hasDraftAndPublish) {\n opts.availableStatus = false;\n }\n\n const { versions, ...meta } = await this.getMetadata(uid, document, opts);\n\n // Populate localization statuses\n if (document.localizations?.length) {\n document.localizations = document.localizations.map((d) => {\n // Find the counterpart version (same documentId + locale, opposite publishedAt) from\n // the already-fetched versions array, avoiding an extra DB query.\n const counterpart = versions.find(\n (v) =>\n v.documentId === d.documentId &&\n v.locale === d.locale &&\n (d.publishedAt === null) !== (v.publishedAt === null)\n );\n return {\n ...d,\n status: this.getStatus(d, counterpart ? [counterpart] : []),\n };\n });\n }\n\n return {\n data: {\n ...document,\n // Add status to the document only if draft and publish is enabled\n status: hasDraftAndPublish\n ? this.getStatus(document, meta.availableStatus as any)\n : undefined,\n },\n meta,\n };\n },\n});\n"],"names":["getScalarAttributes","getMediaAttributes","contentTypes","AVAILABLE_STATUS_SCALAR_FIELDS","AVAILABLE_STATUS_POPULATE","createdBy","select","updatedBy","AVAILABLE_STATUS_FIELDS","AVAILABLE_LOCALES_FIELDS","oppositePublishStatus","publishedAt","$null","$notNull","CONTENT_MANAGER_STATUS","PUBLISHED","DRAFT","MODIFIED","getIsVersionLatestModification","version","otherVersion","updatedAt","versionUpdatedAt","Date","getTime","otherUpdatedAt","strapi","getAvailableLocales","uid","allVersions","versionsByLocale","groupBy","locale","model","getModel","mappingResult","async","map","Object","values","localeVersions","hasDraftAndPublish","draftVersion","find","v","otherVersions","filter","id","status","getStatus","filtered","Boolean","defaultLocaleCode","localization","getDefaultLocale","undefined","defaultEntries","entry","otherEntries","getAvailableStatus","availableStatus","matchLocale","matchStatus","pick","getManyAvailableStatus","documents","length","locales","d","where","documentId","$in","$or","db","query","findMany","otherDocumentStatuses","publishedVersion","at","isDraftModified","getMetadata","availableLocales","hasDnP","isLocalized","isLocalizedContentType","versions","onlyStatusIsRelevant","findOne","populate","nonLocalizedFields","nonLocalizedMediaFields","attributes","allNonLocalized","getNonLocalizedAttributes","scalarAttrs","mediaAttrs","field","includes","mediaPopulate","reduce","acc","folder","params","fields","Set","filters","dbParams","get","transform","availableLocalesResult","availableStatusResult","formatDocumentWithMetadata","document","opts","data","meta","localizations","counterpart"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"document-metadata.js","sources":["../../../server/src/services/document-metadata.ts"],"sourcesContent":["import { groupBy, pick } from 'lodash';\n\nimport { async, contentTypes } from '@strapi/utils';\nimport type { Core, UID, Modules } from '@strapi/types';\n\nimport type { DocumentMetadata } from '../../../shared/contracts/collection-types';\n\nconst { getScalarAttributes, getMediaAttributes } = contentTypes;\n\nexport interface DocumentVersion {\n id: string | number;\n documentId: Modules.Documents.ID;\n locale?: string;\n localizations?: DocumentVersion[];\n updatedAt?: string | null | Date;\n publishedAt?: string | null | Date;\n}\n\n// Scalar fields that can be used in a DB `select`\nconst AVAILABLE_STATUS_SCALAR_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n// Relation populate shared by both the fast path and the full path\nconst AVAILABLE_STATUS_POPULATE = {\n createdBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n updatedBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n};\n// All fields to pick from a hydrated result (scalars + populated relations + virtual)\nconst AVAILABLE_STATUS_FIELDS = [\n ...AVAILABLE_STATUS_SCALAR_FIELDS,\n 'createdBy',\n 'updatedBy',\n 'status',\n];\nconst AVAILABLE_LOCALES_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n\n/**\n * Convert dotted populate paths (`comp.mid.inners`) into a nested populate object\n * the query-params transformer understands.\n */\nconst dottedPathsToPopulate = (paths: string[]): Record<string, unknown> => {\n const root: Record<string, unknown> = {};\n\n for (const path of paths) {\n const parts = path.split('.').filter(Boolean);\n let node: Record<string, unknown> = root;\n\n for (const [i, part] of parts.entries()) {\n const isLast = i === parts.length - 1;\n\n if (isLast) {\n if (node[part] === undefined) {\n node[part] = true;\n }\n continue;\n }\n\n const current = node[part];\n if (current === true || current === undefined) {\n node[part] = { populate: {} };\n } else if (typeof current === 'object' && current !== null && !('populate' in current)) {\n (current as Record<string, unknown>).populate = {};\n }\n\n node = (node[part] as { populate: Record<string, unknown> }).populate;\n }\n }\n\n return root;\n};\n\n/** Returns a DB filter that matches the opposite publish status. */\nconst oppositePublishStatus = (publishedAt: unknown) =>\n publishedAt !== null ? { $null: true } : { $notNull: true };\n\nconst CONTENT_MANAGER_STATUS = {\n PUBLISHED: 'published',\n DRAFT: 'draft',\n MODIFIED: 'modified',\n};\n\n/**\n * Controls the metadata properties to be returned\n *\n * If `availableLocales` is set to `true` (default), the returned metadata will include\n * the available locales of the document for its current status.\n *\n * If `availableStatus` is set to `true` (default), the returned metadata will include\n * the available status of the document for its current locale.\n */\nexport interface GetMetadataOptions {\n availableLocales?: boolean;\n availableStatus?: boolean;\n}\n\n/**\n * Checks if the provided document version has been modified after all other versions.\n */\nconst getIsVersionLatestModification = (\n version?: DocumentVersion,\n otherVersion?: DocumentVersion\n): boolean => {\n if (!version || !version.updatedAt) {\n return false;\n }\n\n const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;\n\n const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;\n\n return versionUpdatedAt > otherUpdatedAt;\n};\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Returns available locales of a document for the current status.\n *\n * The result is sorted with the default locale (as defined by the i18n plugin)\n * at index 0 when present. This is the canonical-source invariant relied on by\n * `useDocument.getInitialFormValues` in the admin: when creating a new locale\n * draft, non-localized scalar/media/component/dynamic-zone values are inherited from\n * `availableLocales[0]`. Putting the default locale first means inheritance\n * stays predictable when sibling locales have drifted on non-localized fields\n * (which can happen because the server only syncs non-localized fields at\n * locale-creation time, not on subsequent updates — see\n * `copyNonLocalizedFields` in document-service/internationalization.ts).\n */\n async getAvailableLocales(\n uid: UID.ContentType,\n version: DocumentVersion,\n allVersions: DocumentVersion[]\n ) {\n // Group all versions by locale\n const versionsByLocale = groupBy(allVersions, 'locale');\n\n // Delete the current locale\n if (version.locale) {\n delete versionsByLocale[version.locale];\n }\n\n // For each locale, get the ones with the same status\n // There will not be a draft and a version counterpart if the content\n // type does not have draft and publish\n const model = strapi.getModel(uid);\n\n const mappingResult = await async.map(\n Object.values(versionsByLocale),\n async (localeVersions: DocumentVersion[]) => {\n if (!contentTypes.hasDraftAndPublish(model)) {\n return localeVersions[0];\n }\n\n const draftVersion = localeVersions.find((v) => v.publishedAt === null);\n const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);\n\n if (!draftVersion) {\n return;\n }\n\n return {\n ...draftVersion,\n status: this.getStatus(draftVersion, otherVersions as any),\n };\n }\n );\n\n const filtered = mappingResult.filter(Boolean) as unknown as NonNullable<\n DocumentMetadata['availableLocales']\n >;\n\n // Sort the default locale first so `availableLocales[0]` is the canonical\n // source for non-localized field inheritance in the admin. Without a\n // localization provider there is no default locale and the order is kept.\n let defaultLocaleCode: string | null | undefined = null;\n try {\n defaultLocaleCode = await strapi.localization.getDefaultLocale();\n } catch {\n // The provider (e.g. its locale store lookup) errored — leave order untouched.\n }\n\n // The provider may resolve `undefined` at runtime when no default locale is stored\n if (defaultLocaleCode === null || defaultLocaleCode === undefined || defaultLocaleCode === '') {\n return filtered as DocumentMetadata['availableLocales'];\n }\n\n // Stable partition: move the default locale entry to the front, keep the\n // rest of the order intact.\n const defaultEntries = filtered.filter((entry) => entry.locale === defaultLocaleCode);\n const otherEntries = filtered.filter((entry) => entry.locale !== defaultLocaleCode);\n\n return [...defaultEntries, ...otherEntries] as DocumentMetadata['availableLocales'];\n },\n\n /**\n * Returns available status of a document for the current locale\n */\n getAvailableStatus(version: DocumentVersion, allVersions: DocumentVersion[]) {\n // Find the other status of the document\n const status =\n version.publishedAt !== null\n ? CONTENT_MANAGER_STATUS.DRAFT\n : CONTENT_MANAGER_STATUS.PUBLISHED;\n\n // Get version that match the current locale and not match the current status\n const availableStatus = allVersions.find((v) => {\n const matchLocale = v.locale === version.locale;\n const matchStatus = status === 'published' ? v.publishedAt !== null : v.publishedAt === null;\n return matchLocale && matchStatus;\n });\n\n if (!availableStatus) return availableStatus;\n\n // Pick status fields (at fields, status, by fields), use lodash\n return pick(availableStatus, AVAILABLE_STATUS_FIELDS);\n },\n\n /**\n * Get the available status of many documents, useful for batch operations\n * @param uid\n * @param documents\n * @returns\n */\n async getManyAvailableStatus(uid: UID.ContentType, documents: DocumentVersion[]) {\n if (!documents.length) return [];\n\n // The status and locale of all documents should be the same\n const status = documents[0].publishedAt !== null ? 'published' : 'draft';\n const locales = documents.map((d) => d.locale).filter(Boolean);\n\n const where: Record<string, any> = {\n documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },\n publishedAt: { $null: status === 'published' },\n };\n\n // If there is any locale to filter (if i18n is enabled)\n if (locales.length === documents.length) {\n where.locale = { $in: locales };\n } else if (locales.length) {\n /*\n * The batch mixes localized and non-localized versions, which happens when a\n * content type holds rows with a locale while others have none — for instance\n * after i18n is disabled on it, or when a locale is sent to a non-localized\n * content type through the API.\n *\n * `locales` only holds the locales that are actually set, so filtering on it\n * alone would drop the counterparts of every version whose locale is null, and\n * those versions would be reported as drafts even though they are published.\n */\n where.$or = [{ locale: { $in: locales } }, { locale: { $null: true } }];\n }\n\n return strapi.db.query(uid).findMany({\n where,\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n });\n },\n\n getStatus(version: DocumentVersion, otherDocumentStatuses?: DocumentMetadata['availableStatus']) {\n let draftVersion: DocumentVersion | undefined;\n let publishedVersion: DocumentVersion | undefined;\n\n if (version.publishedAt) {\n publishedVersion = version;\n } else {\n draftVersion = version;\n }\n\n const otherVersion = otherDocumentStatuses?.at(0);\n if (otherVersion?.publishedAt) {\n publishedVersion = otherVersion;\n } else if (otherVersion) {\n draftVersion = otherVersion;\n }\n\n if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;\n if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;\n\n /*\n * The document is modified if the draft version has been updated more\n * recently than the published version.\n */\n const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);\n return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;\n },\n\n // TODO is it necessary to return metadata on every page of the CM\n // We could refactor this so the locales are only loaded when they're\n // needed. e.g. in the bulk locale action modal.\n async getMetadata(\n uid: UID.ContentType,\n version: DocumentVersion,\n { availableLocales = true, availableStatus = true }: GetMetadataOptions = {}\n ) {\n const model = strapi.getModel(uid);\n const hasDnP = contentTypes.hasDraftAndPublish(model);\n const isLocalized = strapi.localization.isLocalizedContentType(model);\n\n // Resolve once for all return paths — admin lock logic needs this even when\n // the current locale is excluded from `availableLocales`.\n let defaultLocale: string | null = null;\n if (isLocalized) {\n try {\n defaultLocale = (await strapi.localization.getDefaultLocale()) ?? null;\n } catch {\n defaultLocale = null;\n }\n }\n\n if (!availableLocales && !availableStatus) {\n // Nothing to compute.\n return {\n availableLocales: [],\n availableStatus: [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n if (!isLocalized && !hasDnP) {\n // If there are no locales and no draft/publish, there's only ever 1 version of any document.\n return {\n availableLocales: [],\n availableStatus: [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n\n const onlyStatusIsRelevant = hasDnP && (!isLocalized || !availableLocales);\n if (onlyStatusIsRelevant) {\n const otherVersion = availableStatus\n ? await strapi.db.query(uid).findOne({\n where: {\n documentId: version.documentId,\n ...(version.locale ? { locale: version.locale } : {}),\n publishedAt: oppositePublishStatus(version.publishedAt),\n },\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n populate: AVAILABLE_STATUS_POPULATE,\n })\n : null;\n return {\n availableLocales: [],\n availableStatus: otherVersion ? [pick(otherVersion, AVAILABLE_STATUS_FIELDS)] : [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n\n // Full path for localized content types\n // TODO: Ignore publishedAt if availableStatus=false, and ignore locale if\n // i18n is disabled\n\n // Include non-translatable fields in availableLocales for i18n prefilling\n // (scalars + media + components + dynamic zones; relations stay server-filled).\n let nonLocalizedFields: string[] = [];\n let nonLocalizedMediaFields: string[] = [];\n // Without a localization provider there are no non-localized attributes.\n let nestedPopulate: Record<string, unknown> = {};\n try {\n if (model?.attributes !== undefined) {\n const allNonLocalized = strapi.localization.getNonLocalizedAttributes(model);\n // Get scalar and media attributes separately\n const scalarAttrs = getScalarAttributes(model);\n const mediaAttrs = getMediaAttributes(model);\n\n // Separate scalar fields (can be in fields array) from media fields (need to be populated)\n nonLocalizedFields = allNonLocalized.filter(\n (field: string) => field in model.attributes && scalarAttrs.includes(field)\n );\n nonLocalizedMediaFields = allNonLocalized.filter(\n (field: string) => field in model.attributes && mediaAttrs.includes(field)\n );\n\n const getNestedPopulate = strapi.localization.getNestedPopulateOfNonLocalizedAttributes;\n if (typeof getNestedPopulate === 'function') {\n const buildNestedPopulate = (\n schemaUID: UID.Schema,\n populate = dottedPathsToPopulate(getNestedPopulate(schemaUID))\n ): Record<string, unknown> => {\n const schema = strapi.getModel(schemaUID);\n\n return Object.fromEntries(\n Object.entries(populate).map(([field, value]) => {\n const attribute = schema?.attributes[field];\n\n if (attribute?.type === 'dynamiczone') {\n return [\n field,\n {\n on: attribute.components.reduce<\n Record<string, { populate: Record<string, unknown> }>\n >((acc, componentUID) => {\n acc[componentUID] = {\n populate: buildNestedPopulate(componentUID),\n };\n return acc;\n }, {}),\n },\n ];\n }\n\n if (\n attribute?.type === 'component' &&\n typeof value === 'object' &&\n value !== null &&\n 'populate' in value\n ) {\n return [\n field,\n {\n populate: buildNestedPopulate(\n attribute.component,\n (value as { populate: Record<string, unknown> }).populate\n ),\n },\n ];\n }\n\n return [field, value];\n })\n );\n };\n\n nestedPopulate = buildNestedPopulate(uid);\n } else {\n const componentAndDzFields = allNonLocalized.filter(\n (field: string) =>\n field in model.attributes &&\n (model.attributes[field]?.type === 'component' ||\n model.attributes[field]?.type === 'dynamiczone')\n );\n nestedPopulate = componentAndDzFields.reduce(\n (acc: Record<string, true>, field: string) => {\n acc[field] = true;\n return acc;\n },\n {}\n );\n }\n }\n } catch {\n // The provider errored — fall back to no prefilled non-localized fields\n }\n\n // Build populate object for non-localized media + nested component/DZ fields\n const mediaPopulate = nonLocalizedMediaFields.reduce(\n (acc, field) => {\n acc[field] = {\n populate: {\n folder: true,\n },\n };\n return acc;\n },\n {} as Record<string, { populate: { folder: boolean } } | true>\n );\n\n const params = {\n populate: {\n ...nestedPopulate,\n ...mediaPopulate,\n ...AVAILABLE_STATUS_POPULATE,\n },\n fields: [...new Set([...AVAILABLE_LOCALES_FIELDS, ...nonLocalizedFields])],\n filters: {\n documentId: version.documentId,\n },\n };\n\n const dbParams = strapi.get('query-params').transform(uid, params);\n const versions = await strapi.db.query(uid).findMany(dbParams);\n\n // TODO: Remove use of available locales and use localizations instead\n const availableLocalesResult = availableLocales\n ? await this.getAvailableLocales(uid, version, versions)\n : [];\n\n const availableStatusResult = availableStatus\n ? this.getAvailableStatus(version, versions)\n : null;\n\n return {\n availableLocales: availableLocalesResult,\n availableStatus: availableStatusResult ? [availableStatusResult] : [],\n defaultLocale,\n versions,\n };\n },\n\n /**\n * Returns associated metadata of a document:\n * - Available locales of the document for the current status\n * - Available status of the document for the current locale\n */\n async formatDocumentWithMetadata(\n uid: UID.ContentType,\n document: DocumentVersion,\n opts: GetMetadataOptions = {}\n ) {\n if (!document) {\n return {\n data: document,\n meta: {\n availableLocales: [],\n availableStatus: [],\n defaultLocale: null,\n },\n };\n }\n\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(strapi.getModel(uid));\n\n // Ignore available status if the content type does not have draft and publish\n if (!hasDraftAndPublish) {\n opts.availableStatus = false;\n }\n\n const { versions, ...meta } = await this.getMetadata(uid, document, opts);\n\n // Populate localization statuses\n if (document.localizations?.length) {\n document.localizations = document.localizations.map((d) => {\n // Find the counterpart version (same documentId + locale, opposite publishedAt) from\n // the already-fetched versions array, avoiding an extra DB query.\n const counterpart = versions.find(\n (v) =>\n v.documentId === d.documentId &&\n v.locale === d.locale &&\n (d.publishedAt === null) !== (v.publishedAt === null)\n );\n return {\n ...d,\n status: this.getStatus(d, counterpart ? [counterpart] : []),\n };\n });\n }\n\n return {\n data: {\n ...document,\n // Add status to the document only if draft and publish is enabled\n status: hasDraftAndPublish\n ? this.getStatus(document, meta.availableStatus as any)\n : undefined,\n },\n meta,\n };\n },\n});\n"],"names":["getScalarAttributes","getMediaAttributes","contentTypes","AVAILABLE_STATUS_SCALAR_FIELDS","AVAILABLE_STATUS_POPULATE","createdBy","select","updatedBy","AVAILABLE_STATUS_FIELDS","AVAILABLE_LOCALES_FIELDS","dottedPathsToPopulate","paths","root","path","parts","split","filter","Boolean","node","i","part","entries","isLast","length","undefined","current","populate","oppositePublishStatus","publishedAt","$null","$notNull","CONTENT_MANAGER_STATUS","PUBLISHED","DRAFT","MODIFIED","getIsVersionLatestModification","version","otherVersion","updatedAt","versionUpdatedAt","Date","getTime","otherUpdatedAt","strapi","getAvailableLocales","uid","allVersions","versionsByLocale","groupBy","locale","model","getModel","mappingResult","async","map","Object","values","localeVersions","hasDraftAndPublish","draftVersion","find","v","otherVersions","id","status","getStatus","filtered","defaultLocaleCode","localization","getDefaultLocale","defaultEntries","entry","otherEntries","getAvailableStatus","availableStatus","matchLocale","matchStatus","pick","getManyAvailableStatus","documents","locales","d","where","documentId","$in","$or","db","query","findMany","otherDocumentStatuses","publishedVersion","at","isDraftModified","getMetadata","availableLocales","hasDnP","isLocalized","isLocalizedContentType","defaultLocale","versions","onlyStatusIsRelevant","findOne","nonLocalizedFields","nonLocalizedMediaFields","nestedPopulate","attributes","allNonLocalized","getNonLocalizedAttributes","scalarAttrs","mediaAttrs","field","includes","getNestedPopulate","getNestedPopulateOfNonLocalizedAttributes","buildNestedPopulate","schemaUID","schema","fromEntries","value","attribute","type","on","components","reduce","acc","componentUID","component","componentAndDzFields","mediaPopulate","folder","params","fields","Set","filters","dbParams","get","transform","availableLocalesResult","availableStatusResult","formatDocumentWithMetadata","document","opts","data","meta","localizations","counterpart"],"mappings":"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"}
|
|
@@ -45,6 +45,35 @@ const AVAILABLE_LOCALES_FIELDS = [
|
|
|
45
45
|
'createdAt',
|
|
46
46
|
'publishedAt'
|
|
47
47
|
];
|
|
48
|
+
/**
|
|
49
|
+
* Convert dotted populate paths (`comp.mid.inners`) into a nested populate object
|
|
50
|
+
* the query-params transformer understands.
|
|
51
|
+
*/ const dottedPathsToPopulate = (paths)=>{
|
|
52
|
+
const root = {};
|
|
53
|
+
for (const path of paths){
|
|
54
|
+
const parts = path.split('.').filter(Boolean);
|
|
55
|
+
let node = root;
|
|
56
|
+
for (const [i, part] of parts.entries()){
|
|
57
|
+
const isLast = i === parts.length - 1;
|
|
58
|
+
if (isLast) {
|
|
59
|
+
if (node[part] === undefined) {
|
|
60
|
+
node[part] = true;
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const current = node[part];
|
|
65
|
+
if (current === true || current === undefined) {
|
|
66
|
+
node[part] = {
|
|
67
|
+
populate: {}
|
|
68
|
+
};
|
|
69
|
+
} else if (typeof current === 'object' && current !== null && !('populate' in current)) {
|
|
70
|
+
current.populate = {};
|
|
71
|
+
}
|
|
72
|
+
node = node[part].populate;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return root;
|
|
76
|
+
};
|
|
48
77
|
/** Returns a DB filter that matches the opposite publish status. */ const oppositePublishStatus = (publishedAt)=>publishedAt !== null ? {
|
|
49
78
|
$null: true
|
|
50
79
|
} : {
|
|
@@ -72,7 +101,7 @@ var documentMetadata = (({ strapi })=>({
|
|
|
72
101
|
* The result is sorted with the default locale (as defined by the i18n plugin)
|
|
73
102
|
* at index 0 when present. This is the canonical-source invariant relied on by
|
|
74
103
|
* `useDocument.getInitialFormValues` in the admin: when creating a new locale
|
|
75
|
-
* draft, non-localized scalar/media values are inherited from
|
|
104
|
+
* draft, non-localized scalar/media/component/dynamic-zone values are inherited from
|
|
76
105
|
* `availableLocales[0]`. Putting the default locale first means inheritance
|
|
77
106
|
* stays predictable when sibling locales have drifted on non-localized fields
|
|
78
107
|
* (which can happen because the server only syncs non-localized fields at
|
|
@@ -221,11 +250,22 @@ var documentMetadata = (({ strapi })=>({
|
|
|
221
250
|
const model = strapi.getModel(uid);
|
|
222
251
|
const hasDnP = contentTypes.hasDraftAndPublish(model);
|
|
223
252
|
const isLocalized = strapi.localization.isLocalizedContentType(model);
|
|
253
|
+
// Resolve once for all return paths — admin lock logic needs this even when
|
|
254
|
+
// the current locale is excluded from `availableLocales`.
|
|
255
|
+
let defaultLocale = null;
|
|
256
|
+
if (isLocalized) {
|
|
257
|
+
try {
|
|
258
|
+
defaultLocale = await strapi.localization.getDefaultLocale() ?? null;
|
|
259
|
+
} catch {
|
|
260
|
+
defaultLocale = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
224
263
|
if (!availableLocales && !availableStatus) {
|
|
225
264
|
// Nothing to compute.
|
|
226
265
|
return {
|
|
227
266
|
availableLocales: [],
|
|
228
267
|
availableStatus: [],
|
|
268
|
+
defaultLocale,
|
|
229
269
|
versions: []
|
|
230
270
|
};
|
|
231
271
|
}
|
|
@@ -234,6 +274,7 @@ var documentMetadata = (({ strapi })=>({
|
|
|
234
274
|
return {
|
|
235
275
|
availableLocales: [],
|
|
236
276
|
availableStatus: [],
|
|
277
|
+
defaultLocale,
|
|
237
278
|
versions: []
|
|
238
279
|
};
|
|
239
280
|
}
|
|
@@ -255,16 +296,19 @@ var documentMetadata = (({ strapi })=>({
|
|
|
255
296
|
availableStatus: otherVersion ? [
|
|
256
297
|
pick(otherVersion, AVAILABLE_STATUS_FIELDS)
|
|
257
298
|
] : [],
|
|
299
|
+
defaultLocale,
|
|
258
300
|
versions: []
|
|
259
301
|
};
|
|
260
302
|
}
|
|
261
303
|
// Full path for localized content types
|
|
262
304
|
// TODO: Ignore publishedAt if availableStatus=false, and ignore locale if
|
|
263
305
|
// i18n is disabled
|
|
264
|
-
// Include non-translatable
|
|
306
|
+
// Include non-translatable fields in availableLocales for i18n prefilling
|
|
307
|
+
// (scalars + media + components + dynamic zones; relations stay server-filled).
|
|
265
308
|
let nonLocalizedFields = [];
|
|
266
309
|
let nonLocalizedMediaFields = [];
|
|
267
310
|
// Without a localization provider there are no non-localized attributes.
|
|
311
|
+
let nestedPopulate = {};
|
|
268
312
|
try {
|
|
269
313
|
if (model?.attributes !== undefined) {
|
|
270
314
|
const allNonLocalized = strapi.localization.getNonLocalizedAttributes(model);
|
|
@@ -274,11 +318,52 @@ var documentMetadata = (({ strapi })=>({
|
|
|
274
318
|
// Separate scalar fields (can be in fields array) from media fields (need to be populated)
|
|
275
319
|
nonLocalizedFields = allNonLocalized.filter((field)=>field in model.attributes && scalarAttrs.includes(field));
|
|
276
320
|
nonLocalizedMediaFields = allNonLocalized.filter((field)=>field in model.attributes && mediaAttrs.includes(field));
|
|
321
|
+
const getNestedPopulate = strapi.localization.getNestedPopulateOfNonLocalizedAttributes;
|
|
322
|
+
if (typeof getNestedPopulate === 'function') {
|
|
323
|
+
const buildNestedPopulate = (schemaUID, populate = dottedPathsToPopulate(getNestedPopulate(schemaUID)))=>{
|
|
324
|
+
const schema = strapi.getModel(schemaUID);
|
|
325
|
+
return Object.fromEntries(Object.entries(populate).map(([field, value])=>{
|
|
326
|
+
const attribute = schema?.attributes[field];
|
|
327
|
+
if (attribute?.type === 'dynamiczone') {
|
|
328
|
+
return [
|
|
329
|
+
field,
|
|
330
|
+
{
|
|
331
|
+
on: attribute.components.reduce((acc, componentUID)=>{
|
|
332
|
+
acc[componentUID] = {
|
|
333
|
+
populate: buildNestedPopulate(componentUID)
|
|
334
|
+
};
|
|
335
|
+
return acc;
|
|
336
|
+
}, {})
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
}
|
|
340
|
+
if (attribute?.type === 'component' && typeof value === 'object' && value !== null && 'populate' in value) {
|
|
341
|
+
return [
|
|
342
|
+
field,
|
|
343
|
+
{
|
|
344
|
+
populate: buildNestedPopulate(attribute.component, value.populate)
|
|
345
|
+
}
|
|
346
|
+
];
|
|
347
|
+
}
|
|
348
|
+
return [
|
|
349
|
+
field,
|
|
350
|
+
value
|
|
351
|
+
];
|
|
352
|
+
}));
|
|
353
|
+
};
|
|
354
|
+
nestedPopulate = buildNestedPopulate(uid);
|
|
355
|
+
} else {
|
|
356
|
+
const componentAndDzFields = allNonLocalized.filter((field)=>field in model.attributes && (model.attributes[field]?.type === 'component' || model.attributes[field]?.type === 'dynamiczone'));
|
|
357
|
+
nestedPopulate = componentAndDzFields.reduce((acc, field)=>{
|
|
358
|
+
acc[field] = true;
|
|
359
|
+
return acc;
|
|
360
|
+
}, {});
|
|
361
|
+
}
|
|
277
362
|
}
|
|
278
363
|
} catch {
|
|
279
364
|
// The provider errored — fall back to no prefilled non-localized fields
|
|
280
365
|
}
|
|
281
|
-
// Build populate object for non-localized media fields
|
|
366
|
+
// Build populate object for non-localized media + nested component/DZ fields
|
|
282
367
|
const mediaPopulate = nonLocalizedMediaFields.reduce((acc, field)=>{
|
|
283
368
|
acc[field] = {
|
|
284
369
|
populate: {
|
|
@@ -289,6 +374,7 @@ var documentMetadata = (({ strapi })=>({
|
|
|
289
374
|
}, {});
|
|
290
375
|
const params = {
|
|
291
376
|
populate: {
|
|
377
|
+
...nestedPopulate,
|
|
292
378
|
...mediaPopulate,
|
|
293
379
|
...AVAILABLE_STATUS_POPULATE
|
|
294
380
|
},
|
|
@@ -312,6 +398,7 @@ var documentMetadata = (({ strapi })=>({
|
|
|
312
398
|
availableStatus: availableStatusResult ? [
|
|
313
399
|
availableStatusResult
|
|
314
400
|
] : [],
|
|
401
|
+
defaultLocale,
|
|
315
402
|
versions
|
|
316
403
|
};
|
|
317
404
|
},
|
|
@@ -325,7 +412,8 @@ var documentMetadata = (({ strapi })=>({
|
|
|
325
412
|
data: document,
|
|
326
413
|
meta: {
|
|
327
414
|
availableLocales: [],
|
|
328
|
-
availableStatus: []
|
|
415
|
+
availableStatus: [],
|
|
416
|
+
defaultLocale: null
|
|
329
417
|
}
|
|
330
418
|
};
|
|
331
419
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-metadata.mjs","sources":["../../../server/src/services/document-metadata.ts"],"sourcesContent":["import { groupBy, pick } from 'lodash';\n\nimport { async, contentTypes } from '@strapi/utils';\nimport type { Core, UID, Modules } from '@strapi/types';\n\nimport type { DocumentMetadata } from '../../../shared/contracts/collection-types';\n\nconst { getScalarAttributes, getMediaAttributes } = contentTypes;\n\nexport interface DocumentVersion {\n id: string | number;\n documentId: Modules.Documents.ID;\n locale?: string;\n localizations?: DocumentVersion[];\n updatedAt?: string | null | Date;\n publishedAt?: string | null | Date;\n}\n\n// Scalar fields that can be used in a DB `select`\nconst AVAILABLE_STATUS_SCALAR_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n// Relation populate shared by both the fast path and the full path\nconst AVAILABLE_STATUS_POPULATE = {\n createdBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n updatedBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n};\n// All fields to pick from a hydrated result (scalars + populated relations + virtual)\nconst AVAILABLE_STATUS_FIELDS = [\n ...AVAILABLE_STATUS_SCALAR_FIELDS,\n 'createdBy',\n 'updatedBy',\n 'status',\n];\nconst AVAILABLE_LOCALES_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n\n/** Returns a DB filter that matches the opposite publish status. */\nconst oppositePublishStatus = (publishedAt: unknown) =>\n publishedAt !== null ? { $null: true } : { $notNull: true };\n\nconst CONTENT_MANAGER_STATUS = {\n PUBLISHED: 'published',\n DRAFT: 'draft',\n MODIFIED: 'modified',\n};\n\n/**\n * Controls the metadata properties to be returned\n *\n * If `availableLocales` is set to `true` (default), the returned metadata will include\n * the available locales of the document for its current status.\n *\n * If `availableStatus` is set to `true` (default), the returned metadata will include\n * the available status of the document for its current locale.\n */\nexport interface GetMetadataOptions {\n availableLocales?: boolean;\n availableStatus?: boolean;\n}\n\n/**\n * Checks if the provided document version has been modified after all other versions.\n */\nconst getIsVersionLatestModification = (\n version?: DocumentVersion,\n otherVersion?: DocumentVersion\n): boolean => {\n if (!version || !version.updatedAt) {\n return false;\n }\n\n const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;\n\n const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;\n\n return versionUpdatedAt > otherUpdatedAt;\n};\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Returns available locales of a document for the current status.\n *\n * The result is sorted with the default locale (as defined by the i18n plugin)\n * at index 0 when present. This is the canonical-source invariant relied on by\n * `useDocument.getInitialFormValues` in the admin: when creating a new locale\n * draft, non-localized scalar/media values are inherited from\n * `availableLocales[0]`. Putting the default locale first means inheritance\n * stays predictable when sibling locales have drifted on non-localized fields\n * (which can happen because the server only syncs non-localized fields at\n * locale-creation time, not on subsequent updates — see\n * `copyNonLocalizedFields` in document-service/internationalization.ts).\n */\n async getAvailableLocales(\n uid: UID.ContentType,\n version: DocumentVersion,\n allVersions: DocumentVersion[]\n ) {\n // Group all versions by locale\n const versionsByLocale = groupBy(allVersions, 'locale');\n\n // Delete the current locale\n if (version.locale) {\n delete versionsByLocale[version.locale];\n }\n\n // For each locale, get the ones with the same status\n // There will not be a draft and a version counterpart if the content\n // type does not have draft and publish\n const model = strapi.getModel(uid);\n\n const mappingResult = await async.map(\n Object.values(versionsByLocale),\n async (localeVersions: DocumentVersion[]) => {\n if (!contentTypes.hasDraftAndPublish(model)) {\n return localeVersions[0];\n }\n\n const draftVersion = localeVersions.find((v) => v.publishedAt === null);\n const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);\n\n if (!draftVersion) {\n return;\n }\n\n return {\n ...draftVersion,\n status: this.getStatus(draftVersion, otherVersions as any),\n };\n }\n );\n\n const filtered = mappingResult.filter(Boolean) as unknown as NonNullable<\n DocumentMetadata['availableLocales']\n >;\n\n // Sort the default locale first so `availableLocales[0]` is the canonical\n // source for non-localized field inheritance in the admin. Without a\n // localization provider there is no default locale and the order is kept.\n let defaultLocaleCode: string | null | undefined = null;\n try {\n defaultLocaleCode = await strapi.localization.getDefaultLocale();\n } catch {\n // The provider (e.g. its locale store lookup) errored — leave order untouched.\n }\n\n // The provider may resolve `undefined` at runtime when no default locale is stored\n if (defaultLocaleCode === null || defaultLocaleCode === undefined || defaultLocaleCode === '') {\n return filtered as DocumentMetadata['availableLocales'];\n }\n\n // Stable partition: move the default locale entry to the front, keep the\n // rest of the order intact.\n const defaultEntries = filtered.filter((entry) => entry.locale === defaultLocaleCode);\n const otherEntries = filtered.filter((entry) => entry.locale !== defaultLocaleCode);\n\n return [...defaultEntries, ...otherEntries] as DocumentMetadata['availableLocales'];\n },\n\n /**\n * Returns available status of a document for the current locale\n */\n getAvailableStatus(version: DocumentVersion, allVersions: DocumentVersion[]) {\n // Find the other status of the document\n const status =\n version.publishedAt !== null\n ? CONTENT_MANAGER_STATUS.DRAFT\n : CONTENT_MANAGER_STATUS.PUBLISHED;\n\n // Get version that match the current locale and not match the current status\n const availableStatus = allVersions.find((v) => {\n const matchLocale = v.locale === version.locale;\n const matchStatus = status === 'published' ? v.publishedAt !== null : v.publishedAt === null;\n return matchLocale && matchStatus;\n });\n\n if (!availableStatus) return availableStatus;\n\n // Pick status fields (at fields, status, by fields), use lodash\n return pick(availableStatus, AVAILABLE_STATUS_FIELDS);\n },\n\n /**\n * Get the available status of many documents, useful for batch operations\n * @param uid\n * @param documents\n * @returns\n */\n async getManyAvailableStatus(uid: UID.ContentType, documents: DocumentVersion[]) {\n if (!documents.length) return [];\n\n // The status and locale of all documents should be the same\n const status = documents[0].publishedAt !== null ? 'published' : 'draft';\n const locales = documents.map((d) => d.locale).filter(Boolean);\n\n const where: Record<string, any> = {\n documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },\n publishedAt: { $null: status === 'published' },\n };\n\n // If there is any locale to filter (if i18n is enabled)\n if (locales.length === documents.length) {\n where.locale = { $in: locales };\n } else if (locales.length) {\n /*\n * The batch mixes localized and non-localized versions, which happens when a\n * content type holds rows with a locale while others have none — for instance\n * after i18n is disabled on it, or when a locale is sent to a non-localized\n * content type through the API.\n *\n * `locales` only holds the locales that are actually set, so filtering on it\n * alone would drop the counterparts of every version whose locale is null, and\n * those versions would be reported as drafts even though they are published.\n */\n where.$or = [{ locale: { $in: locales } }, { locale: { $null: true } }];\n }\n\n return strapi.db.query(uid).findMany({\n where,\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n });\n },\n\n getStatus(version: DocumentVersion, otherDocumentStatuses?: DocumentMetadata['availableStatus']) {\n let draftVersion: DocumentVersion | undefined;\n let publishedVersion: DocumentVersion | undefined;\n\n if (version.publishedAt) {\n publishedVersion = version;\n } else {\n draftVersion = version;\n }\n\n const otherVersion = otherDocumentStatuses?.at(0);\n if (otherVersion?.publishedAt) {\n publishedVersion = otherVersion;\n } else if (otherVersion) {\n draftVersion = otherVersion;\n }\n\n if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;\n if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;\n\n /*\n * The document is modified if the draft version has been updated more\n * recently than the published version.\n */\n const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);\n return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;\n },\n\n // TODO is it necessary to return metadata on every page of the CM\n // We could refactor this so the locales are only loaded when they're\n // needed. e.g. in the bulk locale action modal.\n async getMetadata(\n uid: UID.ContentType,\n version: DocumentVersion,\n { availableLocales = true, availableStatus = true }: GetMetadataOptions = {}\n ) {\n const model = strapi.getModel(uid);\n const hasDnP = contentTypes.hasDraftAndPublish(model);\n const isLocalized = strapi.localization.isLocalizedContentType(model);\n\n if (!availableLocales && !availableStatus) {\n // Nothing to compute.\n return { availableLocales: [], availableStatus: [], versions: [] as DocumentVersion[] };\n }\n if (!isLocalized && !hasDnP) {\n // If there are no locales and no draft/publish, there's only ever 1 version of any document.\n return { availableLocales: [], availableStatus: [], versions: [] as DocumentVersion[] };\n }\n\n const onlyStatusIsRelevant = hasDnP && (!isLocalized || !availableLocales);\n if (onlyStatusIsRelevant) {\n const otherVersion = availableStatus\n ? await strapi.db.query(uid).findOne({\n where: {\n documentId: version.documentId,\n ...(version.locale ? { locale: version.locale } : {}),\n publishedAt: oppositePublishStatus(version.publishedAt),\n },\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n populate: AVAILABLE_STATUS_POPULATE,\n })\n : null;\n return {\n availableLocales: [],\n availableStatus: otherVersion ? [pick(otherVersion, AVAILABLE_STATUS_FIELDS)] : [],\n versions: [] as DocumentVersion[],\n };\n }\n\n // Full path for localized content types\n // TODO: Ignore publishedAt if availableStatus=false, and ignore locale if\n // i18n is disabled\n\n // Include non-translatable scalar and media fields in availableLocales for i18n prefilling\n let nonLocalizedFields: string[] = [];\n let nonLocalizedMediaFields: string[] = [];\n // Without a localization provider there are no non-localized attributes.\n try {\n if (model?.attributes !== undefined) {\n const allNonLocalized = strapi.localization.getNonLocalizedAttributes(model);\n // Get scalar and media attributes separately\n const scalarAttrs = getScalarAttributes(model);\n const mediaAttrs = getMediaAttributes(model);\n\n // Separate scalar fields (can be in fields array) from media fields (need to be populated)\n nonLocalizedFields = allNonLocalized.filter(\n (field) => field in model.attributes && scalarAttrs.includes(field)\n );\n nonLocalizedMediaFields = allNonLocalized.filter(\n (field) => field in model.attributes && mediaAttrs.includes(field)\n );\n }\n } catch {\n // The provider errored — fall back to no prefilled non-localized fields\n }\n\n // Build populate object for non-localized media fields\n const mediaPopulate = nonLocalizedMediaFields.reduce(\n (acc, field) => {\n acc[field] = {\n populate: {\n folder: true,\n },\n };\n return acc;\n },\n {} as Record<string, { populate: { folder: boolean } }>\n );\n\n const params = {\n populate: {\n ...mediaPopulate,\n ...AVAILABLE_STATUS_POPULATE,\n },\n fields: [...new Set([...AVAILABLE_LOCALES_FIELDS, ...nonLocalizedFields])],\n filters: {\n documentId: version.documentId,\n },\n };\n\n const dbParams = strapi.get('query-params').transform(uid, params);\n const versions = await strapi.db.query(uid).findMany(dbParams);\n\n // TODO: Remove use of available locales and use localizations instead\n const availableLocalesResult = availableLocales\n ? await this.getAvailableLocales(uid, version, versions)\n : [];\n\n const availableStatusResult = availableStatus\n ? this.getAvailableStatus(version, versions)\n : null;\n\n return {\n availableLocales: availableLocalesResult,\n availableStatus: availableStatusResult ? [availableStatusResult] : [],\n versions,\n };\n },\n\n /**\n * Returns associated metadata of a document:\n * - Available locales of the document for the current status\n * - Available status of the document for the current locale\n */\n async formatDocumentWithMetadata(\n uid: UID.ContentType,\n document: DocumentVersion,\n opts: GetMetadataOptions = {}\n ) {\n if (!document) {\n return {\n data: document,\n meta: {\n availableLocales: [],\n availableStatus: [],\n },\n };\n }\n\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(strapi.getModel(uid));\n\n // Ignore available status if the content type does not have draft and publish\n if (!hasDraftAndPublish) {\n opts.availableStatus = false;\n }\n\n const { versions, ...meta } = await this.getMetadata(uid, document, opts);\n\n // Populate localization statuses\n if (document.localizations?.length) {\n document.localizations = document.localizations.map((d) => {\n // Find the counterpart version (same documentId + locale, opposite publishedAt) from\n // the already-fetched versions array, avoiding an extra DB query.\n const counterpart = versions.find(\n (v) =>\n v.documentId === d.documentId &&\n v.locale === d.locale &&\n (d.publishedAt === null) !== (v.publishedAt === null)\n );\n return {\n ...d,\n status: this.getStatus(d, counterpart ? [counterpart] : []),\n };\n });\n }\n\n return {\n data: {\n ...document,\n // Add status to the document only if draft and publish is enabled\n status: hasDraftAndPublish\n ? this.getStatus(document, meta.availableStatus as any)\n : undefined,\n },\n meta,\n };\n },\n});\n"],"names":["getScalarAttributes","getMediaAttributes","contentTypes","AVAILABLE_STATUS_SCALAR_FIELDS","AVAILABLE_STATUS_POPULATE","createdBy","select","updatedBy","AVAILABLE_STATUS_FIELDS","AVAILABLE_LOCALES_FIELDS","oppositePublishStatus","publishedAt","$null","$notNull","CONTENT_MANAGER_STATUS","PUBLISHED","DRAFT","MODIFIED","getIsVersionLatestModification","version","otherVersion","updatedAt","versionUpdatedAt","Date","getTime","otherUpdatedAt","strapi","getAvailableLocales","uid","allVersions","versionsByLocale","groupBy","locale","model","getModel","mappingResult","async","map","Object","values","localeVersions","hasDraftAndPublish","draftVersion","find","v","otherVersions","filter","id","status","getStatus","filtered","Boolean","defaultLocaleCode","localization","getDefaultLocale","undefined","defaultEntries","entry","otherEntries","getAvailableStatus","availableStatus","matchLocale","matchStatus","pick","getManyAvailableStatus","documents","length","locales","d","where","documentId","$in","$or","db","query","findMany","otherDocumentStatuses","publishedVersion","at","isDraftModified","getMetadata","availableLocales","hasDnP","isLocalized","isLocalizedContentType","versions","onlyStatusIsRelevant","findOne","populate","nonLocalizedFields","nonLocalizedMediaFields","attributes","allNonLocalized","getNonLocalizedAttributes","scalarAttrs","mediaAttrs","field","includes","mediaPopulate","reduce","acc","folder","params","fields","Set","filters","dbParams","get","transform","availableLocalesResult","availableStatusResult","formatDocumentWithMetadata","document","opts","data","meta","localizations","counterpart"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"document-metadata.mjs","sources":["../../../server/src/services/document-metadata.ts"],"sourcesContent":["import { groupBy, pick } from 'lodash';\n\nimport { async, contentTypes } from '@strapi/utils';\nimport type { Core, UID, Modules } from '@strapi/types';\n\nimport type { DocumentMetadata } from '../../../shared/contracts/collection-types';\n\nconst { getScalarAttributes, getMediaAttributes } = contentTypes;\n\nexport interface DocumentVersion {\n id: string | number;\n documentId: Modules.Documents.ID;\n locale?: string;\n localizations?: DocumentVersion[];\n updatedAt?: string | null | Date;\n publishedAt?: string | null | Date;\n}\n\n// Scalar fields that can be used in a DB `select`\nconst AVAILABLE_STATUS_SCALAR_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n// Relation populate shared by both the fast path and the full path\nconst AVAILABLE_STATUS_POPULATE = {\n createdBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n updatedBy: { select: ['id', 'firstname', 'lastname', 'email'] },\n};\n// All fields to pick from a hydrated result (scalars + populated relations + virtual)\nconst AVAILABLE_STATUS_FIELDS = [\n ...AVAILABLE_STATUS_SCALAR_FIELDS,\n 'createdBy',\n 'updatedBy',\n 'status',\n];\nconst AVAILABLE_LOCALES_FIELDS = [\n 'id',\n 'documentId',\n 'locale',\n 'updatedAt',\n 'createdAt',\n 'publishedAt',\n];\n\n/**\n * Convert dotted populate paths (`comp.mid.inners`) into a nested populate object\n * the query-params transformer understands.\n */\nconst dottedPathsToPopulate = (paths: string[]): Record<string, unknown> => {\n const root: Record<string, unknown> = {};\n\n for (const path of paths) {\n const parts = path.split('.').filter(Boolean);\n let node: Record<string, unknown> = root;\n\n for (const [i, part] of parts.entries()) {\n const isLast = i === parts.length - 1;\n\n if (isLast) {\n if (node[part] === undefined) {\n node[part] = true;\n }\n continue;\n }\n\n const current = node[part];\n if (current === true || current === undefined) {\n node[part] = { populate: {} };\n } else if (typeof current === 'object' && current !== null && !('populate' in current)) {\n (current as Record<string, unknown>).populate = {};\n }\n\n node = (node[part] as { populate: Record<string, unknown> }).populate;\n }\n }\n\n return root;\n};\n\n/** Returns a DB filter that matches the opposite publish status. */\nconst oppositePublishStatus = (publishedAt: unknown) =>\n publishedAt !== null ? { $null: true } : { $notNull: true };\n\nconst CONTENT_MANAGER_STATUS = {\n PUBLISHED: 'published',\n DRAFT: 'draft',\n MODIFIED: 'modified',\n};\n\n/**\n * Controls the metadata properties to be returned\n *\n * If `availableLocales` is set to `true` (default), the returned metadata will include\n * the available locales of the document for its current status.\n *\n * If `availableStatus` is set to `true` (default), the returned metadata will include\n * the available status of the document for its current locale.\n */\nexport interface GetMetadataOptions {\n availableLocales?: boolean;\n availableStatus?: boolean;\n}\n\n/**\n * Checks if the provided document version has been modified after all other versions.\n */\nconst getIsVersionLatestModification = (\n version?: DocumentVersion,\n otherVersion?: DocumentVersion\n): boolean => {\n if (!version || !version.updatedAt) {\n return false;\n }\n\n const versionUpdatedAt = version?.updatedAt ? new Date(version.updatedAt).getTime() : 0;\n\n const otherUpdatedAt = otherVersion?.updatedAt ? new Date(otherVersion.updatedAt).getTime() : 0;\n\n return versionUpdatedAt > otherUpdatedAt;\n};\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Returns available locales of a document for the current status.\n *\n * The result is sorted with the default locale (as defined by the i18n plugin)\n * at index 0 when present. This is the canonical-source invariant relied on by\n * `useDocument.getInitialFormValues` in the admin: when creating a new locale\n * draft, non-localized scalar/media/component/dynamic-zone values are inherited from\n * `availableLocales[0]`. Putting the default locale first means inheritance\n * stays predictable when sibling locales have drifted on non-localized fields\n * (which can happen because the server only syncs non-localized fields at\n * locale-creation time, not on subsequent updates — see\n * `copyNonLocalizedFields` in document-service/internationalization.ts).\n */\n async getAvailableLocales(\n uid: UID.ContentType,\n version: DocumentVersion,\n allVersions: DocumentVersion[]\n ) {\n // Group all versions by locale\n const versionsByLocale = groupBy(allVersions, 'locale');\n\n // Delete the current locale\n if (version.locale) {\n delete versionsByLocale[version.locale];\n }\n\n // For each locale, get the ones with the same status\n // There will not be a draft and a version counterpart if the content\n // type does not have draft and publish\n const model = strapi.getModel(uid);\n\n const mappingResult = await async.map(\n Object.values(versionsByLocale),\n async (localeVersions: DocumentVersion[]) => {\n if (!contentTypes.hasDraftAndPublish(model)) {\n return localeVersions[0];\n }\n\n const draftVersion = localeVersions.find((v) => v.publishedAt === null);\n const otherVersions = localeVersions.filter((v) => v.id !== draftVersion?.id);\n\n if (!draftVersion) {\n return;\n }\n\n return {\n ...draftVersion,\n status: this.getStatus(draftVersion, otherVersions as any),\n };\n }\n );\n\n const filtered = mappingResult.filter(Boolean) as unknown as NonNullable<\n DocumentMetadata['availableLocales']\n >;\n\n // Sort the default locale first so `availableLocales[0]` is the canonical\n // source for non-localized field inheritance in the admin. Without a\n // localization provider there is no default locale and the order is kept.\n let defaultLocaleCode: string | null | undefined = null;\n try {\n defaultLocaleCode = await strapi.localization.getDefaultLocale();\n } catch {\n // The provider (e.g. its locale store lookup) errored — leave order untouched.\n }\n\n // The provider may resolve `undefined` at runtime when no default locale is stored\n if (defaultLocaleCode === null || defaultLocaleCode === undefined || defaultLocaleCode === '') {\n return filtered as DocumentMetadata['availableLocales'];\n }\n\n // Stable partition: move the default locale entry to the front, keep the\n // rest of the order intact.\n const defaultEntries = filtered.filter((entry) => entry.locale === defaultLocaleCode);\n const otherEntries = filtered.filter((entry) => entry.locale !== defaultLocaleCode);\n\n return [...defaultEntries, ...otherEntries] as DocumentMetadata['availableLocales'];\n },\n\n /**\n * Returns available status of a document for the current locale\n */\n getAvailableStatus(version: DocumentVersion, allVersions: DocumentVersion[]) {\n // Find the other status of the document\n const status =\n version.publishedAt !== null\n ? CONTENT_MANAGER_STATUS.DRAFT\n : CONTENT_MANAGER_STATUS.PUBLISHED;\n\n // Get version that match the current locale and not match the current status\n const availableStatus = allVersions.find((v) => {\n const matchLocale = v.locale === version.locale;\n const matchStatus = status === 'published' ? v.publishedAt !== null : v.publishedAt === null;\n return matchLocale && matchStatus;\n });\n\n if (!availableStatus) return availableStatus;\n\n // Pick status fields (at fields, status, by fields), use lodash\n return pick(availableStatus, AVAILABLE_STATUS_FIELDS);\n },\n\n /**\n * Get the available status of many documents, useful for batch operations\n * @param uid\n * @param documents\n * @returns\n */\n async getManyAvailableStatus(uid: UID.ContentType, documents: DocumentVersion[]) {\n if (!documents.length) return [];\n\n // The status and locale of all documents should be the same\n const status = documents[0].publishedAt !== null ? 'published' : 'draft';\n const locales = documents.map((d) => d.locale).filter(Boolean);\n\n const where: Record<string, any> = {\n documentId: { $in: documents.map((d) => d.documentId).filter(Boolean) },\n publishedAt: { $null: status === 'published' },\n };\n\n // If there is any locale to filter (if i18n is enabled)\n if (locales.length === documents.length) {\n where.locale = { $in: locales };\n } else if (locales.length) {\n /*\n * The batch mixes localized and non-localized versions, which happens when a\n * content type holds rows with a locale while others have none — for instance\n * after i18n is disabled on it, or when a locale is sent to a non-localized\n * content type through the API.\n *\n * `locales` only holds the locales that are actually set, so filtering on it\n * alone would drop the counterparts of every version whose locale is null, and\n * those versions would be reported as drafts even though they are published.\n */\n where.$or = [{ locale: { $in: locales } }, { locale: { $null: true } }];\n }\n\n return strapi.db.query(uid).findMany({\n where,\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n });\n },\n\n getStatus(version: DocumentVersion, otherDocumentStatuses?: DocumentMetadata['availableStatus']) {\n let draftVersion: DocumentVersion | undefined;\n let publishedVersion: DocumentVersion | undefined;\n\n if (version.publishedAt) {\n publishedVersion = version;\n } else {\n draftVersion = version;\n }\n\n const otherVersion = otherDocumentStatuses?.at(0);\n if (otherVersion?.publishedAt) {\n publishedVersion = otherVersion;\n } else if (otherVersion) {\n draftVersion = otherVersion;\n }\n\n if (!draftVersion) return CONTENT_MANAGER_STATUS.PUBLISHED;\n if (!publishedVersion) return CONTENT_MANAGER_STATUS.DRAFT;\n\n /*\n * The document is modified if the draft version has been updated more\n * recently than the published version.\n */\n const isDraftModified = getIsVersionLatestModification(draftVersion, publishedVersion);\n return isDraftModified ? CONTENT_MANAGER_STATUS.MODIFIED : CONTENT_MANAGER_STATUS.PUBLISHED;\n },\n\n // TODO is it necessary to return metadata on every page of the CM\n // We could refactor this so the locales are only loaded when they're\n // needed. e.g. in the bulk locale action modal.\n async getMetadata(\n uid: UID.ContentType,\n version: DocumentVersion,\n { availableLocales = true, availableStatus = true }: GetMetadataOptions = {}\n ) {\n const model = strapi.getModel(uid);\n const hasDnP = contentTypes.hasDraftAndPublish(model);\n const isLocalized = strapi.localization.isLocalizedContentType(model);\n\n // Resolve once for all return paths — admin lock logic needs this even when\n // the current locale is excluded from `availableLocales`.\n let defaultLocale: string | null = null;\n if (isLocalized) {\n try {\n defaultLocale = (await strapi.localization.getDefaultLocale()) ?? null;\n } catch {\n defaultLocale = null;\n }\n }\n\n if (!availableLocales && !availableStatus) {\n // Nothing to compute.\n return {\n availableLocales: [],\n availableStatus: [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n if (!isLocalized && !hasDnP) {\n // If there are no locales and no draft/publish, there's only ever 1 version of any document.\n return {\n availableLocales: [],\n availableStatus: [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n\n const onlyStatusIsRelevant = hasDnP && (!isLocalized || !availableLocales);\n if (onlyStatusIsRelevant) {\n const otherVersion = availableStatus\n ? await strapi.db.query(uid).findOne({\n where: {\n documentId: version.documentId,\n ...(version.locale ? { locale: version.locale } : {}),\n publishedAt: oppositePublishStatus(version.publishedAt),\n },\n select: AVAILABLE_STATUS_SCALAR_FIELDS,\n populate: AVAILABLE_STATUS_POPULATE,\n })\n : null;\n return {\n availableLocales: [],\n availableStatus: otherVersion ? [pick(otherVersion, AVAILABLE_STATUS_FIELDS)] : [],\n defaultLocale,\n versions: [] as DocumentVersion[],\n };\n }\n\n // Full path for localized content types\n // TODO: Ignore publishedAt if availableStatus=false, and ignore locale if\n // i18n is disabled\n\n // Include non-translatable fields in availableLocales for i18n prefilling\n // (scalars + media + components + dynamic zones; relations stay server-filled).\n let nonLocalizedFields: string[] = [];\n let nonLocalizedMediaFields: string[] = [];\n // Without a localization provider there are no non-localized attributes.\n let nestedPopulate: Record<string, unknown> = {};\n try {\n if (model?.attributes !== undefined) {\n const allNonLocalized = strapi.localization.getNonLocalizedAttributes(model);\n // Get scalar and media attributes separately\n const scalarAttrs = getScalarAttributes(model);\n const mediaAttrs = getMediaAttributes(model);\n\n // Separate scalar fields (can be in fields array) from media fields (need to be populated)\n nonLocalizedFields = allNonLocalized.filter(\n (field: string) => field in model.attributes && scalarAttrs.includes(field)\n );\n nonLocalizedMediaFields = allNonLocalized.filter(\n (field: string) => field in model.attributes && mediaAttrs.includes(field)\n );\n\n const getNestedPopulate = strapi.localization.getNestedPopulateOfNonLocalizedAttributes;\n if (typeof getNestedPopulate === 'function') {\n const buildNestedPopulate = (\n schemaUID: UID.Schema,\n populate = dottedPathsToPopulate(getNestedPopulate(schemaUID))\n ): Record<string, unknown> => {\n const schema = strapi.getModel(schemaUID);\n\n return Object.fromEntries(\n Object.entries(populate).map(([field, value]) => {\n const attribute = schema?.attributes[field];\n\n if (attribute?.type === 'dynamiczone') {\n return [\n field,\n {\n on: attribute.components.reduce<\n Record<string, { populate: Record<string, unknown> }>\n >((acc, componentUID) => {\n acc[componentUID] = {\n populate: buildNestedPopulate(componentUID),\n };\n return acc;\n }, {}),\n },\n ];\n }\n\n if (\n attribute?.type === 'component' &&\n typeof value === 'object' &&\n value !== null &&\n 'populate' in value\n ) {\n return [\n field,\n {\n populate: buildNestedPopulate(\n attribute.component,\n (value as { populate: Record<string, unknown> }).populate\n ),\n },\n ];\n }\n\n return [field, value];\n })\n );\n };\n\n nestedPopulate = buildNestedPopulate(uid);\n } else {\n const componentAndDzFields = allNonLocalized.filter(\n (field: string) =>\n field in model.attributes &&\n (model.attributes[field]?.type === 'component' ||\n model.attributes[field]?.type === 'dynamiczone')\n );\n nestedPopulate = componentAndDzFields.reduce(\n (acc: Record<string, true>, field: string) => {\n acc[field] = true;\n return acc;\n },\n {}\n );\n }\n }\n } catch {\n // The provider errored — fall back to no prefilled non-localized fields\n }\n\n // Build populate object for non-localized media + nested component/DZ fields\n const mediaPopulate = nonLocalizedMediaFields.reduce(\n (acc, field) => {\n acc[field] = {\n populate: {\n folder: true,\n },\n };\n return acc;\n },\n {} as Record<string, { populate: { folder: boolean } } | true>\n );\n\n const params = {\n populate: {\n ...nestedPopulate,\n ...mediaPopulate,\n ...AVAILABLE_STATUS_POPULATE,\n },\n fields: [...new Set([...AVAILABLE_LOCALES_FIELDS, ...nonLocalizedFields])],\n filters: {\n documentId: version.documentId,\n },\n };\n\n const dbParams = strapi.get('query-params').transform(uid, params);\n const versions = await strapi.db.query(uid).findMany(dbParams);\n\n // TODO: Remove use of available locales and use localizations instead\n const availableLocalesResult = availableLocales\n ? await this.getAvailableLocales(uid, version, versions)\n : [];\n\n const availableStatusResult = availableStatus\n ? this.getAvailableStatus(version, versions)\n : null;\n\n return {\n availableLocales: availableLocalesResult,\n availableStatus: availableStatusResult ? [availableStatusResult] : [],\n defaultLocale,\n versions,\n };\n },\n\n /**\n * Returns associated metadata of a document:\n * - Available locales of the document for the current status\n * - Available status of the document for the current locale\n */\n async formatDocumentWithMetadata(\n uid: UID.ContentType,\n document: DocumentVersion,\n opts: GetMetadataOptions = {}\n ) {\n if (!document) {\n return {\n data: document,\n meta: {\n availableLocales: [],\n availableStatus: [],\n defaultLocale: null,\n },\n };\n }\n\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(strapi.getModel(uid));\n\n // Ignore available status if the content type does not have draft and publish\n if (!hasDraftAndPublish) {\n opts.availableStatus = false;\n }\n\n const { versions, ...meta } = await this.getMetadata(uid, document, opts);\n\n // Populate localization statuses\n if (document.localizations?.length) {\n document.localizations = document.localizations.map((d) => {\n // Find the counterpart version (same documentId + locale, opposite publishedAt) from\n // the already-fetched versions array, avoiding an extra DB query.\n const counterpart = versions.find(\n (v) =>\n v.documentId === d.documentId &&\n v.locale === d.locale &&\n (d.publishedAt === null) !== (v.publishedAt === null)\n );\n return {\n ...d,\n status: this.getStatus(d, counterpart ? [counterpart] : []),\n };\n });\n }\n\n return {\n data: {\n ...document,\n // Add status to the document only if draft and publish is enabled\n status: hasDraftAndPublish\n ? this.getStatus(document, meta.availableStatus as any)\n : undefined,\n },\n meta,\n };\n },\n});\n"],"names":["getScalarAttributes","getMediaAttributes","contentTypes","AVAILABLE_STATUS_SCALAR_FIELDS","AVAILABLE_STATUS_POPULATE","createdBy","select","updatedBy","AVAILABLE_STATUS_FIELDS","AVAILABLE_LOCALES_FIELDS","dottedPathsToPopulate","paths","root","path","parts","split","filter","Boolean","node","i","part","entries","isLast","length","undefined","current","populate","oppositePublishStatus","publishedAt","$null","$notNull","CONTENT_MANAGER_STATUS","PUBLISHED","DRAFT","MODIFIED","getIsVersionLatestModification","version","otherVersion","updatedAt","versionUpdatedAt","Date","getTime","otherUpdatedAt","strapi","getAvailableLocales","uid","allVersions","versionsByLocale","groupBy","locale","model","getModel","mappingResult","async","map","Object","values","localeVersions","hasDraftAndPublish","draftVersion","find","v","otherVersions","id","status","getStatus","filtered","defaultLocaleCode","localization","getDefaultLocale","defaultEntries","entry","otherEntries","getAvailableStatus","availableStatus","matchLocale","matchStatus","pick","getManyAvailableStatus","documents","locales","d","where","documentId","$in","$or","db","query","findMany","otherDocumentStatuses","publishedVersion","at","isDraftModified","getMetadata","availableLocales","hasDnP","isLocalized","isLocalizedContentType","defaultLocale","versions","onlyStatusIsRelevant","findOne","nonLocalizedFields","nonLocalizedMediaFields","nestedPopulate","attributes","allNonLocalized","getNonLocalizedAttributes","scalarAttrs","mediaAttrs","field","includes","getNestedPopulate","getNestedPopulateOfNonLocalizedAttributes","buildNestedPopulate","schemaUID","schema","fromEntries","value","attribute","type","on","components","reduce","acc","componentUID","component","componentAndDzFields","mediaPopulate","folder","params","fields","Set","filters","dbParams","get","transform","availableLocalesResult","availableStatusResult","formatDocumentWithMetadata","document","opts","data","meta","localizations","counterpart"],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ const ACTIONS = {
|
|
|
14
14
|
unpublish: 'plugin::content-manager.explorer.publish',
|
|
15
15
|
discard: 'plugin::content-manager.explorer.update'
|
|
16
16
|
};
|
|
17
|
+
const ACTION_NAMES = Object.keys(ACTIONS);
|
|
17
18
|
const createPermissionChecker = (strapi)=>({ userAbility, model })=>{
|
|
18
19
|
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
|
19
20
|
ability: userAbility,
|
|
@@ -88,17 +89,28 @@ const createPermissionChecker = (strapi)=>({ userAbility, model })=>{
|
|
|
88
89
|
};
|
|
89
90
|
const sanitizeCreateInput = (data)=>sanitizeInput(ACTIONS.create, data);
|
|
90
91
|
const sanitizeUpdateInput = (entity)=>(data)=>sanitizeInput(ACTIONS.update, data, entity);
|
|
91
|
-
const buildPermissionQuery = (query, action
|
|
92
|
+
const buildPermissionQuery = (query, action)=>{
|
|
92
93
|
return permissionsManager.addPermissionsQueryTo(query, action);
|
|
93
94
|
};
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Sanitizes the query with the rules of the action, then adds the action's permission
|
|
97
|
+
* conditions to it. The action defaults to read.
|
|
98
|
+
* The action can also be given as a plain string, the v4 signature
|
|
99
|
+
* `sanitizedQuery(query, actionUID)`, which untyped plugin code may still use.
|
|
100
|
+
*/ const sanitizedQueryForAction = (query, options = {})=>{
|
|
101
|
+
const action = typeof options === 'string' ? options : options.action ?? ACTIONS.read;
|
|
102
|
+
return strapiUtils.async.pipe((q)=>sanitizeQuery(q, {
|
|
103
|
+
action
|
|
104
|
+
}), (q)=>buildPermissionQuery(q, action))(query);
|
|
96
105
|
};
|
|
97
|
-
// Sanitized queries shortcuts
|
|
98
|
-
Object.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
// Sanitized queries shortcuts, e.g. `sanitizedQuery.update(query)`
|
|
107
|
+
const sanitizedQueryShortcuts = Object.fromEntries(ACTION_NAMES.map((name)=>[
|
|
108
|
+
name,
|
|
109
|
+
(query)=>sanitizedQueryForAction(query, {
|
|
110
|
+
action: ACTIONS[name]
|
|
111
|
+
})
|
|
112
|
+
]));
|
|
113
|
+
const sanitizedQuery = Object.assign(sanitizedQueryForAction, sanitizedQueryShortcuts);
|
|
102
114
|
// Permission utils shortcuts
|
|
103
115
|
Object.keys(ACTIONS).forEach((action)=>{
|
|
104
116
|
// @ts-expect-error TODO
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission-checker.js","sources":["../../../server/src/services/permission-checker.ts"],"sourcesContent":["import type { Ability } from '@casl/ability';\nimport { async } from '@strapi/utils';\nimport { isEmpty } from 'lodash';\n\nimport type { Core, UID, Modules } from '@strapi/types';\n\nexport const ACTIONS = {\n read: 'plugin::content-manager.explorer.read',\n create: 'plugin::content-manager.explorer.create',\n update: 'plugin::content-manager.explorer.update',\n delete: 'plugin::content-manager.explorer.delete',\n publish: 'plugin::content-manager.explorer.publish',\n unpublish: 'plugin::content-manager.explorer.publish',\n discard: 'plugin::content-manager.explorer.update',\n} as const;\n\ntype Entity = Modules.EntityService.Result<UID.ContentType>;\ntype Query = {\n page?: string;\n pageSize?: string;\n sort?: string;\n};\n\nconst createPermissionChecker =\n (strapi: Core.Strapi) =>\n ({ userAbility, model }: { userAbility: Ability; model: string }) => {\n const permissionsManager = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n model,\n });\n\n const { actionProvider } = strapi.service('admin::permission');\n\n const toSubject = (entity?: Entity) => {\n return entity ? permissionsManager.toSubject(entity, model) : model;\n };\n\n const can = (action: string, entity: Entity | undefined, field: string) => {\n const subject = toSubject(entity);\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n\n return (\n // Test the original action to see if it passes\n userAbility.can(action, subject, field) ||\n // Else try every known alias if at least one of them succeed, then the user \"can\"\n aliases.some((alias) => userAbility.can(alias, subject, field))\n );\n };\n\n const cannot = (action: string, entity: Entity | undefined, field: string) => {\n const subject = toSubject(entity);\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n\n return (\n // Test both the original action\n userAbility.cannot(action, subject, field) &&\n // and every known alias, if all of them fail (cannot), then the user truly \"cannot\"\n aliases.every((alias) => userAbility.cannot(alias, subject, field))\n );\n };\n\n const sanitizeOutput = (data: Entity, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });\n };\n\n const getRulesForAction = (action: string) => {\n if (typeof userAbility.rulesFor !== 'function') {\n return [];\n }\n\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n const actions = [action, ...aliases];\n\n return actions.flatMap((actionName) => userAbility.rulesFor(actionName, model));\n };\n\n // Tell callers if we need the full entity to check access\n const requiresEntity = (action: string) => {\n if (typeof userAbility.rulesFor !== 'function') {\n return true;\n }\n\n const rules = getRulesForAction(action);\n\n return rules.some((rule: any) => rule.conditions && !isEmpty(rule.conditions));\n };\n\n const sanitizeQuery = (query: Query, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.sanitizeQuery(query, { subject: model, action });\n };\n\n const sanitizeInput = (action: string, data: any, entity?: Entity) => {\n return permissionsManager.sanitizeInput(data, {\n subject: entity ? toSubject(entity) : model,\n action,\n });\n };\n\n const validateQuery = (query: Query, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.validateQuery(query, { subject: model, action });\n };\n\n const validateInput = (action: string, data: any, entity?: Entity) => {\n return permissionsManager.validateInput(data, {\n subject: entity ? toSubject(entity) : model,\n action,\n });\n };\n\n const sanitizeCreateInput = (data: any) => sanitizeInput(ACTIONS.create, data);\n const sanitizeUpdateInput = (entity: Entity) => (data: any) =>\n sanitizeInput(ACTIONS.update, data, entity);\n\n const buildPermissionQuery = (query: Query, action: { action?: string } = {}) => {\n return permissionsManager.addPermissionsQueryTo(query, action);\n };\n\n const sanitizedQuery = (query: Query, action: { action?: string } = {}) => {\n return async.pipe(\n (q: Query) => sanitizeQuery(q, action),\n (q: Query) => buildPermissionQuery(q, action)\n )(query);\n };\n\n // Sanitized queries shortcuts\n Object.keys(ACTIONS).forEach((action) => {\n // @ts-expect-error TODO\n sanitizedQuery[action] = (query: Query) => sanitizedQuery(query, ACTIONS[action]);\n });\n\n // Permission utils shortcuts\n Object.keys(ACTIONS).forEach((action) => {\n // @ts-expect-error TODO\n can[action] = (...args: any) => can(ACTIONS[action], ...args);\n // @ts-expect-error TODO\n cannot[action] = (...args: any) => cannot(ACTIONS[action], ...args);\n // @ts-expect-error TODO\n requiresEntity[action] = () => requiresEntity(ACTIONS[action]);\n });\n\n return {\n // Permission utils\n can, // check if you have the permission\n cannot, // check if you don't have the permission\n requiresEntity, // check if entity data is needed for permission evaluation\n // Sanitizers\n sanitizeOutput,\n sanitizeQuery,\n sanitizeCreateInput,\n sanitizeUpdateInput,\n // Validators\n validateQuery,\n validateInput,\n // Queries Builder\n sanitizedQuery,\n };\n };\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n create: createPermissionChecker(strapi),\n});\n"],"names":["ACTIONS","read","create","update","delete","publish","unpublish","discard","createPermissionChecker","strapi","userAbility","model","permissionsManager","service","createPermissionsManager","ability","actionProvider","toSubject","entity","can","action","field","subject","aliases","unstable_aliases","some","alias","cannot","every","sanitizeOutput","data","getRulesForAction","rulesFor","actions","flatMap","actionName","requiresEntity","rules","rule","conditions","isEmpty","sanitizeQuery","query","sanitizeInput","validateQuery","validateInput","sanitizeCreateInput","sanitizeUpdateInput","buildPermissionQuery","addPermissionsQueryTo","sanitizedQuery","async","pipe","q","Object","keys","forEach","args"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"permission-checker.js","sources":["../../../server/src/services/permission-checker.ts"],"sourcesContent":["import type { Ability } from '@casl/ability';\nimport { async } from '@strapi/utils';\nimport { isEmpty } from 'lodash';\n\nimport type { Core, UID, Modules } from '@strapi/types';\n\nexport const ACTIONS = {\n read: 'plugin::content-manager.explorer.read',\n create: 'plugin::content-manager.explorer.create',\n update: 'plugin::content-manager.explorer.update',\n delete: 'plugin::content-manager.explorer.delete',\n publish: 'plugin::content-manager.explorer.publish',\n unpublish: 'plugin::content-manager.explorer.publish',\n discard: 'plugin::content-manager.explorer.update',\n} as const;\n\ntype ActionName = keyof typeof ACTIONS;\n\nconst ACTION_NAMES = Object.keys(ACTIONS) as ActionName[];\n\ntype SanitizedQueryOptions = { action?: string } | string;\n\ntype Entity = Modules.EntityService.Result<UID.ContentType>;\ntype Query = {\n page?: string;\n pageSize?: string;\n sort?: string;\n};\n\nconst createPermissionChecker =\n (strapi: Core.Strapi) =>\n ({ userAbility, model }: { userAbility: Ability; model: string }) => {\n const permissionsManager = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n model,\n });\n\n const { actionProvider } = strapi.service('admin::permission');\n\n const toSubject = (entity?: Entity) => {\n return entity ? permissionsManager.toSubject(entity, model) : model;\n };\n\n const can = (action: string, entity?: Entity, field?: string) => {\n const subject = toSubject(entity);\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n\n return (\n // Test the original action to see if it passes\n userAbility.can(action, subject, field) ||\n // Else try every known alias if at least one of them succeed, then the user \"can\"\n aliases.some((alias) => userAbility.can(alias, subject, field))\n );\n };\n\n const cannot = (action: string, entity?: Entity, field?: string) => {\n const subject = toSubject(entity);\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n\n return (\n // Test both the original action\n userAbility.cannot(action, subject, field) &&\n // and every known alias, if all of them fail (cannot), then the user truly \"cannot\"\n aliases.every((alias) => userAbility.cannot(alias, subject, field))\n );\n };\n\n const sanitizeOutput = (data: Entity, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.sanitizeOutput(data, { subject: toSubject(data), action });\n };\n\n const getRulesForAction = (action: string) => {\n if (typeof userAbility.rulesFor !== 'function') {\n return [];\n }\n\n const aliases = actionProvider.unstable_aliases(action, model) as string[];\n const actions = [action, ...aliases];\n\n return actions.flatMap((actionName) => userAbility.rulesFor(actionName, model));\n };\n\n // Tell callers if we need the full entity to check access\n const requiresEntity = (action: string) => {\n if (typeof userAbility.rulesFor !== 'function') {\n return true;\n }\n\n const rules = getRulesForAction(action);\n\n return rules.some((rule: any) => rule.conditions && !isEmpty(rule.conditions));\n };\n\n const sanitizeQuery = (query: Query, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.sanitizeQuery(query, { subject: model, action });\n };\n\n const sanitizeInput = (action: string, data: any, entity?: Entity) => {\n return permissionsManager.sanitizeInput(data, {\n subject: entity ? toSubject(entity) : model,\n action,\n });\n };\n\n const validateQuery = (query: Query, { action = ACTIONS.read }: { action?: string } = {}) => {\n return permissionsManager.validateQuery(query, { subject: model, action });\n };\n\n const validateInput = (action: string, data: any, entity?: Entity) => {\n return permissionsManager.validateInput(data, {\n subject: entity ? toSubject(entity) : model,\n action,\n });\n };\n\n const sanitizeCreateInput = (data: any) => sanitizeInput(ACTIONS.create, data);\n const sanitizeUpdateInput = (entity: Entity) => (data: any) =>\n sanitizeInput(ACTIONS.update, data, entity);\n\n const buildPermissionQuery = (query: Query, action: string) => {\n return permissionsManager.addPermissionsQueryTo(query, action);\n };\n\n /**\n * Sanitizes the query with the rules of the action, then adds the action's permission\n * conditions to it. The action defaults to read.\n * The action can also be given as a plain string, the v4 signature\n * `sanitizedQuery(query, actionUID)`, which untyped plugin code may still use.\n */\n const sanitizedQueryForAction = (query: Query, options: SanitizedQueryOptions = {}) => {\n const action = typeof options === 'string' ? options : (options.action ?? ACTIONS.read);\n\n return async.pipe(\n (q: Query) => sanitizeQuery(q, { action }),\n (q: Query) => buildPermissionQuery(q, action)\n )(query);\n };\n\n // Sanitized queries shortcuts, e.g. `sanitizedQuery.update(query)`\n const sanitizedQueryShortcuts = Object.fromEntries(\n ACTION_NAMES.map((name) => [\n name,\n (query: Query) => sanitizedQueryForAction(query, { action: ACTIONS[name] }),\n ])\n ) as Record<ActionName, (query: Query) => ReturnType<typeof sanitizedQueryForAction>>;\n\n const sanitizedQuery = Object.assign(sanitizedQueryForAction, sanitizedQueryShortcuts);\n\n // Permission utils shortcuts\n Object.keys(ACTIONS).forEach((action) => {\n // @ts-expect-error TODO\n can[action] = (...args: any) => can(ACTIONS[action], ...args);\n // @ts-expect-error TODO\n cannot[action] = (...args: any) => cannot(ACTIONS[action], ...args);\n // @ts-expect-error TODO\n requiresEntity[action] = () => requiresEntity(ACTIONS[action]);\n });\n\n return {\n // Permission utils\n can, // check if you have the permission\n cannot, // check if you don't have the permission\n requiresEntity, // check if entity data is needed for permission evaluation\n // Sanitizers\n sanitizeOutput,\n sanitizeQuery,\n sanitizeCreateInput,\n sanitizeUpdateInput,\n // Validators\n validateQuery,\n validateInput,\n // Queries Builder\n sanitizedQuery,\n };\n };\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n create: createPermissionChecker(strapi),\n});\n"],"names":["ACTIONS","read","create","update","delete","publish","unpublish","discard","ACTION_NAMES","Object","keys","createPermissionChecker","strapi","userAbility","model","permissionsManager","service","createPermissionsManager","ability","actionProvider","toSubject","entity","can","action","field","subject","aliases","unstable_aliases","some","alias","cannot","every","sanitizeOutput","data","getRulesForAction","rulesFor","actions","flatMap","actionName","requiresEntity","rules","rule","conditions","isEmpty","sanitizeQuery","query","sanitizeInput","validateQuery","validateInput","sanitizeCreateInput","sanitizeUpdateInput","buildPermissionQuery","addPermissionsQueryTo","sanitizedQueryForAction","options","async","pipe","q","sanitizedQueryShortcuts","fromEntries","map","name","sanitizedQuery","assign","forEach","args"],"mappings":"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"}
|