UNPKG

strapi-plugin-soft-delete

Version:

Add a soft delete feature to your project

187 lines (186 loc) 7.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../utils"); const utils_2 = require("./utils"); const plugin_1 = require("../utils/plugin"); const sdWrapParams = async (defaultService, opts, ctx) => { const { uid, action } = ctx; const wrappedParams = await defaultService.wrapParams(opts, ctx); if (!utils_1.plugin.supportsContentType(uid)) { return wrappedParams; } // Prevent users to set values for _softDeletedAt, _softDeletedById, and _softDeletedByType if (wrappedParams.data) { delete wrappedParams.data._softDeletedAt; delete wrappedParams.data._softDeletedById; delete wrappedParams.data._softDeletedByType; } return { ...wrappedParams, filters: { $and: [ { ...wrappedParams.filters }, { _softDeletedAt: { $null: true }, }, ], }, }; }; exports.default = async ({ strapi }) => { // Setup Plugin Settings const pluginStore = strapi.store({ environment: strapi.config.environment, type: 'plugin', name: utils_1.plugin.pluginId, }); const pluginStoreSettings = await pluginStore.get({ key: 'settings' }); if (!pluginStoreSettings || !pluginStoreSettings.singleTypesRestorationBehavior || !pluginStoreSettings.draftPublishRestorationBehavior) { const defaultSettings = { singleTypesRestorationBehavior: (pluginStoreSettings === null || pluginStoreSettings === void 0 ? void 0 : pluginStoreSettings.singleTypesRestorationBehavior) || 'soft-delete', draftPublishRestorationBehavior: (pluginStoreSettings === null || pluginStoreSettings === void 0 ? void 0 : pluginStoreSettings.draftPublishRestorationBehavior) || 'unchanged', }; await pluginStore.set({ key: 'settings', value: defaultSettings }); } // Setup Permissions strapi.admin.services.permission.actionProvider.get('plugin::content-manager.explorer.delete').displayName = 'Soft Delete'; const contentTypeUids = Object.keys(strapi.contentTypes).filter(utils_1.plugin.supportsContentType); strapi.admin.services.permission.actionProvider.register({ uid: 'read', displayName: 'Read', pluginName: utils_1.plugin.pluginId, section: 'plugins', }); strapi.admin.services.permission.actionProvider.register({ uid: 'settings', displayName: 'Settings', pluginName: utils_1.plugin.pluginId, section: 'plugins', }); strapi.admin.services.permission.actionProvider.register({ uid: 'explorer.read', options: { applyToProperties: ['locales'] }, section: 'contentTypes', displayName: 'Deleted Read', pluginName: utils_1.plugin.pluginId, subjects: contentTypeUids, }); strapi.admin.services.permission.actionProvider.register({ uid: 'explorer.restore', options: { applyToProperties: ['locales'] }, section: 'contentTypes', displayName: 'Deleted Restore', pluginName: utils_1.plugin.pluginId, subjects: contentTypeUids, }); strapi.admin.services.permission.actionProvider.register({ uid: 'explorer.delete-permanently', options: { applyToProperties: ['locales'] }, section: 'contentTypes', displayName: 'Delete Permanently', pluginName: utils_1.plugin.pluginId, subjects: contentTypeUids, }); // 'Decorate' Strapi's EventHub to prevent firing 'entry.update' events from soft-delete plugin const defaultEventHubEmit = strapi.eventHub.emit; strapi.eventHub.emit = async (event, ...args) => { var _a; const data = args[0]; if ((0, plugin_1.supportsContentType)(data.uid) && event === 'entry.update' && ((_a = data.plugin) === null || _a === void 0 ? void 0 : _a.id) !== utils_1.plugin.pluginId) { const entry = await strapi.query(data.uid).findOne({ select: 'id', where: { id: data.entry.id, _softDeletedAt: null } }); if (!entry) { return; } } await defaultEventHubEmit(event, ...args); }; // Decorate Entity Services strapi.entityService.decorate((defaultService) => ({ delete: async (uid, id, opts) => { if (!utils_1.plugin.supportsContentType(uid)) { return await defaultService.delete(uid, id, opts); } const wrappedParams = await defaultService.wrapParams(opts, { uid, action: 'delete' }); const ctx = strapi.requestContext.get(); const { id: authId, strategy: authStrategy } = (0, utils_2.getSoftDeletedByAuth)(ctx.state.auth); const entity = await defaultService.update(uid, id, { ...wrappedParams, data: { ...wrappedParams.data, _softDeletedAt: Date.now(), _softDeletedById: authId, _softDeletedByType: authStrategy, }, }); (0, utils_2.eventHubEmit)({ uid, event: 'entry.delete', action: 'soft-delete', entity: entity, }); return entity; }, deleteMany: async (uid, opts) => { if (!utils_1.plugin.supportsContentType(uid)) { return await defaultService.deleteMany(uid, opts); } const wrappedParams = await defaultService.wrapParams(opts, { uid, action: 'deleteMany' }); const ctx = strapi.requestContext.get(); const { id: authId, strategy: authStrategy } = (0, utils_2.getSoftDeletedByAuth)(ctx.state.auth); // TODO: Optimize decoratedService.deleteMany to use a single query? const entitiesToDelete = await defaultService.findMany(uid, wrappedParams); const deletedEntities = []; for (let entityToDelete of entitiesToDelete) { const deletedEntity = await defaultService.update(uid, entityToDelete.id, { data: { _softDeletedAt: Date.now(), _softDeletedById: authId, _softDeletedByType: authStrategy, }, }); if (deletedEntity) { deletedEntities.push(deletedEntity); } (0, utils_2.eventHubEmit)({ uid, event: 'entry.delete', action: 'soft-delete', entity: deletedEntity, }); } return deletedEntities; }, findOne: async (uid, id, opts) => { if (!utils_1.plugin.supportsContentType(uid)) { return await defaultService.findOne(uid, id, opts); } // Because of other plugins, like i18n, we need to use the findMany method to ignore upstream filters const entities = await strapi.query(uid).findMany({ where: { id, _softDeletedAt: { $null: true, }, }, }); if (entities.length === 0) { return null; } // And then use the defaultService findOne method to apply the upstream filters and not break the decorate pattern chain return defaultService.findOne(uid, id, opts); }, wrapParams: async (opts, ctx) => { return await sdWrapParams(defaultService, opts, ctx); }, })); };