strapi-plugin-soft-delete
Version:
Add a soft delete feature to your project
187 lines (186 loc) • 7.92 kB
JavaScript
"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);
},
}));
};