UNPKG

strapi-plugin-do-not-delete

Version:

A plugin for Strapi CMS that protects certain entries from being deleted.

1 lines 11.3 kB
{"version":3,"file":"index.mjs","sources":["../../server/src/constants.ts","../../server/src/utils/getService.ts","../../server/src/utils/isProtectedEntry.ts","../../server/src/bootstrap.ts","../../server/src/register.ts","../../server/src/services/validation.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'do-not-delete';\n","import { PLUGIN_ID } from '../constants';\nimport { type DoNotDeleteServices } from '../services';\n\nconst getService = <TName extends keyof DoNotDeleteServices>(\n name: TName\n): DoNotDeleteServices[TName] =>\n global.strapi.plugin(PLUGIN_ID).service<DoNotDeleteServices[TName]>(name);\n\nexport default getService;\n","import { type DoNotDeleteRule } from '../types';\n\nconst COMPARATOR_ACTIONS = {\n // Equality.\n is: (value, attr) => value === attr,\n isNot: (value, attr) => value !== attr,\n\n // Contains.\n has: (value, attr) => attr.includes(value),\n hasNot: (value, attr) => !attr.includes(value),\n in: (value, attr) => value.includes(attr),\n notIn: (value, attr) => !value.includes(attr),\n\n // Greater than or equal to.\n between: (value, attr) => attr >= value[0] && attr <= value[1],\n gt: (value, attr) => attr > value,\n gte: (value, attr) => attr >= value,\n lt: (value, attr) => attr < value,\n lte: (value, attr) => attr <= value,\n\n // Dates.\n after: (value, attr) => new Date(attr) > new Date(value),\n before: (value, attr) => new Date(attr) < new Date(value),\n day: (value, attr) => {\n const d1 = new Date(attr);\n const d2 = new Date(value);\n\n return (\n d1.getUTCDate() === d2.getUTCDate() &&\n d1.getUTCMonth() === d2.getUTCMonth() &&\n d1.getUTCFullYear() === d2.getUTCFullYear()\n );\n },\n month: (value, attr) => {\n const d1 = new Date(attr);\n const d2 = new Date(value);\n\n return d1.getUTCMonth() === d2.getUTCMonth() && d1.getUTCFullYear() === d2.getUTCFullYear();\n },\n year: (value, attr) => new Date(attr).getUTCFullYear() === new Date(value).getUTCFullYear(),\n\n // Regular expression.\n matches: (value, attr) => RegExp(value).test(attr),\n};\n\nconst isProtectedEntry = (entity: any, rules: DoNotDeleteRule[]): boolean =>\n rules.some((rule) => {\n const [attr, comparator, value] = rule;\n const entityAttr = entity[attr];\n const comparatorAction = COMPARATOR_ACTIONS[comparator];\n\n return !!(comparatorAction && comparatorAction(value, entityAttr));\n });\n\nexport default isProtectedEntry;\n","import { type Core, type UID } from '@strapi/strapi';\n\nimport { PLUGIN_ID } from './constants';\nimport { type DoNotDeletePluginOptions } from './types';\nimport { getService } from './utils';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n const validateService = getService('validation');\n\n // Verify any \"do not delete\" plugin options.\n Object.keys(strapi.contentTypes).forEach((uid: UID.ContentType) => {\n const contentType = strapi.contentTypes[uid];\n const pluginOptions = contentType.pluginOptions\n ? (contentType.pluginOptions[PLUGIN_ID] as DoNotDeletePluginOptions)\n : null;\n\n if (pluginOptions) {\n validateService.validatePluginOptions(uid, pluginOptions);\n }\n });\n};\n\nexport default bootstrap;\n","import { type Core } from '@strapi/strapi';\n\nimport { PLUGIN_ID } from './constants';\nimport { getService } from './utils';\n\nconst register = async ({ strapi }: { strapi: Core.Strapi }) => {\n const validateService = getService('validation');\n\n // Middleware for the documents \"delete\" action.\n strapi.documents.use(async (context: any, next) => {\n const { action, contentType, params, uid } = context;\n const { documentId } = params;\n const pluginOptions = contentType.pluginOptions[PLUGIN_ID];\n\n // Only run if this is a \"delete\" action and the contentType is configured for this plugin.\n if (!['delete'].includes(action) || !pluginOptions) {\n return next();\n }\n\n // Ensure the entity exists.\n const entity = await strapi.documents(uid).findOne({ documentId });\n\n if (!entity) {\n return;\n }\n\n // Validate the delete action.\n validateService.validateDeleteAction(entity, pluginOptions.rules);\n\n return next();\n });\n};\n\nexport default register;\n","import { type UID } from '@strapi/strapi';\nimport { errors } from '@strapi/utils';\n\nimport { type DoNotDeletePluginOptions, type DoNotDeleteRule } from '../types';\nimport { isProtectedEntry } from '../utils';\n\nexport type ValidationService = ReturnType<typeof validationService>;\n\nconst validationService = () => ({\n validateDeleteAction(entry: any, rules: DoNotDeleteRule[]): void {\n if (!rules || !rules.length) {\n return;\n }\n\n // Do not delete if this is a protected entry.\n if (isProtectedEntry(entry, rules)) {\n throw new errors.ValidationError('This entry is protected and cannot be deleted.');\n }\n },\n\n validatePluginOptions(uid: UID.ContentType, options: DoNotDeletePluginOptions): void {\n // Require array for the `rules` prop.\n if (!Array.isArray(options.rules)) {\n throw new errors.ValidationError(\n `Must define delete protection rules as an array for ${uid}.`\n );\n }\n\n options.rules.forEach((rule) => {\n // Require an array for each rule.\n if (!Array.isArray(rule)) {\n throw new errors.ValidationError(\n `Must define delete protection rules as an array for ${uid}.`\n );\n }\n\n // Require all 3 arguments per rule.\n if (rule.length !== 3) {\n throw new errors.ValidationError(\n `Must define delete protection rules with all arguments for ${uid}.`\n );\n }\n\n const comparator = rule[1];\n const value = rule[2];\n const comparators = [\n 'after',\n 'before',\n 'between',\n 'has',\n 'hasNot',\n 'in',\n 'notIn',\n 'is',\n 'isNot',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'day',\n 'month',\n 'year',\n 'matches',\n ];\n\n // Validate each `comparator` arg is a valid comparator.\n if (!comparators.includes(comparator)) {\n throw new errors.ValidationError(\n `Unknown comparator ${comparator} used for ${uid} protection rules.`\n );\n }\n\n // Validate `in` and `notIn` comparators are compared against an array `value`.\n if (['in', 'notIn', 'between'].includes(comparator) && !Array.isArray(value)) {\n throw new errors.ValidationError(\n `Invalid ${comparator} value for ${uid} protection rules.`\n );\n }\n\n // Validate `between` comparators are compared against an array of 2 `values`.\n if (comparator === 'between' && value.length !== 2) {\n throw new errors.ValidationError(\n `Invalid number of array values for between comparators for ${uid} protection rules.`\n );\n }\n\n // Validate date comparators are compared against a valid date string.\n if (['day', 'month', 'year'].includes(comparator)) {\n throw new errors.ValidationError(\n `Invalid date string for ${comparator} value for ${uid} protection rules.`\n );\n }\n });\n },\n});\n\nexport default validationService;\n","import validation, { type ValidationService } from './validation';\n\nexport type DoNotDeleteServices = {\n validation: ValidationService;\n};\n\nexport default {\n validation,\n};\n","import bootstrap from './bootstrap';\nimport register from './register';\nimport services from './services';\n\nexport default {\n bootstrap,\n register,\n services,\n};\n"],"names":["validation"],"mappings":"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"}