@strapi/content-manager 0.0.0-next.daa3d4c4db6322f58233f0ccb757d80dbd1b48e9 → 0.0.0-next.df0d99415fc543d9747f3946fd7d1a4c39052b95
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 +300 -204
- package/dist/admin/components/ConfigurationForm/Fields.js.map +1 -1
- package/dist/admin/components/ConfigurationForm/Fields.mjs +304 -209
- package/dist/admin/components/ConfigurationForm/Fields.mjs.map +1 -1
- package/dist/admin/components/LeftMenu.js +34 -30
- package/dist/admin/components/LeftMenu.js.map +1 -1
- package/dist/admin/components/LeftMenu.mjs +36 -32
- package/dist/admin/components/LeftMenu.mjs.map +1 -1
- package/dist/admin/components/Widgets.js +253 -0
- package/dist/admin/components/Widgets.js.map +1 -1
- package/dist/admin/components/Widgets.mjs +236 -3
- package/dist/admin/components/Widgets.mjs.map +1 -1
- package/dist/admin/history/components/VersionContent.js +24 -3
- package/dist/admin/history/components/VersionContent.js.map +1 -1
- package/dist/admin/history/components/VersionContent.mjs +25 -4
- package/dist/admin/history/components/VersionContent.mjs.map +1 -1
- package/dist/admin/history/components/VersionHeader.js +6 -0
- package/dist/admin/history/components/VersionHeader.js.map +1 -1
- package/dist/admin/history/components/VersionHeader.mjs +7 -1
- package/dist/admin/history/components/VersionHeader.mjs.map +1 -1
- package/dist/admin/hooks/useDocumentActions.js +7 -6
- package/dist/admin/hooks/useDocumentActions.js.map +1 -1
- package/dist/admin/hooks/useDocumentActions.mjs +8 -7
- package/dist/admin/hooks/useDocumentActions.mjs.map +1 -1
- package/dist/admin/index.js +47 -8
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +47 -9
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/layout.js +1 -27
- package/dist/admin/layout.js.map +1 -1
- package/dist/admin/layout.mjs +2 -9
- package/dist/admin/layout.mjs.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.js +99 -75
- package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.mjs +101 -77
- package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.js +83 -70
- package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.mjs +85 -72
- package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +12 -15
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +12 -15
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js +54 -14
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs +55 -15
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js +21 -35
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs +21 -35
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js +12 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs +13 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js +13 -2
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs +14 -3
- package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +18 -5
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +20 -7
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +158 -106
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +161 -109
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/UID.js +4 -2
- package/dist/admin/pages/EditView/components/FormInputs/UID.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/UID.mjs +4 -2
- package/dist/admin/pages/EditView/components/FormInputs/UID.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.js +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.mjs +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js +86 -118
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs +86 -118
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.js +47 -27
- package/dist/admin/pages/EditView/components/FormLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.mjs +47 -27
- package/dist/admin/pages/EditView/components/FormLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/utils/data.js +103 -0
- package/dist/admin/pages/EditView/utils/data.js.map +1 -1
- package/dist/admin/pages/EditView/utils/data.mjs +103 -1
- package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +227 -132
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +229 -134
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.js +2 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.js.map +1 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.mjs +2 -1
- package/dist/admin/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.js +4 -1
- package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.mjs +4 -1
- package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/TableActions.js +13 -3
- package/dist/admin/pages/ListView/components/TableActions.js.map +1 -1
- package/dist/admin/pages/ListView/components/TableActions.mjs +13 -3
- package/dist/admin/pages/ListView/components/TableActions.mjs.map +1 -1
- package/dist/admin/preview/components/PreviewSidePanel.js +31 -4
- package/dist/admin/preview/components/PreviewSidePanel.js.map +1 -1
- package/dist/admin/preview/components/PreviewSidePanel.mjs +32 -5
- package/dist/admin/preview/components/PreviewSidePanel.mjs.map +1 -1
- package/dist/admin/preview/pages/Preview.js +101 -35
- package/dist/admin/preview/pages/Preview.js.map +1 -1
- package/dist/admin/preview/pages/Preview.mjs +102 -36
- package/dist/admin/preview/pages/Preview.mjs.map +1 -1
- package/dist/admin/services/api.js +3 -1
- package/dist/admin/services/api.js.map +1 -1
- package/dist/admin/services/api.mjs +3 -1
- package/dist/admin/services/api.mjs.map +1 -1
- package/dist/admin/services/documents.js +32 -16
- package/dist/admin/services/documents.js.map +1 -1
- package/dist/admin/services/documents.mjs +32 -16
- package/dist/admin/services/documents.mjs.map +1 -1
- package/dist/admin/services/homepage.js +11 -2
- package/dist/admin/services/homepage.js.map +1 -1
- package/dist/admin/services/homepage.mjs +11 -3
- package/dist/admin/services/homepage.mjs.map +1 -1
- package/dist/admin/src/components/ConfigurationForm/Fields.d.ts +6 -4
- package/dist/admin/src/components/Widgets.d.ts +2 -1
- package/dist/admin/src/exports.d.ts +1 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +7 -8
- package/dist/admin/src/pages/EditView/utils/data.d.ts +19 -1
- package/dist/admin/src/preview/services/preview.d.ts +1 -1
- 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 +23 -17
- package/dist/admin/src/services/homepage.d.ts +6 -2
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +1 -0
- package/dist/admin/translations/en.json.js +7 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +7 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +5 -2
- package/dist/admin/translations/es.json.js.map +1 -1
- package/dist/admin/translations/es.json.mjs +5 -2
- package/dist/admin/translations/es.json.mjs.map +1 -1
- package/dist/admin/translations/fr.json.js +10 -2
- package/dist/admin/translations/fr.json.js.map +1 -1
- package/dist/admin/translations/fr.json.mjs +10 -2
- package/dist/admin/translations/fr.json.mjs.map +1 -1
- package/dist/admin/utils/validation.js +19 -7
- package/dist/admin/utils/validation.js.map +1 -1
- package/dist/admin/utils/validation.mjs +19 -7
- package/dist/admin/utils/validation.mjs.map +1 -1
- package/dist/server/controllers/content-types.js +11 -1
- package/dist/server/controllers/content-types.js.map +1 -1
- package/dist/server/controllers/content-types.mjs +11 -1
- package/dist/server/controllers/content-types.mjs.map +1 -1
- package/dist/server/controllers/relations.js +2 -2
- package/dist/server/controllers/relations.js.map +1 -1
- package/dist/server/controllers/relations.mjs +2 -2
- package/dist/server/controllers/relations.mjs.map +1 -1
- package/dist/server/controllers/validation/index.js +14 -2
- package/dist/server/controllers/validation/index.js.map +1 -1
- package/dist/server/controllers/validation/index.mjs +14 -2
- package/dist/server/controllers/validation/index.mjs.map +1 -1
- package/dist/server/history/services/lifecycles.js +23 -19
- package/dist/server/history/services/lifecycles.js.map +1 -1
- package/dist/server/history/services/lifecycles.mjs +23 -19
- package/dist/server/history/services/lifecycles.mjs.map +1 -1
- package/dist/server/homepage/controllers/homepage.js +5 -0
- package/dist/server/homepage/controllers/homepage.js.map +1 -1
- package/dist/server/homepage/controllers/homepage.mjs +5 -0
- package/dist/server/homepage/controllers/homepage.mjs.map +1 -1
- package/dist/server/homepage/routes/homepage.js +11 -0
- package/dist/server/homepage/routes/homepage.js.map +1 -1
- package/dist/server/homepage/routes/homepage.mjs +11 -0
- package/dist/server/homepage/routes/homepage.mjs.map +1 -1
- package/dist/server/homepage/services/homepage.js +86 -46
- package/dist/server/homepage/services/homepage.js.map +1 -1
- package/dist/server/homepage/services/homepage.mjs +86 -46
- package/dist/server/homepage/services/homepage.mjs.map +1 -1
- package/dist/server/preview/services/preview-config.js +5 -1
- package/dist/server/preview/services/preview-config.js.map +1 -1
- package/dist/server/preview/services/preview-config.mjs +5 -1
- package/dist/server/preview/services/preview-config.mjs.map +1 -1
- package/dist/server/preview/services/preview.js +4 -0
- package/dist/server/preview/services/preview.js.map +1 -1
- package/dist/server/preview/services/preview.mjs +4 -0
- package/dist/server/preview/services/preview.mjs.map +1 -1
- package/dist/server/services/data-mapper.js +4 -1
- package/dist/server/services/data-mapper.js.map +1 -1
- package/dist/server/services/data-mapper.mjs +4 -1
- package/dist/server/services/data-mapper.mjs.map +1 -1
- package/dist/server/services/document-manager.js +8 -1
- package/dist/server/services/document-manager.js.map +1 -1
- package/dist/server/services/document-manager.mjs +8 -1
- package/dist/server/services/document-manager.mjs.map +1 -1
- package/dist/server/services/document-metadata.js +3 -1
- package/dist/server/services/document-metadata.js.map +1 -1
- package/dist/server/services/document-metadata.mjs +3 -1
- package/dist/server/services/document-metadata.mjs.map +1 -1
- package/dist/server/services/utils/configuration/attributes.js +1 -1
- package/dist/server/services/utils/configuration/attributes.js.map +1 -1
- package/dist/server/services/utils/configuration/attributes.mjs +1 -1
- package/dist/server/services/utils/configuration/attributes.mjs.map +1 -1
- package/dist/server/services/utils/configuration/layouts.js +1 -1
- package/dist/server/services/utils/configuration/layouts.js.map +1 -1
- package/dist/server/services/utils/configuration/layouts.mjs +1 -1
- package/dist/server/services/utils/configuration/layouts.mjs.map +1 -1
- package/dist/server/services/utils/configuration/metadatas.js +8 -0
- package/dist/server/services/utils/configuration/metadatas.js.map +1 -1
- package/dist/server/services/utils/configuration/metadatas.mjs +8 -0
- package/dist/server/services/utils/configuration/metadatas.mjs.map +1 -1
- package/dist/server/services/utils/populate.js +11 -0
- package/dist/server/services/utils/populate.js.map +1 -1
- package/dist/server/services/utils/populate.mjs +11 -0
- package/dist/server/services/utils/populate.mjs.map +1 -1
- package/dist/server/src/controllers/content-types.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/index.d.ts +6 -1
- package/dist/server/src/controllers/validation/index.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/homepage/controllers/homepage.d.ts +2 -1
- package/dist/server/src/homepage/controllers/homepage.d.ts.map +1 -1
- package/dist/server/src/homepage/index.d.ts +7 -0
- package/dist/server/src/homepage/index.d.ts.map +1 -1
- package/dist/server/src/homepage/routes/homepage.d.ts.map +1 -1
- package/dist/server/src/homepage/services/homepage.d.ts +4 -1
- package/dist/server/src/homepage/services/homepage.d.ts.map +1 -1
- package/dist/server/src/homepage/services/index.d.ts +7 -0
- package/dist/server/src/homepage/services/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +8 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/preview/services/index.d.ts +1 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -1
- package/dist/server/src/preview/services/preview-config.d.ts +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -1
- package/dist/server/src/preview/services/preview.d.ts.map +1 -1
- package/dist/server/src/preview/utils.d.ts +1 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -1
- package/dist/server/src/services/data-mapper.d.ts +1 -0
- package/dist/server/src/services/data-mapper.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.map +1 -1
- package/dist/server/src/services/index.d.ts +8 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/metadatas.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +0 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/homepage.d.ts +13 -0
- package/dist/shared/contracts/homepage.d.ts.map +1 -1
- package/package.json +11 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycles.js","sources":["../../../../server/src/history/services/lifecycles.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport { omit, castArray } from 'lodash/fp';\n\nimport { scheduleJob } from 'node-schedule';\n\nimport { getService } from '../utils';\nimport { FIELDS_TO_IGNORE, HISTORY_VERSION_UID } from '../constants';\n\nimport type { CreateHistoryVersion } from '../../../../shared/contracts/history-versions';\nimport { createServiceUtils } from './utils';\n\n/**\n * Filters out actions that should not create a history version.\n */\nconst shouldCreateHistoryVersion = (\n context: Modules.Documents.Middleware.Context\n): context is Modules.Documents.Middleware.Context & {\n action: 'create' | 'update' | 'clone' | 'publish' | 'unpublish' | 'discardDraft';\n contentType: UID.CollectionType;\n} => {\n // Ignore requests that are not related to the content manager\n if (!strapi.requestContext.get()?.request.url.startsWith('/content-manager')) {\n return false;\n }\n\n // NOTE: cannot do type narrowing with array includes\n if (\n context.action !== 'create' &&\n context.action !== 'update' &&\n context.action !== 'clone' &&\n context.action !== 'publish' &&\n context.action !== 'unpublish' &&\n context.action !== 'discardDraft'\n ) {\n return false;\n }\n\n /**\n * When a document is published, the draft version of the document is also updated.\n * It creates confusion for users because they see two history versions each publish action.\n * To avoid this, we silence the update action during a publish request,\n * so that they only see the published version of the document in the history.\n */\n if (\n context.action === 'update' &&\n strapi.requestContext.get()?.request.url.endsWith('/actions/publish')\n ) {\n return false;\n }\n\n // Ignore content types not created by the user\n if (!context.contentType.uid.startsWith('api::')) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Returns the content type schema (and its components schemas).\n * Used to determine if changes were made in the content type builder since a history version was created.\n * And therefore which fields can be restored and which cannot.\n */\nconst getSchemas = (uid: UID.CollectionType) => {\n const attributesSchema = strapi.getModel(uid).attributes;\n\n // TODO: Handle nested components\n const componentsSchemas = Object.keys(attributesSchema).reduce(\n (currentComponentSchemas, key) => {\n const fieldSchema = attributesSchema[key];\n\n if (fieldSchema.type === 'component') {\n const componentSchema = strapi.getModel(fieldSchema.component).attributes;\n return {\n ...currentComponentSchemas,\n [fieldSchema.component]: componentSchema,\n };\n }\n\n // Ignore anything that's not a component\n return currentComponentSchemas;\n },\n {} as CreateHistoryVersion['componentsSchemas']\n );\n\n return {\n schema: omit(FIELDS_TO_IGNORE, attributesSchema) as CreateHistoryVersion['schema'],\n componentsSchemas,\n };\n};\n\nconst createLifecyclesService = ({ strapi }: { strapi: Core.Strapi }) => {\n const state: {\n deleteExpiredJob: ReturnType<typeof scheduleJob> | null;\n isInitialized: boolean;\n } = {\n deleteExpiredJob: null,\n isInitialized: false,\n };\n\n const serviceUtils = createServiceUtils({ strapi });\n\n return {\n async bootstrap() {\n // Prevent initializing the service twice\n if (state.isInitialized) {\n return;\n }\n\n strapi.documents.use(async (context, next) => {\n const result = (await next()) as any;\n\n if (!shouldCreateHistoryVersion(context)) {\n return result;\n }\n\n // On create/clone actions, the documentId is not available before creating the action is executed\n const documentId =\n context.action === 'create' || context.action === 'clone'\n ? result.documentId\n : context.params.documentId;\n\n // Apply default locale if not available in the request\n const defaultLocale = await serviceUtils.getDefaultLocale();\n const locales = castArray(context.params?.locale || defaultLocale);\n if (!locales.length) {\n return result;\n }\n\n // All schemas related to the content type\n const uid = context.contentType.uid;\n const schemas = getSchemas(uid);\n const model = strapi.getModel(uid);\n\n const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);\n\n // Find all affected entries\n const localeEntries = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n ...(isLocalizedContentType ? { locale: { $in: locales } } : {}),\n ...(contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])\n ? { publishedAt: null }\n : {}),\n },\n populate: serviceUtils.getDeepPopulate(uid, true /* use database syntax */),\n });\n\n await strapi.db.transaction(async ({ onCommit }) => {\n // .createVersion() is executed asynchronously,\n // onCommit prevents creating a history version\n // when the transaction has already been committed\n onCommit(async () => {\n for (const entry of localeEntries) {\n const status = await serviceUtils.getVersionStatus(uid, entry);\n\n await getService(strapi, 'history').createVersion({\n contentType: uid,\n data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,\n relatedDocumentId: documentId,\n locale: entry.locale,\n status,\n ...schemas,\n });\n }\n });\n });\n\n return result;\n });\n\n // Schedule a job to delete expired history versions every day at midnight\n state.deleteExpiredJob = scheduleJob('historyDaily', '0 0 * * *', () => {\n const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;\n const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);\n\n strapi.db\n .query(HISTORY_VERSION_UID)\n .deleteMany({\n where: {\n created_at: {\n $lt: expirationDate,\n },\n },\n })\n .catch((error) => {\n if (error instanceof Error) {\n strapi.log.error('Error deleting expired history versions', error.message);\n }\n });\n });\n\n state.isInitialized = true;\n },\n\n async destroy() {\n if (state.deleteExpiredJob) {\n state.deleteExpiredJob.cancel();\n }\n },\n };\n};\n\nexport { createLifecyclesService };\n"],"names":["shouldCreateHistoryVersion","context","strapi","requestContext","get","request","url","startsWith","action","endsWith","contentType","uid","getSchemas","attributesSchema","getModel","attributes","componentsSchemas","Object","keys","reduce","currentComponentSchemas","key","fieldSchema","type","componentSchema","component","schema","omit","FIELDS_TO_IGNORE","createLifecyclesService","state","deleteExpiredJob","isInitialized","serviceUtils","createServiceUtils","bootstrap","documents","use","next","result","documentId","params","defaultLocale","getDefaultLocale","locales","castArray","locale","length","schemas","model","isLocalizedContentType","localeEntries","db","query","findMany","where","$in","contentTypes","hasDraftAndPublish","publishedAt","populate","getDeepPopulate","transaction","onCommit","entry","status","getVersionStatus","getService","createVersion","data","relatedDocumentId","scheduleJob","retentionDaysInMilliseconds","getRetentionDays","expirationDate","Date","now","HISTORY_VERSION_UID","deleteMany","created_at","$lt","catch","error","Error","log","message","destroy","cancel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecycles.js","sources":["../../../../server/src/history/services/lifecycles.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport { omit, castArray } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { FIELDS_TO_IGNORE, HISTORY_VERSION_UID } from '../constants';\n\nimport type { CreateHistoryVersion } from '../../../../shared/contracts/history-versions';\nimport { createServiceUtils } from './utils';\n\n/**\n * Filters out actions that should not create a history version.\n */\nconst shouldCreateHistoryVersion = (\n context: Modules.Documents.Middleware.Context\n): context is Modules.Documents.Middleware.Context & {\n action: 'create' | 'update' | 'clone' | 'publish' | 'unpublish' | 'discardDraft';\n contentType: UID.CollectionType;\n} => {\n // Ignore requests that are not related to the content manager\n if (!strapi.requestContext.get()?.request.url.startsWith('/content-manager')) {\n return false;\n }\n\n // NOTE: cannot do type narrowing with array includes\n if (\n context.action !== 'create' &&\n context.action !== 'update' &&\n context.action !== 'clone' &&\n context.action !== 'publish' &&\n context.action !== 'unpublish' &&\n context.action !== 'discardDraft'\n ) {\n return false;\n }\n\n /**\n * When a document is published, the draft version of the document is also updated.\n * It creates confusion for users because they see two history versions each publish action.\n * To avoid this, we silence the update action during a publish request,\n * so that they only see the published version of the document in the history.\n */\n if (\n context.action === 'update' &&\n strapi.requestContext.get()?.request.url.endsWith('/actions/publish')\n ) {\n return false;\n }\n\n // Ignore content types not created by the user\n if (!context.contentType.uid.startsWith('api::')) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Returns the content type schema (and its components schemas).\n * Used to determine if changes were made in the content type builder since a history version was created.\n * And therefore which fields can be restored and which cannot.\n */\nconst getSchemas = (uid: UID.CollectionType) => {\n const attributesSchema = strapi.getModel(uid).attributes;\n\n // TODO: Handle nested components\n const componentsSchemas = Object.keys(attributesSchema).reduce(\n (currentComponentSchemas, key) => {\n const fieldSchema = attributesSchema[key];\n\n if (fieldSchema.type === 'component') {\n const componentSchema = strapi.getModel(fieldSchema.component).attributes;\n return {\n ...currentComponentSchemas,\n [fieldSchema.component]: componentSchema,\n };\n }\n\n // Ignore anything that's not a component\n return currentComponentSchemas;\n },\n {} as CreateHistoryVersion['componentsSchemas']\n );\n\n return {\n schema: omit(FIELDS_TO_IGNORE, attributesSchema) as CreateHistoryVersion['schema'],\n componentsSchemas,\n };\n};\n\nconst createLifecyclesService = ({ strapi }: { strapi: Core.Strapi }) => {\n const state: {\n isInitialized: boolean;\n } = {\n isInitialized: false,\n };\n\n const serviceUtils = createServiceUtils({ strapi });\n const { persistTablesWithPrefix } = strapi.service('admin::persist-tables');\n\n return {\n async bootstrap() {\n // Prevent initializing the service twice\n if (state.isInitialized) {\n return;\n }\n\n // Avoid data loss in case users temporarily don't have a license\n await persistTablesWithPrefix('strapi_history_versions');\n\n strapi.documents.use(async (context, next) => {\n const result = (await next()) as any;\n\n if (!shouldCreateHistoryVersion(context)) {\n return result;\n }\n\n // On create/clone actions, the documentId is not available before creating the action is executed\n const documentId =\n context.action === 'create' || context.action === 'clone'\n ? result.documentId\n : context.params.documentId;\n\n // Apply default locale if not available in the request\n const defaultLocale = await serviceUtils.getDefaultLocale();\n const locales = castArray(context.params?.locale || defaultLocale);\n if (!locales.length) {\n return result;\n }\n\n // All schemas related to the content type\n const uid = context.contentType.uid;\n const schemas = getSchemas(uid);\n const model = strapi.getModel(uid);\n\n const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);\n\n // Find all affected entries\n const localeEntries = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n ...(isLocalizedContentType ? { locale: { $in: locales } } : {}),\n ...(contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])\n ? { publishedAt: null }\n : {}),\n },\n populate: serviceUtils.getDeepPopulate(uid, true /* use database syntax */),\n });\n\n await strapi.db.transaction(async ({ onCommit }) => {\n // .createVersion() is executed asynchronously,\n // onCommit prevents creating a history version\n // when the transaction has already been committed\n onCommit(async () => {\n for (const entry of localeEntries) {\n const status = await serviceUtils.getVersionStatus(uid, entry);\n\n await getService(strapi, 'history').createVersion({\n contentType: uid,\n data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,\n relatedDocumentId: documentId,\n locale: entry.locale,\n status,\n ...schemas,\n });\n }\n });\n });\n\n return result;\n });\n\n // Schedule a job to delete expired history versions every day at midnight\n strapi.cron.add({\n deleteHistoryDaily: {\n async task() {\n const retentionDaysInMilliseconds =\n serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;\n const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);\n\n strapi.db\n .query(HISTORY_VERSION_UID)\n .deleteMany({\n where: {\n created_at: {\n $lt: expirationDate,\n },\n },\n })\n .catch((error) => {\n if (error instanceof Error) {\n strapi.log.error('Error deleting expired history versions', error.message);\n }\n });\n },\n options: '0 0 * * *',\n },\n });\n\n state.isInitialized = true;\n },\n\n async destroy() {\n strapi.cron.remove('deleteHistoryDaily');\n },\n };\n};\n\nexport { createLifecyclesService };\n"],"names":["shouldCreateHistoryVersion","context","strapi","requestContext","get","request","url","startsWith","action","endsWith","contentType","uid","getSchemas","attributesSchema","getModel","attributes","componentsSchemas","Object","keys","reduce","currentComponentSchemas","key","fieldSchema","type","componentSchema","component","schema","omit","FIELDS_TO_IGNORE","createLifecyclesService","state","isInitialized","serviceUtils","createServiceUtils","persistTablesWithPrefix","service","bootstrap","documents","use","next","result","documentId","params","defaultLocale","getDefaultLocale","locales","castArray","locale","length","schemas","model","isLocalizedContentType","localeEntries","db","query","findMany","where","$in","contentTypes","hasDraftAndPublish","publishedAt","populate","getDeepPopulate","transaction","onCommit","entry","status","getVersionStatus","getService","createVersion","data","relatedDocumentId","cron","add","deleteHistoryDaily","task","retentionDaysInMilliseconds","getRetentionDays","expirationDate","Date","now","HISTORY_VERSION_UID","deleteMany","created_at","$lt","catch","error","Error","log","message","options","destroy","remove"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { contentTypes } from '@strapi/utils';
|
|
2
2
|
import { castArray, omit } from 'lodash/fp';
|
|
3
|
-
import { scheduleJob } from 'node-schedule';
|
|
4
3
|
import { getService } from '../utils.mjs';
|
|
5
4
|
import { FIELDS_TO_IGNORE, HISTORY_VERSION_UID } from '../constants.mjs';
|
|
6
5
|
import { createServiceUtils } from './utils.mjs';
|
|
@@ -56,18 +55,20 @@ import { createServiceUtils } from './utils.mjs';
|
|
|
56
55
|
};
|
|
57
56
|
const createLifecyclesService = ({ strapi: strapi1 })=>{
|
|
58
57
|
const state = {
|
|
59
|
-
deleteExpiredJob: null,
|
|
60
58
|
isInitialized: false
|
|
61
59
|
};
|
|
62
60
|
const serviceUtils = createServiceUtils({
|
|
63
61
|
strapi: strapi1
|
|
64
62
|
});
|
|
63
|
+
const { persistTablesWithPrefix } = strapi1.service('admin::persist-tables');
|
|
65
64
|
return {
|
|
66
65
|
async bootstrap () {
|
|
67
66
|
// Prevent initializing the service twice
|
|
68
67
|
if (state.isInitialized) {
|
|
69
68
|
return;
|
|
70
69
|
}
|
|
70
|
+
// Avoid data loss in case users temporarily don't have a license
|
|
71
|
+
await persistTablesWithPrefix('strapi_history_versions');
|
|
71
72
|
strapi1.documents.use(async (context, next)=>{
|
|
72
73
|
const result = await next();
|
|
73
74
|
if (!shouldCreateHistoryVersion(context)) {
|
|
@@ -122,27 +123,30 @@ const createLifecyclesService = ({ strapi: strapi1 })=>{
|
|
|
122
123
|
return result;
|
|
123
124
|
});
|
|
124
125
|
// Schedule a job to delete expired history versions every day at midnight
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
126
|
+
strapi1.cron.add({
|
|
127
|
+
deleteHistoryDaily: {
|
|
128
|
+
async task () {
|
|
129
|
+
const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;
|
|
130
|
+
const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);
|
|
131
|
+
strapi1.db.query(HISTORY_VERSION_UID).deleteMany({
|
|
132
|
+
where: {
|
|
133
|
+
created_at: {
|
|
134
|
+
$lt: expirationDate
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}).catch((error)=>{
|
|
138
|
+
if (error instanceof Error) {
|
|
139
|
+
strapi1.log.error('Error deleting expired history versions', error.message);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
options: '0 0 * * *'
|
|
144
|
+
}
|
|
139
145
|
});
|
|
140
146
|
state.isInitialized = true;
|
|
141
147
|
},
|
|
142
148
|
async destroy () {
|
|
143
|
-
|
|
144
|
-
state.deleteExpiredJob.cancel();
|
|
145
|
-
}
|
|
149
|
+
strapi1.cron.remove('deleteHistoryDaily');
|
|
146
150
|
}
|
|
147
151
|
};
|
|
148
152
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycles.mjs","sources":["../../../../server/src/history/services/lifecycles.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport { omit, castArray } from 'lodash/fp';\n\nimport { scheduleJob } from 'node-schedule';\n\nimport { getService } from '../utils';\nimport { FIELDS_TO_IGNORE, HISTORY_VERSION_UID } from '../constants';\n\nimport type { CreateHistoryVersion } from '../../../../shared/contracts/history-versions';\nimport { createServiceUtils } from './utils';\n\n/**\n * Filters out actions that should not create a history version.\n */\nconst shouldCreateHistoryVersion = (\n context: Modules.Documents.Middleware.Context\n): context is Modules.Documents.Middleware.Context & {\n action: 'create' | 'update' | 'clone' | 'publish' | 'unpublish' | 'discardDraft';\n contentType: UID.CollectionType;\n} => {\n // Ignore requests that are not related to the content manager\n if (!strapi.requestContext.get()?.request.url.startsWith('/content-manager')) {\n return false;\n }\n\n // NOTE: cannot do type narrowing with array includes\n if (\n context.action !== 'create' &&\n context.action !== 'update' &&\n context.action !== 'clone' &&\n context.action !== 'publish' &&\n context.action !== 'unpublish' &&\n context.action !== 'discardDraft'\n ) {\n return false;\n }\n\n /**\n * When a document is published, the draft version of the document is also updated.\n * It creates confusion for users because they see two history versions each publish action.\n * To avoid this, we silence the update action during a publish request,\n * so that they only see the published version of the document in the history.\n */\n if (\n context.action === 'update' &&\n strapi.requestContext.get()?.request.url.endsWith('/actions/publish')\n ) {\n return false;\n }\n\n // Ignore content types not created by the user\n if (!context.contentType.uid.startsWith('api::')) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Returns the content type schema (and its components schemas).\n * Used to determine if changes were made in the content type builder since a history version was created.\n * And therefore which fields can be restored and which cannot.\n */\nconst getSchemas = (uid: UID.CollectionType) => {\n const attributesSchema = strapi.getModel(uid).attributes;\n\n // TODO: Handle nested components\n const componentsSchemas = Object.keys(attributesSchema).reduce(\n (currentComponentSchemas, key) => {\n const fieldSchema = attributesSchema[key];\n\n if (fieldSchema.type === 'component') {\n const componentSchema = strapi.getModel(fieldSchema.component).attributes;\n return {\n ...currentComponentSchemas,\n [fieldSchema.component]: componentSchema,\n };\n }\n\n // Ignore anything that's not a component\n return currentComponentSchemas;\n },\n {} as CreateHistoryVersion['componentsSchemas']\n );\n\n return {\n schema: omit(FIELDS_TO_IGNORE, attributesSchema) as CreateHistoryVersion['schema'],\n componentsSchemas,\n };\n};\n\nconst createLifecyclesService = ({ strapi }: { strapi: Core.Strapi }) => {\n const state: {\n deleteExpiredJob: ReturnType<typeof scheduleJob> | null;\n isInitialized: boolean;\n } = {\n deleteExpiredJob: null,\n isInitialized: false,\n };\n\n const serviceUtils = createServiceUtils({ strapi });\n\n return {\n async bootstrap() {\n // Prevent initializing the service twice\n if (state.isInitialized) {\n return;\n }\n\n strapi.documents.use(async (context, next) => {\n const result = (await next()) as any;\n\n if (!shouldCreateHistoryVersion(context)) {\n return result;\n }\n\n // On create/clone actions, the documentId is not available before creating the action is executed\n const documentId =\n context.action === 'create' || context.action === 'clone'\n ? result.documentId\n : context.params.documentId;\n\n // Apply default locale if not available in the request\n const defaultLocale = await serviceUtils.getDefaultLocale();\n const locales = castArray(context.params?.locale || defaultLocale);\n if (!locales.length) {\n return result;\n }\n\n // All schemas related to the content type\n const uid = context.contentType.uid;\n const schemas = getSchemas(uid);\n const model = strapi.getModel(uid);\n\n const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);\n\n // Find all affected entries\n const localeEntries = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n ...(isLocalizedContentType ? { locale: { $in: locales } } : {}),\n ...(contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])\n ? { publishedAt: null }\n : {}),\n },\n populate: serviceUtils.getDeepPopulate(uid, true /* use database syntax */),\n });\n\n await strapi.db.transaction(async ({ onCommit }) => {\n // .createVersion() is executed asynchronously,\n // onCommit prevents creating a history version\n // when the transaction has already been committed\n onCommit(async () => {\n for (const entry of localeEntries) {\n const status = await serviceUtils.getVersionStatus(uid, entry);\n\n await getService(strapi, 'history').createVersion({\n contentType: uid,\n data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,\n relatedDocumentId: documentId,\n locale: entry.locale,\n status,\n ...schemas,\n });\n }\n });\n });\n\n return result;\n });\n\n // Schedule a job to delete expired history versions every day at midnight\n state.deleteExpiredJob = scheduleJob('historyDaily', '0 0 * * *', () => {\n const retentionDaysInMilliseconds = serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;\n const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);\n\n strapi.db\n .query(HISTORY_VERSION_UID)\n .deleteMany({\n where: {\n created_at: {\n $lt: expirationDate,\n },\n },\n })\n .catch((error) => {\n if (error instanceof Error) {\n strapi.log.error('Error deleting expired history versions', error.message);\n }\n });\n });\n\n state.isInitialized = true;\n },\n\n async destroy() {\n if (state.deleteExpiredJob) {\n state.deleteExpiredJob.cancel();\n }\n },\n };\n};\n\nexport { createLifecyclesService };\n"],"names":["shouldCreateHistoryVersion","context","strapi","requestContext","get","request","url","startsWith","action","endsWith","contentType","uid","getSchemas","attributesSchema","getModel","attributes","componentsSchemas","Object","keys","reduce","currentComponentSchemas","key","fieldSchema","type","componentSchema","component","schema","omit","FIELDS_TO_IGNORE","createLifecyclesService","state","deleteExpiredJob","isInitialized","serviceUtils","createServiceUtils","bootstrap","documents","use","next","result","documentId","params","defaultLocale","getDefaultLocale","locales","castArray","locale","length","schemas","model","isLocalizedContentType","localeEntries","db","query","findMany","where","$in","contentTypes","hasDraftAndPublish","publishedAt","populate","getDeepPopulate","transaction","onCommit","entry","status","getVersionStatus","getService","createVersion","data","relatedDocumentId","scheduleJob","retentionDaysInMilliseconds","getRetentionDays","expirationDate","Date","now","HISTORY_VERSION_UID","deleteMany","created_at","$lt","catch","error","Error","log","message","destroy","cancel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecycles.mjs","sources":["../../../../server/src/history/services/lifecycles.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport { omit, castArray } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { FIELDS_TO_IGNORE, HISTORY_VERSION_UID } from '../constants';\n\nimport type { CreateHistoryVersion } from '../../../../shared/contracts/history-versions';\nimport { createServiceUtils } from './utils';\n\n/**\n * Filters out actions that should not create a history version.\n */\nconst shouldCreateHistoryVersion = (\n context: Modules.Documents.Middleware.Context\n): context is Modules.Documents.Middleware.Context & {\n action: 'create' | 'update' | 'clone' | 'publish' | 'unpublish' | 'discardDraft';\n contentType: UID.CollectionType;\n} => {\n // Ignore requests that are not related to the content manager\n if (!strapi.requestContext.get()?.request.url.startsWith('/content-manager')) {\n return false;\n }\n\n // NOTE: cannot do type narrowing with array includes\n if (\n context.action !== 'create' &&\n context.action !== 'update' &&\n context.action !== 'clone' &&\n context.action !== 'publish' &&\n context.action !== 'unpublish' &&\n context.action !== 'discardDraft'\n ) {\n return false;\n }\n\n /**\n * When a document is published, the draft version of the document is also updated.\n * It creates confusion for users because they see two history versions each publish action.\n * To avoid this, we silence the update action during a publish request,\n * so that they only see the published version of the document in the history.\n */\n if (\n context.action === 'update' &&\n strapi.requestContext.get()?.request.url.endsWith('/actions/publish')\n ) {\n return false;\n }\n\n // Ignore content types not created by the user\n if (!context.contentType.uid.startsWith('api::')) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Returns the content type schema (and its components schemas).\n * Used to determine if changes were made in the content type builder since a history version was created.\n * And therefore which fields can be restored and which cannot.\n */\nconst getSchemas = (uid: UID.CollectionType) => {\n const attributesSchema = strapi.getModel(uid).attributes;\n\n // TODO: Handle nested components\n const componentsSchemas = Object.keys(attributesSchema).reduce(\n (currentComponentSchemas, key) => {\n const fieldSchema = attributesSchema[key];\n\n if (fieldSchema.type === 'component') {\n const componentSchema = strapi.getModel(fieldSchema.component).attributes;\n return {\n ...currentComponentSchemas,\n [fieldSchema.component]: componentSchema,\n };\n }\n\n // Ignore anything that's not a component\n return currentComponentSchemas;\n },\n {} as CreateHistoryVersion['componentsSchemas']\n );\n\n return {\n schema: omit(FIELDS_TO_IGNORE, attributesSchema) as CreateHistoryVersion['schema'],\n componentsSchemas,\n };\n};\n\nconst createLifecyclesService = ({ strapi }: { strapi: Core.Strapi }) => {\n const state: {\n isInitialized: boolean;\n } = {\n isInitialized: false,\n };\n\n const serviceUtils = createServiceUtils({ strapi });\n const { persistTablesWithPrefix } = strapi.service('admin::persist-tables');\n\n return {\n async bootstrap() {\n // Prevent initializing the service twice\n if (state.isInitialized) {\n return;\n }\n\n // Avoid data loss in case users temporarily don't have a license\n await persistTablesWithPrefix('strapi_history_versions');\n\n strapi.documents.use(async (context, next) => {\n const result = (await next()) as any;\n\n if (!shouldCreateHistoryVersion(context)) {\n return result;\n }\n\n // On create/clone actions, the documentId is not available before creating the action is executed\n const documentId =\n context.action === 'create' || context.action === 'clone'\n ? result.documentId\n : context.params.documentId;\n\n // Apply default locale if not available in the request\n const defaultLocale = await serviceUtils.getDefaultLocale();\n const locales = castArray(context.params?.locale || defaultLocale);\n if (!locales.length) {\n return result;\n }\n\n // All schemas related to the content type\n const uid = context.contentType.uid;\n const schemas = getSchemas(uid);\n const model = strapi.getModel(uid);\n\n const isLocalizedContentType = serviceUtils.isLocalizedContentType(model);\n\n // Find all affected entries\n const localeEntries = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n ...(isLocalizedContentType ? { locale: { $in: locales } } : {}),\n ...(contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])\n ? { publishedAt: null }\n : {}),\n },\n populate: serviceUtils.getDeepPopulate(uid, true /* use database syntax */),\n });\n\n await strapi.db.transaction(async ({ onCommit }) => {\n // .createVersion() is executed asynchronously,\n // onCommit prevents creating a history version\n // when the transaction has already been committed\n onCommit(async () => {\n for (const entry of localeEntries) {\n const status = await serviceUtils.getVersionStatus(uid, entry);\n\n await getService(strapi, 'history').createVersion({\n contentType: uid,\n data: omit(FIELDS_TO_IGNORE, entry) as Modules.Documents.AnyDocument,\n relatedDocumentId: documentId,\n locale: entry.locale,\n status,\n ...schemas,\n });\n }\n });\n });\n\n return result;\n });\n\n // Schedule a job to delete expired history versions every day at midnight\n strapi.cron.add({\n deleteHistoryDaily: {\n async task() {\n const retentionDaysInMilliseconds =\n serviceUtils.getRetentionDays() * 24 * 60 * 60 * 1000;\n const expirationDate = new Date(Date.now() - retentionDaysInMilliseconds);\n\n strapi.db\n .query(HISTORY_VERSION_UID)\n .deleteMany({\n where: {\n created_at: {\n $lt: expirationDate,\n },\n },\n })\n .catch((error) => {\n if (error instanceof Error) {\n strapi.log.error('Error deleting expired history versions', error.message);\n }\n });\n },\n options: '0 0 * * *',\n },\n });\n\n state.isInitialized = true;\n },\n\n async destroy() {\n strapi.cron.remove('deleteHistoryDaily');\n },\n };\n};\n\nexport { createLifecyclesService };\n"],"names":["shouldCreateHistoryVersion","context","strapi","requestContext","get","request","url","startsWith","action","endsWith","contentType","uid","getSchemas","attributesSchema","getModel","attributes","componentsSchemas","Object","keys","reduce","currentComponentSchemas","key","fieldSchema","type","componentSchema","component","schema","omit","FIELDS_TO_IGNORE","createLifecyclesService","state","isInitialized","serviceUtils","createServiceUtils","persistTablesWithPrefix","service","bootstrap","documents","use","next","result","documentId","params","defaultLocale","getDefaultLocale","locales","castArray","locale","length","schemas","model","isLocalizedContentType","localeEntries","db","query","findMany","where","$in","contentTypes","hasDraftAndPublish","publishedAt","populate","getDeepPopulate","transaction","onCommit","entry","status","getVersionStatus","getService","createVersion","data","relatedDocumentId","cron","add","deleteHistoryDaily","task","retentionDaysInMilliseconds","getRetentionDays","expirationDate","Date","now","HISTORY_VERSION_UID","deleteMany","created_at","$lt","catch","error","Error","log","message","options","destroy","remove"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/controllers/homepage.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as yup from 'yup';\nimport { errors } from '@strapi/utils';\nimport type { GetRecentDocuments } from '../../../../shared/contracts/homepage';\n\nconst createHomepageController = () => {\n const homepageService = strapi.plugin('content-manager').service('homepage');\n\n const recentDocumentParamsSchema = yup.object().shape({\n action: yup\n .mixed<GetRecentDocuments.Request['query']['action']>()\n .oneOf(['update', 'publish'])\n .required(),\n });\n\n return {\n async getRecentDocuments(ctx): Promise<GetRecentDocuments.Response> {\n let action;\n\n try {\n action = (await recentDocumentParamsSchema.validate(ctx.query)).action;\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n throw new errors.ValidationError(error.message);\n }\n throw error;\n }\n\n if (action === 'publish') {\n return { data: await homepageService.getRecentlyPublishedDocuments() };\n }\n\n return { data: await homepageService.getRecentlyUpdatedDocuments() };\n },\n } satisfies Core.Controller;\n};\n\nexport { createHomepageController };\n"],"names":["createHomepageController","homepageService","strapi","plugin","service","recentDocumentParamsSchema","yup","object","shape","action","mixed","oneOf","required","getRecentDocuments","ctx","validate","query","error","ValidationError","errors","message","data","getRecentlyPublishedDocuments","getRecentlyUpdatedDocuments"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAMA,wBAA2B,GAAA,IAAA;AAC/B,IAAA,MAAMC,kBAAkBC,MAAOC,CAAAA,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,UAAA,CAAA;AAEjE,IAAA,MAAMC,0BAA6BC,GAAAA,cAAAA,CAAIC,MAAM,EAAA,CAAGC,KAAK,CAAC;AACpDC,QAAAA,MAAAA,EAAQH,cACLI,CAAAA,KAAK,EACLC,CAAAA,KAAK,CAAC;AAAC,YAAA,QAAA;AAAU,YAAA;AAAU,SAAA,CAAA,CAC3BC,QAAQ;AACb,KAAA,CAAA;IAEA,OAAO;AACL,QAAA,MAAMC,oBAAmBC,GAAG,EAAA;YAC1B,IAAIL,MAAAA;YAEJ,IAAI;gBACFA,MAAS,GAAC,CAAA,MAAMJ,0BAA2BU,CAAAA,QAAQ,CAACD,GAAIE,CAAAA,KAAK,CAAA,EAAGP,MAAM;AACxE,aAAA,CAAE,OAAOQ,KAAO,EAAA;gBACd,IAAIA,KAAAA,YAAiBX,cAAIY,CAAAA,eAAe,EAAE;AACxC,oBAAA,MAAM,IAAIC,kBAAAA,CAAOD,eAAe,CAACD,MAAMG,OAAO,CAAA;AAChD;gBACA,MAAMH,KAAAA;AACR;AAEA,YAAA,IAAIR,WAAW,SAAW,EAAA;gBACxB,OAAO;oBAAEY,IAAM,EAAA,MAAMpB,gBAAgBqB,6BAA6B;AAAG,iBAAA;AACvE;YAEA,OAAO;gBAAED,IAAM,EAAA,MAAMpB,gBAAgBsB,2BAA2B;AAAG,aAAA;AACrE;AACF,KAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/controllers/homepage.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as yup from 'yup';\nimport { errors } from '@strapi/utils';\nimport type { GetRecentDocuments, GetCountDocuments } from '../../../../shared/contracts/homepage';\n\nconst createHomepageController = () => {\n const homepageService = strapi.plugin('content-manager').service('homepage');\n\n const recentDocumentParamsSchema = yup.object().shape({\n action: yup\n .mixed<GetRecentDocuments.Request['query']['action']>()\n .oneOf(['update', 'publish'])\n .required(),\n });\n\n return {\n async getRecentDocuments(ctx): Promise<GetRecentDocuments.Response> {\n let action;\n\n try {\n action = (await recentDocumentParamsSchema.validate(ctx.query)).action;\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n throw new errors.ValidationError(error.message);\n }\n throw error;\n }\n\n if (action === 'publish') {\n return { data: await homepageService.getRecentlyPublishedDocuments() };\n }\n\n return { data: await homepageService.getRecentlyUpdatedDocuments() };\n },\n async getCountDocuments(): Promise<GetCountDocuments.Response> {\n return { data: await homepageService.getCountDocuments() };\n },\n } satisfies Core.Controller;\n};\n\nexport { createHomepageController };\n"],"names":["createHomepageController","homepageService","strapi","plugin","service","recentDocumentParamsSchema","yup","object","shape","action","mixed","oneOf","required","getRecentDocuments","ctx","validate","query","error","ValidationError","errors","message","data","getRecentlyPublishedDocuments","getRecentlyUpdatedDocuments","getCountDocuments"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAMA,wBAA2B,GAAA,IAAA;AAC/B,IAAA,MAAMC,kBAAkBC,MAAOC,CAAAA,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,UAAA,CAAA;AAEjE,IAAA,MAAMC,0BAA6BC,GAAAA,cAAAA,CAAIC,MAAM,EAAA,CAAGC,KAAK,CAAC;AACpDC,QAAAA,MAAAA,EAAQH,cACLI,CAAAA,KAAK,EACLC,CAAAA,KAAK,CAAC;AAAC,YAAA,QAAA;AAAU,YAAA;AAAU,SAAA,CAAA,CAC3BC,QAAQ;AACb,KAAA,CAAA;IAEA,OAAO;AACL,QAAA,MAAMC,oBAAmBC,GAAG,EAAA;YAC1B,IAAIL,MAAAA;YAEJ,IAAI;gBACFA,MAAS,GAAC,CAAA,MAAMJ,0BAA2BU,CAAAA,QAAQ,CAACD,GAAIE,CAAAA,KAAK,CAAA,EAAGP,MAAM;AACxE,aAAA,CAAE,OAAOQ,KAAO,EAAA;gBACd,IAAIA,KAAAA,YAAiBX,cAAIY,CAAAA,eAAe,EAAE;AACxC,oBAAA,MAAM,IAAIC,kBAAAA,CAAOD,eAAe,CAACD,MAAMG,OAAO,CAAA;AAChD;gBACA,MAAMH,KAAAA;AACR;AAEA,YAAA,IAAIR,WAAW,SAAW,EAAA;gBACxB,OAAO;oBAAEY,IAAM,EAAA,MAAMpB,gBAAgBqB,6BAA6B;AAAG,iBAAA;AACvE;YAEA,OAAO;gBAAED,IAAM,EAAA,MAAMpB,gBAAgBsB,2BAA2B;AAAG,aAAA;AACrE,SAAA;QACA,MAAMC,iBAAAA,CAAAA,GAAAA;YACJ,OAAO;gBAAEH,IAAM,EAAA,MAAMpB,gBAAgBuB,iBAAiB;AAAG,aAAA;AAC3D;AACF,KAAA;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/controllers/homepage.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as yup from 'yup';\nimport { errors } from '@strapi/utils';\nimport type { GetRecentDocuments } from '../../../../shared/contracts/homepage';\n\nconst createHomepageController = () => {\n const homepageService = strapi.plugin('content-manager').service('homepage');\n\n const recentDocumentParamsSchema = yup.object().shape({\n action: yup\n .mixed<GetRecentDocuments.Request['query']['action']>()\n .oneOf(['update', 'publish'])\n .required(),\n });\n\n return {\n async getRecentDocuments(ctx): Promise<GetRecentDocuments.Response> {\n let action;\n\n try {\n action = (await recentDocumentParamsSchema.validate(ctx.query)).action;\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n throw new errors.ValidationError(error.message);\n }\n throw error;\n }\n\n if (action === 'publish') {\n return { data: await homepageService.getRecentlyPublishedDocuments() };\n }\n\n return { data: await homepageService.getRecentlyUpdatedDocuments() };\n },\n } satisfies Core.Controller;\n};\n\nexport { createHomepageController };\n"],"names":["createHomepageController","homepageService","strapi","plugin","service","recentDocumentParamsSchema","yup","object","shape","action","mixed","oneOf","required","getRecentDocuments","ctx","validate","query","error","ValidationError","errors","message","data","getRecentlyPublishedDocuments","getRecentlyUpdatedDocuments"],"mappings":";;;AAKA,MAAMA,wBAA2B,GAAA,IAAA;AAC/B,IAAA,MAAMC,kBAAkBC,MAAOC,CAAAA,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,UAAA,CAAA;AAEjE,IAAA,MAAMC,0BAA6BC,GAAAA,GAAAA,CAAIC,MAAM,EAAA,CAAGC,KAAK,CAAC;AACpDC,QAAAA,MAAAA,EAAQH,GACLI,CAAAA,KAAK,EACLC,CAAAA,KAAK,CAAC;AAAC,YAAA,QAAA;AAAU,YAAA;AAAU,SAAA,CAAA,CAC3BC,QAAQ;AACb,KAAA,CAAA;IAEA,OAAO;AACL,QAAA,MAAMC,oBAAmBC,GAAG,EAAA;YAC1B,IAAIL,MAAAA;YAEJ,IAAI;gBACFA,MAAS,GAAC,CAAA,MAAMJ,0BAA2BU,CAAAA,QAAQ,CAACD,GAAIE,CAAAA,KAAK,CAAA,EAAGP,MAAM;AACxE,aAAA,CAAE,OAAOQ,KAAO,EAAA;gBACd,IAAIA,KAAAA,YAAiBX,GAAIY,CAAAA,eAAe,EAAE;AACxC,oBAAA,MAAM,IAAIC,MAAAA,CAAOD,eAAe,CAACD,MAAMG,OAAO,CAAA;AAChD;gBACA,MAAMH,KAAAA;AACR;AAEA,YAAA,IAAIR,WAAW,SAAW,EAAA;gBACxB,OAAO;oBAAEY,IAAM,EAAA,MAAMpB,gBAAgBqB,6BAA6B;AAAG,iBAAA;AACvE;YAEA,OAAO;gBAAED,IAAM,EAAA,MAAMpB,gBAAgBsB,2BAA2B;AAAG,aAAA;AACrE;AACF,KAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/controllers/homepage.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as yup from 'yup';\nimport { errors } from '@strapi/utils';\nimport type { GetRecentDocuments, GetCountDocuments } from '../../../../shared/contracts/homepage';\n\nconst createHomepageController = () => {\n const homepageService = strapi.plugin('content-manager').service('homepage');\n\n const recentDocumentParamsSchema = yup.object().shape({\n action: yup\n .mixed<GetRecentDocuments.Request['query']['action']>()\n .oneOf(['update', 'publish'])\n .required(),\n });\n\n return {\n async getRecentDocuments(ctx): Promise<GetRecentDocuments.Response> {\n let action;\n\n try {\n action = (await recentDocumentParamsSchema.validate(ctx.query)).action;\n } catch (error) {\n if (error instanceof yup.ValidationError) {\n throw new errors.ValidationError(error.message);\n }\n throw error;\n }\n\n if (action === 'publish') {\n return { data: await homepageService.getRecentlyPublishedDocuments() };\n }\n\n return { data: await homepageService.getRecentlyUpdatedDocuments() };\n },\n async getCountDocuments(): Promise<GetCountDocuments.Response> {\n return { data: await homepageService.getCountDocuments() };\n },\n } satisfies Core.Controller;\n};\n\nexport { createHomepageController };\n"],"names":["createHomepageController","homepageService","strapi","plugin","service","recentDocumentParamsSchema","yup","object","shape","action","mixed","oneOf","required","getRecentDocuments","ctx","validate","query","error","ValidationError","errors","message","data","getRecentlyPublishedDocuments","getRecentlyUpdatedDocuments","getCountDocuments"],"mappings":";;;AAKA,MAAMA,wBAA2B,GAAA,IAAA;AAC/B,IAAA,MAAMC,kBAAkBC,MAAOC,CAAAA,MAAM,CAAC,iBAAA,CAAA,CAAmBC,OAAO,CAAC,UAAA,CAAA;AAEjE,IAAA,MAAMC,0BAA6BC,GAAAA,GAAAA,CAAIC,MAAM,EAAA,CAAGC,KAAK,CAAC;AACpDC,QAAAA,MAAAA,EAAQH,GACLI,CAAAA,KAAK,EACLC,CAAAA,KAAK,CAAC;AAAC,YAAA,QAAA;AAAU,YAAA;AAAU,SAAA,CAAA,CAC3BC,QAAQ;AACb,KAAA,CAAA;IAEA,OAAO;AACL,QAAA,MAAMC,oBAAmBC,GAAG,EAAA;YAC1B,IAAIL,MAAAA;YAEJ,IAAI;gBACFA,MAAS,GAAC,CAAA,MAAMJ,0BAA2BU,CAAAA,QAAQ,CAACD,GAAIE,CAAAA,KAAK,CAAA,EAAGP,MAAM;AACxE,aAAA,CAAE,OAAOQ,KAAO,EAAA;gBACd,IAAIA,KAAAA,YAAiBX,GAAIY,CAAAA,eAAe,EAAE;AACxC,oBAAA,MAAM,IAAIC,MAAAA,CAAOD,eAAe,CAACD,MAAMG,OAAO,CAAA;AAChD;gBACA,MAAMH,KAAAA;AACR;AAEA,YAAA,IAAIR,WAAW,SAAW,EAAA;gBACxB,OAAO;oBAAEY,IAAM,EAAA,MAAMpB,gBAAgBqB,6BAA6B;AAAG,iBAAA;AACvE;YAEA,OAAO;gBAAED,IAAM,EAAA,MAAMpB,gBAAgBsB,2BAA2B;AAAG,aAAA;AACrE,SAAA;QACA,MAAMC,iBAAAA,CAAAA,GAAAA;YACJ,OAAO;gBAAEH,IAAM,EAAA,MAAMpB,gBAAgBuB,iBAAiB;AAAG,aAAA;AAC3D;AACF,KAAA;AACF;;;;"}
|
|
@@ -17,6 +17,17 @@ const homepageRouter = {
|
|
|
17
17
|
'admin::isAuthenticatedAdmin'
|
|
18
18
|
]
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
method: 'GET',
|
|
23
|
+
info,
|
|
24
|
+
path: '/homepage/count-documents',
|
|
25
|
+
handler: 'homepage.getCountDocuments',
|
|
26
|
+
config: {
|
|
27
|
+
policies: [
|
|
28
|
+
'admin::isAuthenticatedAdmin'
|
|
29
|
+
]
|
|
30
|
+
}
|
|
20
31
|
}
|
|
21
32
|
]
|
|
22
33
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/routes/homepage.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\n\nconst info = { pluginName: 'content-manager', type: 'admin' };\n\nconst homepageRouter: Plugin.LoadedPlugin['routes'][string] = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n info,\n path: '/homepage/recent-documents',\n handler: 'homepage.getRecentDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n\nexport { homepageRouter };\n"],"names":["info","pluginName","type","homepageRouter","routes","method","path","handler","config","policies"],"mappings":";;AAEA,MAAMA,IAAO,GAAA;IAAEC,UAAY,EAAA,iBAAA;IAAmBC,IAAM,EAAA;AAAQ,CAAA;AAE5D,MAAMC,cAAwD,GAAA;IAC5DD,IAAM,EAAA,OAAA;IACNE,MAAQ,EAAA;AACN,QAAA;YACEC,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,4BAAA;YACNC,OAAS,EAAA,6BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/routes/homepage.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\n\nconst info = { pluginName: 'content-manager', type: 'admin' };\n\nconst homepageRouter: Plugin.LoadedPlugin['routes'][string] = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n info,\n path: '/homepage/recent-documents',\n handler: 'homepage.getRecentDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n info,\n path: '/homepage/count-documents',\n handler: 'homepage.getCountDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n\nexport { homepageRouter };\n"],"names":["info","pluginName","type","homepageRouter","routes","method","path","handler","config","policies"],"mappings":";;AAEA,MAAMA,IAAO,GAAA;IAAEC,UAAY,EAAA,iBAAA;IAAmBC,IAAM,EAAA;AAAQ,CAAA;AAE5D,MAAMC,cAAwD,GAAA;IAC5DD,IAAM,EAAA,OAAA;IACNE,MAAQ,EAAA;AACN,QAAA;YACEC,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,4BAAA;YACNC,OAAS,EAAA,6BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,2BAAA;YACNC,OAAS,EAAA,4BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH;;;;"}
|
|
@@ -15,6 +15,17 @@ const homepageRouter = {
|
|
|
15
15
|
'admin::isAuthenticatedAdmin'
|
|
16
16
|
]
|
|
17
17
|
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
method: 'GET',
|
|
21
|
+
info,
|
|
22
|
+
path: '/homepage/count-documents',
|
|
23
|
+
handler: 'homepage.getCountDocuments',
|
|
24
|
+
config: {
|
|
25
|
+
policies: [
|
|
26
|
+
'admin::isAuthenticatedAdmin'
|
|
27
|
+
]
|
|
28
|
+
}
|
|
18
29
|
}
|
|
19
30
|
]
|
|
20
31
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/routes/homepage.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\n\nconst info = { pluginName: 'content-manager', type: 'admin' };\n\nconst homepageRouter: Plugin.LoadedPlugin['routes'][string] = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n info,\n path: '/homepage/recent-documents',\n handler: 'homepage.getRecentDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n\nexport { homepageRouter };\n"],"names":["info","pluginName","type","homepageRouter","routes","method","path","handler","config","policies"],"mappings":"AAEA,MAAMA,IAAO,GAAA;IAAEC,UAAY,EAAA,iBAAA;IAAmBC,IAAM,EAAA;AAAQ,CAAA;AAE5D,MAAMC,cAAwD,GAAA;IAC5DD,IAAM,EAAA,OAAA;IACNE,MAAQ,EAAA;AACN,QAAA;YACEC,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,4BAAA;YACNC,OAAS,EAAA,6BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"homepage.mjs","sources":["../../../../server/src/homepage/routes/homepage.ts"],"sourcesContent":["import type { Plugin } from '@strapi/types';\n\nconst info = { pluginName: 'content-manager', type: 'admin' };\n\nconst homepageRouter: Plugin.LoadedPlugin['routes'][string] = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n info,\n path: '/homepage/recent-documents',\n handler: 'homepage.getRecentDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n info,\n path: '/homepage/count-documents',\n handler: 'homepage.getCountDocuments',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n\nexport { homepageRouter };\n"],"names":["info","pluginName","type","homepageRouter","routes","method","path","handler","config","policies"],"mappings":"AAEA,MAAMA,IAAO,GAAA;IAAEC,UAAY,EAAA,iBAAA;IAAmBC,IAAM,EAAA;AAAQ,CAAA;AAE5D,MAAMC,cAAwD,GAAA;IAC5DD,IAAM,EAAA,OAAA;IACNE,MAAQ,EAAA;AACN,QAAA;YACEC,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,4BAAA;YACNC,OAAS,EAAA,6BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAQ,EAAA,KAAA;AACRL,YAAAA,IAAAA;YACAM,IAAM,EAAA,2BAAA;YACNC,OAAS,EAAA,4BAAA;YACTC,MAAQ,EAAA;gBACNC,QAAU,EAAA;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH;;;;"}
|
|
@@ -66,8 +66,12 @@ const createHomepageService = ({ strapi })=>{
|
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
|
-
const formatDocuments = (documents, meta)=>{
|
|
69
|
+
const formatDocuments = (documents, meta, populate)=>{
|
|
70
70
|
return documents.map((document)=>{
|
|
71
|
+
const additionalFields = populate?.reduce((acc, key)=>{
|
|
72
|
+
acc[key] = document[key];
|
|
73
|
+
return acc;
|
|
74
|
+
}, {}) || {};
|
|
71
75
|
return {
|
|
72
76
|
documentId: document.documentId,
|
|
73
77
|
locale: document.locale ?? null,
|
|
@@ -76,79 +80,115 @@ const createHomepageService = ({ strapi })=>{
|
|
|
76
80
|
publishedAt: meta.hasDraftAndPublish && document.publishedAt ? new Date(document.publishedAt) : null,
|
|
77
81
|
contentTypeUid: meta.uid,
|
|
78
82
|
contentTypeDisplayName: meta.contentType.info.displayName,
|
|
79
|
-
kind: meta.contentType.kind
|
|
83
|
+
kind: meta.contentType.kind,
|
|
84
|
+
...additionalFields
|
|
80
85
|
};
|
|
81
86
|
});
|
|
82
87
|
};
|
|
83
|
-
const addStatusToDocuments = async (documents)=>{
|
|
84
|
-
return Promise.all(documents.map(async (recentDocument)=>{
|
|
85
|
-
const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentType(recentDocument.contentTypeUid));
|
|
86
|
-
/**
|
|
87
|
-
* Tries to query the other version of the document if draft and publish is enabled,
|
|
88
|
-
* so that we know when to give the "modified" status.
|
|
89
|
-
*/ const { availableStatus } = await metadataService.getMetadata(recentDocument.contentTypeUid, recentDocument, {
|
|
90
|
-
availableStatus: hasDraftAndPublish,
|
|
91
|
-
availableLocales: false
|
|
92
|
-
});
|
|
93
|
-
const status = metadataService.getStatus(recentDocument, availableStatus);
|
|
94
|
-
return {
|
|
95
|
-
...recentDocument,
|
|
96
|
-
status: hasDraftAndPublish ? status : undefined
|
|
97
|
-
};
|
|
98
|
-
}));
|
|
99
|
-
};
|
|
100
88
|
const permissionCheckerService = strapi.plugin('content-manager').service('permission-checker');
|
|
101
89
|
const getPermissionChecker = (uid)=>permissionCheckerService.create({
|
|
102
90
|
userAbility: strapi.requestContext.get()?.state.userAbility,
|
|
103
91
|
model: uid
|
|
104
92
|
});
|
|
105
93
|
return {
|
|
106
|
-
async
|
|
94
|
+
async addStatusToDocuments (documents) {
|
|
95
|
+
return Promise.all(documents.map(async (recentDocument)=>{
|
|
96
|
+
const hasDraftAndPublish = strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentType(recentDocument.contentTypeUid));
|
|
97
|
+
/**
|
|
98
|
+
* Tries to query the other version of the document if draft and publish is enabled,
|
|
99
|
+
* so that we know when to give the "modified" status.
|
|
100
|
+
*/ const { availableStatus } = await metadataService.getMetadata(recentDocument.contentTypeUid, recentDocument, {
|
|
101
|
+
availableStatus: hasDraftAndPublish,
|
|
102
|
+
availableLocales: false
|
|
103
|
+
});
|
|
104
|
+
const status = metadataService.getStatus(recentDocument, availableStatus);
|
|
105
|
+
return {
|
|
106
|
+
...recentDocument,
|
|
107
|
+
status: hasDraftAndPublish ? status : undefined
|
|
108
|
+
};
|
|
109
|
+
}));
|
|
110
|
+
},
|
|
111
|
+
async queryLastDocuments (additionalQueryParams, draftAndPublishOnly) {
|
|
107
112
|
const permittedContentTypes = await getPermittedContentTypes();
|
|
108
|
-
const allowedContentTypeUids = permittedContentTypes.filter((uid)=>{
|
|
113
|
+
const allowedContentTypeUids = draftAndPublishOnly ? permittedContentTypes.filter((uid)=>{
|
|
109
114
|
return strapiUtils.contentTypes.hasDraftAndPublish(strapi.contentType(uid));
|
|
110
|
-
});
|
|
115
|
+
}) : permittedContentTypes;
|
|
111
116
|
// Fetch the configuration for each content type in a single query
|
|
112
117
|
const configurations = await getConfiguration(allowedContentTypeUids);
|
|
113
118
|
// Get the necessary metadata for the documents
|
|
114
119
|
const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);
|
|
115
|
-
// Now actually fetch and format the documents
|
|
116
120
|
const recentDocuments = await Promise.all(contentTypesMeta.map(async (meta)=>{
|
|
117
121
|
const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({
|
|
118
122
|
limit: MAX_DOCUMENTS,
|
|
119
|
-
sort: 'publishedAt:desc',
|
|
120
123
|
fields: meta.fields,
|
|
121
|
-
|
|
124
|
+
...additionalQueryParams
|
|
122
125
|
});
|
|
123
126
|
const docs = await strapi.documents(meta.uid).findMany(permissionQuery);
|
|
124
|
-
|
|
127
|
+
const populate = additionalQueryParams?.populate;
|
|
128
|
+
return formatDocuments(docs, meta, populate);
|
|
125
129
|
}));
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
return recentDocuments.flat().sort((a, b)=>{
|
|
131
|
+
switch(additionalQueryParams?.sort){
|
|
132
|
+
case 'publishedAt:desc':
|
|
133
|
+
if (!a.publishedAt || !b.publishedAt) return 0;
|
|
134
|
+
return b.publishedAt.valueOf() - a.publishedAt.valueOf();
|
|
135
|
+
case 'publishedAt:asc':
|
|
136
|
+
if (!a.publishedAt || !b.publishedAt) return 0;
|
|
137
|
+
return a.publishedAt.valueOf() - b.publishedAt.valueOf();
|
|
138
|
+
case 'updatedAt:desc':
|
|
139
|
+
if (!a.updatedAt || !b.updatedAt) return 0;
|
|
140
|
+
return b.updatedAt.valueOf() - a.updatedAt.valueOf();
|
|
141
|
+
case 'updatedAt:asc':
|
|
142
|
+
if (!a.updatedAt || !b.updatedAt) return 0;
|
|
143
|
+
return a.updatedAt.valueOf() - b.updatedAt.valueOf();
|
|
144
|
+
default:
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
129
147
|
}).slice(0, MAX_DOCUMENTS);
|
|
130
|
-
|
|
148
|
+
},
|
|
149
|
+
async getRecentlyPublishedDocuments () {
|
|
150
|
+
const recentlyPublishedDocuments = await this.queryLastDocuments({
|
|
151
|
+
sort: 'publishedAt:desc',
|
|
152
|
+
status: 'published'
|
|
153
|
+
}, true);
|
|
154
|
+
return this.addStatusToDocuments(recentlyPublishedDocuments);
|
|
131
155
|
},
|
|
132
156
|
async getRecentlyUpdatedDocuments () {
|
|
133
|
-
const
|
|
157
|
+
const recentlyUpdatedDocuments = await this.queryLastDocuments({
|
|
158
|
+
sort: 'updatedAt:desc'
|
|
159
|
+
});
|
|
160
|
+
return this.addStatusToDocuments(recentlyUpdatedDocuments);
|
|
161
|
+
},
|
|
162
|
+
async getCountDocuments () {
|
|
163
|
+
const permittedContentTypes = await getPermittedContentTypes();
|
|
134
164
|
// Fetch the configuration for each content type in a single query
|
|
135
|
-
const configurations = await getConfiguration(
|
|
165
|
+
const configurations = await getConfiguration(permittedContentTypes);
|
|
136
166
|
// Get the necessary metadata for the documents
|
|
137
|
-
const contentTypesMeta = getContentTypesMeta(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
167
|
+
const contentTypesMeta = getContentTypesMeta(permittedContentTypes, configurations);
|
|
168
|
+
const countDocuments = {
|
|
169
|
+
draft: 0,
|
|
170
|
+
published: 0,
|
|
171
|
+
modified: 0
|
|
172
|
+
};
|
|
173
|
+
await Promise.all(contentTypesMeta.map(async (meta)=>{
|
|
174
|
+
const strapiDBConnection = strapi.db.connection;
|
|
175
|
+
const tableName = strapi.contentType(meta.uid).collectionName;
|
|
176
|
+
if (tableName) {
|
|
177
|
+
const draftDocuments = await strapiDBConnection(tableName).whereNull('published_at').whereIn('document_id', function() {
|
|
178
|
+
this.select('document_id').from(tableName).groupBy('document_id').havingRaw('COUNT(*) = 1');
|
|
179
|
+
}).count('* as count').first();
|
|
180
|
+
countDocuments.draft += Number(draftDocuments?.count) || 0;
|
|
181
|
+
const publishedDocuments = meta.hasDraftAndPublish ? await strapiDBConnection(tableName).select('draft.document_id').from(`${tableName} as draft`).join(`${tableName} as published`, function() {
|
|
182
|
+
this.on('draft.document_id', '=', 'published.document_id').andOn('draft.updated_at', '=', 'published.updated_at').andOnNull('draft.published_at').andOnNotNull('published.published_at');
|
|
183
|
+
}).countDistinct('draft.document_id as count').groupBy('draft.document_id').first() : await strapiDBConnection(tableName).select('document_id').from(`${tableName}`).countDistinct('document_id as count').groupBy('document_id').first();
|
|
184
|
+
countDocuments.published += Number(publishedDocuments?.count) || 0;
|
|
185
|
+
const modifiedDocuments = await strapiDBConnection(tableName).select('draft.document_id').from(`${tableName} as draft`).join(`${tableName} as published`, function() {
|
|
186
|
+
this.on('draft.document_id', '=', 'published.document_id').andOn('draft.updated_at', '!=', 'published.updated_at').andOnNull('draft.published_at').andOnNotNull('published.published_at');
|
|
187
|
+
}).countDistinct('draft.document_id as count').groupBy('draft.document_id').first();
|
|
188
|
+
countDocuments.modified += Number(modifiedDocuments?.count) || 0;
|
|
189
|
+
}
|
|
147
190
|
}));
|
|
148
|
-
|
|
149
|
-
return b.updatedAt.valueOf() - a.updatedAt.valueOf();
|
|
150
|
-
}).slice(0, MAX_DOCUMENTS);
|
|
151
|
-
return addStatusToDocuments(overallRecentDocuments);
|
|
191
|
+
return countDocuments;
|
|
152
192
|
}
|
|
153
193
|
};
|
|
154
194
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/services/homepage.ts"],"sourcesContent":["import type { Core, Modules, Schema } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport type { GetRecentDocuments, RecentDocument } from '../../../../shared/contracts/homepage';\n\nconst createHomepageService = ({ strapi }: { strapi: Core.Strapi }) => {\n const MAX_DOCUMENTS = 4;\n\n const metadataService = strapi.plugin('content-manager').service('document-metadata');\n const permissionService = strapi.admin.services.permission;\n\n type ContentTypeConfiguration = {\n uid: RecentDocument['contentTypeUid'];\n settings: { mainField: string };\n };\n const getConfiguration = async (\n contentTypeUids: RecentDocument['contentTypeUid'][]\n ): Promise<ContentTypeConfiguration[]> => {\n /**\n * Don't use the strapi.store util because we need to make\n * more precise queries than exact key matches, in order to make as few queries as possible.\n */\n const coreStore = strapi.db.query('strapi::core-store');\n const rawConfigurations = await coreStore.findMany({\n where: {\n key: {\n $in: contentTypeUids.map(\n (contentType) => `plugin_content_manager_configuration_content_types::${contentType}`\n ),\n },\n },\n });\n\n return rawConfigurations.map((rawConfiguration) => {\n return JSON.parse(rawConfiguration.value);\n });\n };\n\n const getPermittedContentTypes = async () => {\n const readPermissions: Modules.Permissions.PermissionRule[] = await permissionService.findMany({\n where: {\n role: { users: { id: strapi.requestContext.get()?.state?.user.id } },\n action: 'plugin::content-manager.explorer.read',\n },\n });\n\n return readPermissions\n .map((permission) => permission.subject)\n .filter(Boolean) as RecentDocument['contentTypeUid'][];\n };\n\n type ContentTypeMeta = {\n fields: string[];\n mainField: string;\n contentType: Schema.ContentType;\n hasDraftAndPublish: boolean;\n uid: RecentDocument['contentTypeUid'];\n };\n\n const getContentTypesMeta = (\n allowedContentTypeUids: RecentDocument['contentTypeUid'][],\n configurations: ContentTypeConfiguration[]\n ): ContentTypeMeta[] => {\n return allowedContentTypeUids.map((uid) => {\n const configuration = configurations.find((config) => config.uid === uid);\n const contentType = strapi.contentType(uid);\n const fields = ['documentId', 'updatedAt'];\n\n // Add fields required to get the status if D&P is enabled\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(contentType);\n if (hasDraftAndPublish) {\n fields.push('publishedAt');\n }\n\n // Only add the main field if it's defined\n if (configuration?.settings.mainField) {\n fields.push(configuration.settings.mainField);\n }\n\n // Only add locale if it's localized\n const isLocalized = (contentType.pluginOptions?.i18n as any)?.localized;\n if (isLocalized) {\n fields.push('locale');\n }\n\n return {\n fields,\n mainField: configuration!.settings.mainField,\n contentType,\n hasDraftAndPublish,\n uid,\n };\n });\n };\n\n const formatDocuments = (documents: Modules.Documents.AnyDocument[], meta: ContentTypeMeta) => {\n return documents.map((document) => {\n return {\n documentId: document.documentId,\n locale: document.locale ?? null,\n updatedAt: new Date(document.updatedAt),\n title: document[meta.mainField ?? 'documentId'],\n publishedAt:\n meta.hasDraftAndPublish && document.publishedAt ? new Date(document.publishedAt) : null,\n contentTypeUid: meta.uid,\n contentTypeDisplayName: meta.contentType.info.displayName,\n kind: meta.contentType.kind,\n };\n });\n };\n\n const addStatusToDocuments = async (documents: RecentDocument[]): Promise<RecentDocument[]> => {\n return Promise.all(\n documents.map(async (recentDocument) => {\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(\n strapi.contentType(recentDocument.contentTypeUid)\n );\n /**\n * Tries to query the other version of the document if draft and publish is enabled,\n * so that we know when to give the \"modified\" status.\n */\n const { availableStatus } = await metadataService.getMetadata(\n recentDocument.contentTypeUid,\n recentDocument,\n {\n availableStatus: hasDraftAndPublish,\n availableLocales: false,\n }\n );\n const status: RecentDocument['status'] = metadataService.getStatus(\n recentDocument,\n availableStatus\n );\n\n return {\n ...recentDocument,\n status: hasDraftAndPublish ? status : undefined,\n };\n })\n );\n };\n\n const permissionCheckerService = strapi.plugin('content-manager').service('permission-checker');\n const getPermissionChecker = (uid: string) =>\n permissionCheckerService.create({\n userAbility: strapi.requestContext.get()?.state.userAbility,\n model: uid,\n });\n\n return {\n async getRecentlyPublishedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const permittedContentTypes = await getPermittedContentTypes();\n const allowedContentTypeUids = permittedContentTypes.filter((uid) => {\n return contentTypes.hasDraftAndPublish(strapi.contentType(uid));\n });\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(allowedContentTypeUids);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);\n // Now actually fetch and format the documents\n const recentDocuments = await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({\n limit: MAX_DOCUMENTS,\n sort: 'publishedAt:desc',\n fields: meta.fields,\n status: 'published',\n });\n\n const docs = await strapi.documents(meta.uid).findMany(permissionQuery);\n\n return formatDocuments(docs, meta);\n })\n );\n\n const overallRecentDocuments = recentDocuments\n .flat()\n .sort((a, b) => {\n if (!a.publishedAt || !b.publishedAt) return 0;\n return b.publishedAt.valueOf() - a.publishedAt.valueOf();\n })\n .slice(0, MAX_DOCUMENTS);\n\n return addStatusToDocuments(overallRecentDocuments);\n },\n\n async getRecentlyUpdatedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const allowedContentTypeUids = await getPermittedContentTypes();\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(allowedContentTypeUids);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);\n // Now actually fetch and format the documents\n const recentDocuments = await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({\n limit: MAX_DOCUMENTS,\n sort: 'updatedAt:desc',\n fields: meta.fields,\n });\n\n const docs = await strapi.documents(meta.uid).findMany(permissionQuery);\n\n return formatDocuments(docs, meta);\n })\n );\n\n const overallRecentDocuments = recentDocuments\n .flat()\n .sort((a, b) => {\n return b.updatedAt.valueOf() - a.updatedAt.valueOf();\n })\n .slice(0, MAX_DOCUMENTS);\n\n return addStatusToDocuments(overallRecentDocuments);\n },\n };\n};\n\nexport { createHomepageService };\n"],"names":["createHomepageService","strapi","MAX_DOCUMENTS","metadataService","plugin","service","permissionService","admin","services","permission","getConfiguration","contentTypeUids","coreStore","db","query","rawConfigurations","findMany","where","key","$in","map","contentType","rawConfiguration","JSON","parse","value","getPermittedContentTypes","readPermissions","role","users","id","requestContext","get","state","user","action","subject","filter","Boolean","getContentTypesMeta","allowedContentTypeUids","configurations","uid","configuration","find","config","fields","hasDraftAndPublish","contentTypes","push","settings","mainField","isLocalized","pluginOptions","i18n","localized","formatDocuments","documents","meta","document","documentId","locale","updatedAt","Date","title","publishedAt","contentTypeUid","contentTypeDisplayName","info","displayName","kind","addStatusToDocuments","Promise","all","recentDocument","availableStatus","getMetadata","availableLocales","status","getStatus","undefined","permissionCheckerService","getPermissionChecker","create","userAbility","model","getRecentlyPublishedDocuments","permittedContentTypes","contentTypesMeta","recentDocuments","permissionQuery","sanitizedQuery","read","limit","sort","docs","overallRecentDocuments","flat","a","b","valueOf","slice","getRecentlyUpdatedDocuments"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"homepage.js","sources":["../../../../server/src/homepage/services/homepage.ts"],"sourcesContent":["import type { Core, Modules, Schema } from '@strapi/types';\nimport { contentTypes } from '@strapi/utils';\n\nimport type {\n GetCountDocuments,\n GetRecentDocuments,\n RecentDocument,\n} from '../../../../shared/contracts/homepage';\n\nconst createHomepageService = ({ strapi }: { strapi: Core.Strapi }) => {\n const MAX_DOCUMENTS = 4;\n\n const metadataService = strapi.plugin('content-manager').service('document-metadata');\n const permissionService = strapi.admin.services.permission;\n\n type ContentTypeConfiguration = {\n uid: RecentDocument['contentTypeUid'];\n settings: { mainField: string };\n };\n const getConfiguration = async (\n contentTypeUids: RecentDocument['contentTypeUid'][]\n ): Promise<ContentTypeConfiguration[]> => {\n /**\n * Don't use the strapi.store util because we need to make\n * more precise queries than exact key matches, in order to make as few queries as possible.\n */\n const coreStore = strapi.db.query('strapi::core-store');\n const rawConfigurations = await coreStore.findMany({\n where: {\n key: {\n $in: contentTypeUids.map(\n (contentType) => `plugin_content_manager_configuration_content_types::${contentType}`\n ),\n },\n },\n });\n\n return rawConfigurations.map((rawConfiguration) => {\n return JSON.parse(rawConfiguration.value);\n });\n };\n\n const getPermittedContentTypes = async () => {\n const readPermissions: Modules.Permissions.PermissionRule[] = await permissionService.findMany({\n where: {\n role: { users: { id: strapi.requestContext.get()?.state?.user.id } },\n action: 'plugin::content-manager.explorer.read',\n },\n });\n\n return readPermissions\n .map((permission) => permission.subject)\n .filter(Boolean) as RecentDocument['contentTypeUid'][];\n };\n\n type ContentTypeMeta = {\n fields: string[];\n mainField: string;\n contentType: Schema.ContentType;\n hasDraftAndPublish: boolean;\n uid: RecentDocument['contentTypeUid'];\n };\n\n const getContentTypesMeta = (\n allowedContentTypeUids: RecentDocument['contentTypeUid'][],\n configurations: ContentTypeConfiguration[]\n ): ContentTypeMeta[] => {\n return allowedContentTypeUids.map((uid) => {\n const configuration = configurations.find((config) => config.uid === uid);\n const contentType = strapi.contentType(uid);\n const fields = ['documentId', 'updatedAt'];\n\n // Add fields required to get the status if D&P is enabled\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(contentType);\n if (hasDraftAndPublish) {\n fields.push('publishedAt');\n }\n\n // Only add the main field if it's defined\n if (configuration?.settings.mainField) {\n fields.push(configuration.settings.mainField);\n }\n\n // Only add locale if it's localized\n const isLocalized = (contentType.pluginOptions?.i18n as any)?.localized;\n if (isLocalized) {\n fields.push('locale');\n }\n\n return {\n fields,\n mainField: configuration!.settings.mainField,\n contentType,\n hasDraftAndPublish,\n uid,\n };\n });\n };\n\n const formatDocuments = (\n documents: Modules.Documents.AnyDocument[],\n meta: ContentTypeMeta,\n populate?: string[]\n ) => {\n return documents.map((document) => {\n const additionalFields =\n populate?.reduce(\n (acc, key) => {\n acc[key] = document[key];\n return acc;\n },\n {} as Record<string, any>\n ) || {};\n return {\n documentId: document.documentId,\n locale: document.locale ?? null,\n updatedAt: new Date(document.updatedAt),\n title: document[meta.mainField ?? 'documentId'],\n publishedAt:\n meta.hasDraftAndPublish && document.publishedAt ? new Date(document.publishedAt) : null,\n contentTypeUid: meta.uid,\n contentTypeDisplayName: meta.contentType.info.displayName,\n kind: meta.contentType.kind,\n ...additionalFields,\n };\n });\n };\n\n const permissionCheckerService = strapi.plugin('content-manager').service('permission-checker');\n const getPermissionChecker = (uid: string) =>\n permissionCheckerService.create({\n userAbility: strapi.requestContext.get()?.state.userAbility,\n model: uid,\n });\n\n return {\n async addStatusToDocuments(documents: RecentDocument[]): Promise<RecentDocument[]> {\n return Promise.all(\n documents.map(async (recentDocument) => {\n const hasDraftAndPublish = contentTypes.hasDraftAndPublish(\n strapi.contentType(recentDocument.contentTypeUid)\n );\n /**\n * Tries to query the other version of the document if draft and publish is enabled,\n * so that we know when to give the \"modified\" status.\n */\n const { availableStatus } = await metadataService.getMetadata(\n recentDocument.contentTypeUid,\n recentDocument,\n {\n availableStatus: hasDraftAndPublish,\n availableLocales: false,\n }\n );\n const status: RecentDocument['status'] = metadataService.getStatus(\n recentDocument,\n availableStatus\n );\n\n return {\n ...recentDocument,\n status: hasDraftAndPublish ? status : undefined,\n };\n })\n );\n },\n\n async queryLastDocuments(\n additionalQueryParams?: Record<string, unknown>,\n draftAndPublishOnly?: boolean\n ): Promise<RecentDocument[]> {\n const permittedContentTypes = await getPermittedContentTypes();\n const allowedContentTypeUids = draftAndPublishOnly\n ? permittedContentTypes.filter((uid) => {\n return contentTypes.hasDraftAndPublish(strapi.contentType(uid));\n })\n : permittedContentTypes;\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(allowedContentTypeUids);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(allowedContentTypeUids, configurations);\n\n const recentDocuments = await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const permissionQuery = await getPermissionChecker(meta.uid).sanitizedQuery.read({\n limit: MAX_DOCUMENTS,\n fields: meta.fields,\n ...additionalQueryParams,\n });\n\n const docs = await strapi.documents(meta.uid).findMany(permissionQuery);\n const populate = additionalQueryParams?.populate as string[];\n\n return formatDocuments(docs, meta, populate);\n })\n );\n\n return recentDocuments\n .flat()\n .sort((a, b) => {\n switch (additionalQueryParams?.sort) {\n case 'publishedAt:desc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return b.publishedAt.valueOf() - a.publishedAt.valueOf();\n case 'publishedAt:asc':\n if (!a.publishedAt || !b.publishedAt) return 0;\n return a.publishedAt.valueOf() - b.publishedAt.valueOf();\n case 'updatedAt:desc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return b.updatedAt.valueOf() - a.updatedAt.valueOf();\n case 'updatedAt:asc':\n if (!a.updatedAt || !b.updatedAt) return 0;\n return a.updatedAt.valueOf() - b.updatedAt.valueOf();\n default:\n return 0;\n }\n })\n .slice(0, MAX_DOCUMENTS);\n },\n\n async getRecentlyPublishedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyPublishedDocuments = await this.queryLastDocuments(\n {\n sort: 'publishedAt:desc',\n status: 'published',\n },\n true\n );\n\n return this.addStatusToDocuments(recentlyPublishedDocuments);\n },\n\n async getRecentlyUpdatedDocuments(): Promise<GetRecentDocuments.Response['data']> {\n const recentlyUpdatedDocuments = await this.queryLastDocuments({\n sort: 'updatedAt:desc',\n });\n\n return this.addStatusToDocuments(recentlyUpdatedDocuments);\n },\n\n async getCountDocuments(): Promise<GetCountDocuments.Response['data']> {\n const permittedContentTypes = await getPermittedContentTypes();\n // Fetch the configuration for each content type in a single query\n const configurations = await getConfiguration(permittedContentTypes);\n // Get the necessary metadata for the documents\n const contentTypesMeta = getContentTypesMeta(permittedContentTypes, configurations);\n\n const countDocuments = {\n draft: 0,\n published: 0,\n modified: 0,\n };\n\n await Promise.all(\n contentTypesMeta.map(async (meta) => {\n const strapiDBConnection = strapi.db.connection;\n const tableName = strapi.contentType(meta.uid).collectionName;\n if (tableName) {\n const draftDocuments = await strapiDBConnection(tableName)\n .whereNull('published_at')\n .whereIn('document_id', function () {\n this.select('document_id')\n .from(tableName)\n .groupBy('document_id')\n .havingRaw('COUNT(*) = 1');\n })\n .count('* as count')\n .first();\n countDocuments.draft += Number(draftDocuments?.count) || 0;\n\n const publishedDocuments = meta.hasDraftAndPublish\n ? await strapiDBConnection(tableName)\n .select('draft.document_id')\n .from(`${tableName} as draft`)\n .join(`${tableName} as published`, function () {\n this.on('draft.document_id', '=', 'published.document_id')\n .andOn('draft.updated_at', '=', 'published.updated_at')\n .andOnNull('draft.published_at')\n .andOnNotNull('published.published_at');\n })\n .countDistinct('draft.document_id as count')\n .groupBy('draft.document_id')\n .first()\n : await strapiDBConnection(tableName)\n .select('document_id')\n .from(`${tableName}`)\n .countDistinct('document_id as count')\n .groupBy('document_id')\n .first();\n countDocuments.published += Number(publishedDocuments?.count) || 0;\n\n const modifiedDocuments = await strapiDBConnection(tableName)\n .select('draft.document_id')\n .from(`${tableName} as draft`)\n .join(`${tableName} as published`, function () {\n this.on('draft.document_id', '=', 'published.document_id')\n .andOn('draft.updated_at', '!=', 'published.updated_at')\n .andOnNull('draft.published_at')\n .andOnNotNull('published.published_at');\n })\n .countDistinct('draft.document_id as count')\n .groupBy('draft.document_id')\n .first();\n countDocuments.modified += Number(modifiedDocuments?.count) || 0;\n }\n })\n );\n\n return countDocuments;\n },\n };\n};\n\nexport { createHomepageService };\n"],"names":["createHomepageService","strapi","MAX_DOCUMENTS","metadataService","plugin","service","permissionService","admin","services","permission","getConfiguration","contentTypeUids","coreStore","db","query","rawConfigurations","findMany","where","key","$in","map","contentType","rawConfiguration","JSON","parse","value","getPermittedContentTypes","readPermissions","role","users","id","requestContext","get","state","user","action","subject","filter","Boolean","getContentTypesMeta","allowedContentTypeUids","configurations","uid","configuration","find","config","fields","hasDraftAndPublish","contentTypes","push","settings","mainField","isLocalized","pluginOptions","i18n","localized","formatDocuments","documents","meta","populate","document","additionalFields","reduce","acc","documentId","locale","updatedAt","Date","title","publishedAt","contentTypeUid","contentTypeDisplayName","info","displayName","kind","permissionCheckerService","getPermissionChecker","create","userAbility","model","addStatusToDocuments","Promise","all","recentDocument","availableStatus","getMetadata","availableLocales","status","getStatus","undefined","queryLastDocuments","additionalQueryParams","draftAndPublishOnly","permittedContentTypes","contentTypesMeta","recentDocuments","permissionQuery","sanitizedQuery","read","limit","docs","flat","sort","a","b","valueOf","slice","getRecentlyPublishedDocuments","recentlyPublishedDocuments","getRecentlyUpdatedDocuments","recentlyUpdatedDocuments","getCountDocuments","countDocuments","draft","published","modified","strapiDBConnection","connection","tableName","collectionName","draftDocuments","whereNull","whereIn","select","from","groupBy","havingRaw","count","first","Number","publishedDocuments","join","on","andOn","andOnNull","andOnNotNull","countDistinct","modifiedDocuments"],"mappings":"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"}
|