Checks for dependencies during deletion.
This commit is contained in:
parent
0a08088893
commit
efbfa2b366
20 changed files with 246 additions and 121 deletions
|
@ -467,7 +467,12 @@ async function remove(context, id) {
|
|||
return new interoperableErrors.InvalidStateError;
|
||||
}
|
||||
|
||||
// FIXME - deal with deletion of dependent entities (files)
|
||||
await files.removeAllTx(tx, context, 'campaign', 'file', id);
|
||||
await files.removeAllTx(tx, context, 'campaign', 'attachment', id);
|
||||
|
||||
await tx('campaign_lists').where('campaign', id).del();
|
||||
await tx('campaign_messages').where('campaign', id).del();
|
||||
await tx('campaign_links').where('campaign', id).del();
|
||||
|
||||
await triggers.removeAllByCampaignIdTx(tx, context, id);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ const path = require('path');
|
|||
const mjml = require('mjml');
|
||||
const _ = require('../lib/translate')._;
|
||||
const lists = require('./lists');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const formAllowedKeys = new Set([
|
||||
'name',
|
||||
|
@ -173,7 +174,9 @@ async function remove(context, id) {
|
|||
await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'customForm', id, 'delete');
|
||||
|
||||
await lists.removeFormFromAllTx(tx, context, id);
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{ entityTypeId: 'list', column: 'default_form' }
|
||||
]);
|
||||
|
||||
await tx('custom_forms_data').where('form', id).del();
|
||||
await tx('custom_forms').where('id', id).del();
|
||||
|
|
|
@ -10,7 +10,9 @@ const shares = require('./shares');
|
|||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
const fields = require('./fields');
|
||||
const segments = require('./segments');
|
||||
const imports = require('./imports');
|
||||
const entitySettings = require('../lib/entity-settings');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const UnsubscriptionMode = require('../shared/lists').UnsubscriptionMode;
|
||||
|
||||
|
@ -176,23 +178,23 @@ async function remove(context, id) {
|
|||
|
||||
await fields.removeAllByListIdTx(tx, context, id);
|
||||
await segments.removeAllByListIdTx(tx, context, id);
|
||||
await imports.removeAllByListIdTx(tx, context, id);
|
||||
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{
|
||||
entityTypeId: 'campaign',
|
||||
query: tx => tx('campaign_lists')
|
||||
.where('campaign_lists.list', id)
|
||||
.innerJoin('campaigns', 'campaign_lists.campaign', 'campaigns.id')
|
||||
.select(['campaigns.id', 'campaigns.name'])
|
||||
}
|
||||
]);
|
||||
|
||||
await tx('lists').where('id', id).del();
|
||||
await knex.schema.dropTableIfExists('subscription__' + id);
|
||||
});
|
||||
}
|
||||
|
||||
async function removeFormFromAllTx(tx, context, formId) {
|
||||
await knex.transaction(async tx => {
|
||||
const entities = tx('lists').where('default_form', formId).select(['id']);
|
||||
|
||||
for (const entity of entities) {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'list', entity.id, 'edit');
|
||||
await tx('lists').where('id', entity.id).update({default_form: null});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function getMergeTags(context, id) {
|
||||
return await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'list', id, ['view']);
|
||||
|
@ -224,5 +226,4 @@ module.exports.getByCid = getByCid;
|
|||
module.exports.create = create;
|
||||
module.exports.updateWithConsistencyCheck = updateWithConsistencyCheck;
|
||||
module.exports.remove = remove;
|
||||
module.exports.removeFormFromAllTx = removeFormFromAllTx;
|
||||
module.exports.getMergeTags = getMergeTags;
|
||||
|
|
|
@ -7,6 +7,8 @@ const dtHelpers = require('../lib/dt-helpers');
|
|||
const interoperableErrors = require('../shared/interoperable-errors');
|
||||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
const shares = require('./shares');
|
||||
const files = require('./files');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const allowedKeys = new Set(['name', 'description', 'type', 'data', 'namespace']);
|
||||
|
||||
|
@ -84,22 +86,34 @@ async function updateWithConsistencyCheck(context, entity) {
|
|||
async function remove(context, id) {
|
||||
await knex.transaction(async tx => {
|
||||
const deps = [];
|
||||
const tmpls = await tx('templates').where('type', 'mosaico').select(['id', 'name', 'data']);
|
||||
for (const row of tmpls) {
|
||||
const data = JSON.parse(row.data);
|
||||
if (data.mosaicoTemplate === id) {
|
||||
deps.push({ entityTypeId: 'template', name: row.name, link: `templates/${row.id}` });
|
||||
}
|
||||
}
|
||||
|
||||
if (deps.length > 0) {
|
||||
throw new interoperableErrors.DependencyPresentError('', {
|
||||
dependencies: deps
|
||||
});
|
||||
}
|
||||
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'mosaicoTemplate', id, 'delete');
|
||||
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{
|
||||
entityTypeId: 'template',
|
||||
rows: async (tx, limit) => {
|
||||
const result = [];
|
||||
|
||||
const tmpls = await tx('templates').where('type', 'mosaico').select(['id', 'name', 'data']);
|
||||
for (const tmpl of tmpls) {
|
||||
const data = JSON.parse(tmpl.data);
|
||||
if (data.mosaicoTemplate === id) {
|
||||
result.push(tmpl);
|
||||
}
|
||||
|
||||
limit -= 1;
|
||||
if (limit <= 0) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
await files.removeAllTx(tx, context, 'mosaicoTemplate', 'file', id);
|
||||
await files.removeAllTx(tx, context, 'mosaicoTemplate', 'block', id);
|
||||
|
||||
await tx('mosaico_templates').where('id', id).del();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ const interoperableErrors = require('../shared/interoperable-errors');
|
|||
const shares = require('./shares');
|
||||
const entitySettings = require('../lib/entity-settings');
|
||||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
|
||||
const allowedKeys = new Set(['name', 'description', 'namespace']);
|
||||
|
@ -176,12 +177,8 @@ async function remove(context, id) {
|
|||
await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'namespace', id, 'delete');
|
||||
|
||||
const childNs = await tx('namespaces').where('namespace', id).first();
|
||||
if (childNs) {
|
||||
throw new interoperableErrors.ChildDetectedError();
|
||||
}
|
||||
|
||||
// FIXME - Remove all contained entities first
|
||||
const entityTypesWithNamespace = Object.keys(entitySettings.getEntityTypes());
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, entityTypesWithNamespace.map(entityTypeId => ({ entityTypeId: entityTypeId, column: 'namespace' })));
|
||||
|
||||
await tx('namespaces').where('id', id).del();
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ const interoperableErrors = require('../shared/interoperable-errors');
|
|||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
const shares = require('./shares');
|
||||
const reports = require('./reports');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const allowedKeys = new Set(['name', 'description', 'mime_type', 'user_fields', 'js', 'hbs', 'namespace']);
|
||||
|
||||
|
@ -77,7 +78,9 @@ async function remove(context, id) {
|
|||
await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'reportTemplate', id, 'delete');
|
||||
|
||||
await reports.removeAllByReportTemplateIdTx(tx, context, id);
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{ entityTypeId: 'report', column: 'report_template' }
|
||||
]);
|
||||
|
||||
await tx('report_templates').where('id', id).del();
|
||||
});
|
||||
|
|
|
@ -8,6 +8,8 @@ const interoperableErrors = require('../shared/interoperable-errors');
|
|||
const fields = require('./fields');
|
||||
const namespaceHelpers = require('../lib/namespace-helpers');
|
||||
const shares = require('./shares');
|
||||
const reportHelpers = require('../lib/report-helpers');
|
||||
const fs = require('fs-extra-promise');
|
||||
|
||||
const ReportState = require('../shared/reports').ReportState;
|
||||
|
||||
|
@ -114,9 +116,12 @@ async function updateWithConsistencyCheck(context, entity) {
|
|||
async function removeTx(tx, context, id) {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'report', id, 'delete');
|
||||
|
||||
await tx('reports').where('id', id).del();
|
||||
const report = tx('reports').where('id', id).first();
|
||||
|
||||
// FIXME: Remove generated files
|
||||
await fs.removeAsync(reportHelpers.getReportContentFile(report));
|
||||
await fs.removeAsync(reportHelpers.getReportOutputFile(report));
|
||||
|
||||
await tx('reports').where('id', id).del();
|
||||
}
|
||||
|
||||
async function remove(context, id) {
|
||||
|
@ -125,14 +130,6 @@ async function remove(context, id) {
|
|||
});
|
||||
}
|
||||
|
||||
async function removeAllByReportTemplateIdTx(tx, context, templateId) {
|
||||
const entities = await tx('reports').where('report_template', templateId).select(['id']);
|
||||
for (const entity of entities) {
|
||||
await removeTx(tx, context, entity.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function updateFields(id, fields) {
|
||||
return await knex('reports').where('id', id).update(fields);
|
||||
}
|
||||
|
@ -203,7 +200,6 @@ module.exports.listDTAjax = listDTAjax;
|
|||
module.exports.create = create;
|
||||
module.exports.updateWithConsistencyCheck = updateWithConsistencyCheck;
|
||||
module.exports.remove = remove;
|
||||
module.exports.removeAllByReportTemplateIdTx = removeAllByReportTemplateIdTx;
|
||||
module.exports.updateFields = updateFields;
|
||||
module.exports.listByState = listByState;
|
||||
module.exports.bulkChangeState = bulkChangeState;
|
||||
|
|
|
@ -9,6 +9,7 @@ const hasher = require('node-object-hash')();
|
|||
const moment = require('moment');
|
||||
const fields = require('./fields');
|
||||
const subscriptions = require('./subscriptions');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const { parseDate, parseBirthday, DateFormat } = require('../shared/date');
|
||||
|
||||
|
@ -331,7 +332,15 @@ async function updateWithConsistencyCheck(context, listId, entity) {
|
|||
async function removeTx(tx, context, listId, id) {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageSegments');
|
||||
|
||||
// FIXME - check dependencies: campaigns
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{
|
||||
entityTypeId: 'campaign',
|
||||
query: tx => tx('campaign_lists')
|
||||
.where('campaign_lists.segment', id)
|
||||
.innerJoin('campaigns', 'campaign_lists.campaign', 'campaigns.id')
|
||||
.select(['campaigns.id', 'campaigns.name'])
|
||||
}
|
||||
]);
|
||||
|
||||
// The listId "where" is here to prevent deleting segment of a list for which a user does not have permission
|
||||
await tx('segments').where({list: listId, id}).del();
|
||||
|
|
|
@ -12,6 +12,7 @@ const {MailerType, getSystemSendConfigurationId} = require('../shared/send-confi
|
|||
const contextHelpers = require('../lib/context-helpers');
|
||||
const mailers = require('../lib/mailers');
|
||||
const senders = require('../lib/senders');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const allowedKeys = new Set(['name', 'description', 'from_email', 'from_email_overridable', 'from_name', 'from_name_overridable', 'reply_to', 'reply_to_overridable', 'subject', 'subject_overridable', 'x_mailer', 'verp_hostname', 'mailer_type', 'mailer_settings', 'namespace']);
|
||||
|
||||
|
@ -147,9 +148,11 @@ async function remove(context, id) {
|
|||
await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'sendConfiguration', id, 'delete');
|
||||
|
||||
await tx('lists').update({send_configuration: null}).where('send_configuration', id);
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{ entityTypeId: 'campaign', column: 'send_configuration' },
|
||||
{ entityTypeId: 'list', column: 'send_configuration' }
|
||||
]);
|
||||
|
||||
// If any campaign with the send configuration exists, this fails due to sql foreign key
|
||||
await tx('send_configurations').where('id', id).del();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ async function rebuildPermissionsTx(tx, restriction) {
|
|||
[restriction.entityTypeId]: entityType
|
||||
};
|
||||
} else {
|
||||
restrictedEntityTypes = entitySettings.getEntityTypes();
|
||||
restrictedEntityTypes = entitySettings.getEntityTypesWithPermissions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,7 +375,7 @@ async function regenerateRoleNamesTable() {
|
|||
await knex.transaction(async tx => {
|
||||
await tx('generated_role_names').del();
|
||||
|
||||
const entityTypeIds = ['global', ...Object.keys(entitySettings.getEntityTypes())];
|
||||
const entityTypeIds = ['global', ...Object.keys(entitySettings.getEntityTypesWithPermissions())];
|
||||
|
||||
for (const entityTypeId of entityTypeIds) {
|
||||
const roles = config.roles[entityTypeId];
|
||||
|
@ -539,6 +539,14 @@ async function checkEntityPermission(context, entityTypeId, entityId, requiredOp
|
|||
});
|
||||
}
|
||||
|
||||
async function checkEntityPermissionTx(tx, context, entityTypeId, entityId, requiredOperations) {
|
||||
if (!entityId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await _checkPermissionTx(tx, context, entityTypeId, entityId, requiredOperations);
|
||||
}
|
||||
|
||||
async function checkTypePermission(context, entityTypeId, requiredOperations) {
|
||||
return await knex.transaction(async tx => {
|
||||
return await _checkPermissionTx(tx, context, entityTypeId, null, requiredOperations);
|
||||
|
@ -626,6 +634,7 @@ module.exports.enforceEntityPermission = enforceEntityPermission;
|
|||
module.exports.enforceEntityPermissionTx = enforceEntityPermissionTx;
|
||||
module.exports.enforceTypePermission = enforceTypePermission;
|
||||
module.exports.enforceTypePermissionTx = enforceTypePermissionTx;
|
||||
module.exports.checkEntityPermissionTx = checkEntityPermissionTx;
|
||||
module.exports.checkEntityPermission = checkEntityPermission;
|
||||
module.exports.checkTypePermission = checkTypePermission;
|
||||
module.exports.enforceGlobalPermission = enforceGlobalPermission;
|
||||
|
|
|
@ -9,6 +9,7 @@ const namespaceHelpers = require('../lib/namespace-helpers');
|
|||
const shares = require('./shares');
|
||||
const reports = require('./reports');
|
||||
const files = require('./files');
|
||||
const dependencyHelpers = require('../lib/dependency-helpers');
|
||||
|
||||
const allowedKeys = new Set(['name', 'description', 'type', 'data', 'html', 'text', 'namespace']);
|
||||
|
||||
|
@ -97,17 +98,15 @@ async function remove(context, id) {
|
|||
await knex.transaction(async tx => {
|
||||
await shares.enforceEntityPermissionTx(tx, context, 'template', id, 'delete');
|
||||
|
||||
const depCampaigns = await tx('template_dep_campaigns')
|
||||
.where('template_dep_campaigns.template', id)
|
||||
.innerJoin('campaigns', 'template_dep_campaigns.campaign', 'campaigns.id')
|
||||
.limit(interoperableErrors.defaultNoOfDependenciesReported)
|
||||
.select(['campaigns.id', 'campaigns.name']);
|
||||
|
||||
if (depCampaigns.length > 0) {
|
||||
throw new interoperableErrors.DependencyPresentError('', {
|
||||
dependencies: depCampaigns.map(row => ({ entityTypeId: 'campaign', name: row.name, link: `campaigns/${row.id}` }))
|
||||
});
|
||||
}
|
||||
await dependencyHelpers.ensureNoDependencies(tx, context, id, [
|
||||
{
|
||||
entityTypeId: 'campaign',
|
||||
query: tx => tx('template_dep_campaigns')
|
||||
.where('template_dep_campaigns.template', id)
|
||||
.innerJoin('campaigns', 'template_dep_campaigns.campaign', 'campaigns.id')
|
||||
.select(['campaigns.id', 'campaigns.name'])
|
||||
}
|
||||
]);
|
||||
|
||||
await files.removeAllTx(tx, context, 'template', 'file', id);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue