{"version":3,"file":"validation.mjs","sources":["../../../server/src/services/validation.ts"],"sourcesContent":["import { errors, contentTypes } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { Release, CreateRelease, UpdateRelease } from '../../../shared/contracts/releases';\nimport type { CreateReleaseAction } from '../../../shared/contracts/release-actions';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nexport class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnReleaseError'> {\n  constructor(message: string) {\n    super(message);\n    this.name = 'AlreadyOnReleaseError';\n  }\n}\n\nconst createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({\n  async validateUniqueEntry(\n    releaseId: CreateReleaseAction.Request['params']['releaseId'],\n    releaseActionArgs: CreateReleaseAction.Request['body']\n  ) {\n    /**\n     * Asserting the type, otherwise TS complains: 'release.actions' is of type 'unknown', even though the types come through for non-populated fields...\n     * Possibly related to the comment on GetValues: https://github.com/strapi/strapi/blob/main/packages/core/types/src/modules/entity-service/result.ts\n     */\n    const release = (await strapi.db.query(RELEASE_MODEL_UID).findOne({\n      where: {\n        id: releaseId,\n      },\n      populate: {\n        actions: true,\n      },\n    })) as Release | null;\n\n    if (!release) {\n      throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n    }\n\n    const isEntryInRelease = release.actions.some(\n      (action) =>\n        action.entryDocumentId === releaseActionArgs.entryDocumentId &&\n        action.contentType === releaseActionArgs.contentType &&\n        (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)\n    );\n\n    if (isEntryInRelease) {\n      throw new AlreadyOnReleaseError(\n        `Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ''} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`\n      );\n    }\n  },\n  validateEntryData(\n    contentTypeUid: CreateReleaseAction.Request['body']['contentType'],\n    entryDocumentId: CreateReleaseAction.Request['body']['entryDocumentId']\n  ) {\n    const contentType = strapi.contentType(contentTypeUid as UID.ContentType);\n\n    if (!contentType) {\n      throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);\n    }\n\n    if (!contentTypes.hasDraftAndPublish(contentType)) {\n      throw new errors.ValidationError(\n        `Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`\n      );\n    }\n\n    if (contentType.kind === 'collectionType' && !entryDocumentId) {\n      throw new errors.ValidationError('Document id is required for collection type');\n    }\n  },\n  async validatePendingReleasesLimit() {\n    // Use the maximum releases option if it exists, otherwise default to 3\n    const featureCfg = strapi.ee.features.get('cms-content-releases');\n\n    const maximumPendingReleases =\n      (typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;\n\n    const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({\n      filters: {\n        releasedAt: {\n          $null: true,\n        },\n      },\n    });\n\n    // Unlimited is a number that will never be reached like 9999\n    if (pendingReleasesCount >= maximumPendingReleases) {\n      throw new errors.ValidationError('You have reached the maximum number of pending releases');\n    }\n  },\n  async validateUniqueNameForPendingRelease(\n    name: CreateRelease.Request['body']['name'],\n    id?: UpdateRelease.Request['params']['id']\n  ) {\n    const pendingReleases = (await strapi.db.query(RELEASE_MODEL_UID).findMany({\n      where: {\n        releasedAt: {\n          $null: true,\n        },\n        name,\n        ...(id && { id: { $ne: id } }),\n      },\n    })) as Release[];\n\n    const isNameUnique = pendingReleases.length === 0;\n\n    if (!isNameUnique) {\n      throw new errors.ValidationError(`Release with name ${name} already exists`);\n    }\n  },\n  async validateScheduledAtIsLaterThanNow(\n    scheduledAt: CreateRelease.Request['body']['scheduledAt']\n  ) {\n    if (scheduledAt && new Date(scheduledAt) <= new Date()) {\n      throw new errors.ValidationError('Scheduled at must be later than now');\n    }\n  },\n});\n\nexport default createReleaseValidationService;\n"],"names":["AlreadyOnReleaseError","errors","ApplicationError","message","name","createReleaseValidationService","strapi","validateUniqueEntry","releaseId","releaseActionArgs","release","db","query","RELEASE_MODEL_UID","findOne","where","id","populate","actions","NotFoundError","isEntryInRelease","some","action","entryDocumentId","contentType","locale","validateEntryData","contentTypeUid","contentTypes","hasDraftAndPublish","ValidationError","kind","validatePendingReleasesLimit","featureCfg","ee","features","get","maximumPendingReleases","options","maximumReleases","pendingReleasesCount","findWithCount","filters","releasedAt","$null","validateUniqueNameForPendingRelease","pendingReleases","findMany","$ne","isNameUnique","length","validateScheduledAtIsLaterThanNow","scheduledAt","Date"],"mappings":"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"}