work in progress on segments

some cleanup of models - handling dependencies in delete
This commit is contained in:
Tomas Bures 2017-08-14 22:53:29 +02:00
parent b23529a75b
commit 0bfb30817b
29 changed files with 553 additions and 990 deletions

View file

@ -10,6 +10,7 @@ const shares = require('./shares');
const bluebird = require('bluebird');
const validators = require('../shared/validators');
const shortid = require('shortid');
const segments = require('./segments');
const allowedKeysCreate = new Set(['name', 'key', 'default_value', 'type', 'group', 'settings']);
const allowedKeysUpdate = new Set(['name', 'key', 'default_value', 'group', 'settings']);
@ -353,32 +354,44 @@ async function updateWithConsistencyCheck(context, listId, entity) {
});
}
async function removeTx(tx, context, listId, id) {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageFields');
const existing = await tx('custom_fields').where({list: listId, id: id}).first();
if (!existing) {
throw new interoperableErrors.NotFoundError();
}
const fieldType = fieldTypes[existing.type];
await tx('custom_fields').where({list: listId, id}).del();
if (fieldType.grouped) {
await tx('custom_fields').where({list: listId, group: id}).del();
} else {
await knex.schema.table('subscription__' + listId, table => {
table.dropColumn(existing.column);
});
await segments.removeRulesByFieldIdTx(tx, context, listId, id);
}
}
async function remove(context, listId, id) {
await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageFields');
const existing = await tx('custom_fields').where({list: listId, id: id}).first();
if (!existing) {
throw new interoperableErrors.NotFoundError();
}
const fieldType = fieldTypes[existing.type];
await tx('custom_fields').where({list: listId, id}).del();
if (fieldType.grouped) {
await tx('custom_fields').where({list: listId, group: id}).del();
} else {
await knex.schema.table('subscription__' + listId, table => {
table.dropColumn(existing.column);
});
await tx('segemnt_rules').where({column: existing.column}).del();
}
await removeTx(tx, context, listId, id);
});
}
async function removeAllByListIdTx(tx, context, listId) {
const entities = await tx('custom_fields').where('list', listId).select(['id']);
for (const entity of entities) {
await removeTx(tx, context, listId, entity.id);
}
}
module.exports = {
hash,
getById,
@ -389,5 +402,6 @@ module.exports = {
create,
updateWithConsistencyCheck,
remove,
removeAllByListIdTx,
serverValidate
};

View file

@ -12,6 +12,7 @@ const fsReadFile = bluebird.promisify(require('fs').readFile);
const path = require('path');
const mjml = require('mjml');
const _ = require('../lib/translate')._;
const lists = require('./lists');
const formAllowedKeys = new Set([
'name',
@ -131,7 +132,7 @@ async function create(context, entity) {
})
}
await shares.rebuildPermissions(tx, { entityTypeId: 'customForm', entityId: id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'customForm', entityId: id });
return id;
});
}
@ -164,7 +165,7 @@ async function updateWithConsistencyCheck(context, entity) {
});
}
await shares.rebuildPermissions(tx, { entityTypeId: 'customForm', entityId: entity.id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'customForm', entityId: entity.id });
});
}
@ -172,11 +173,7 @@ async function remove(context, id) {
await knex.transaction(async tx => {
shares.enforceEntityPermissionTx(tx, context, 'customForm', id, 'delete');
const entity = await tx('custom_forms').where('id', id).first();
if (!entity) {
throw shares.throwPermissionDenied();
}
lists.removeFormFromAllTx(tx, context, id);
await tx('custom_forms_data').where('form', id).del();
await tx('custom_forms').where('id', id).del();

View file

@ -9,6 +9,7 @@ const interoperableErrors = require('../shared/interoperable-errors');
const shares = require('./shares');
const namespaceHelpers = require('../lib/namespace-helpers');
const fields = require('./fields');
const segments = require('./segments');
const UnsubscriptionMode = require('../shared/lists').UnsubscriptionMode;
@ -56,7 +57,7 @@ async function create(context, entity) {
await knex.schema.raw('CREATE TABLE `subscription__' + id + '` LIKE subscription');
await shares.rebuildPermissions(tx, { entityTypeId: 'list', entityId: id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'list', entityId: id });
return id;
});
@ -82,7 +83,7 @@ async function updateWithConsistencyCheck(context, entity) {
await tx('lists').where('id', entity.id).update(filterObject(entity, allowedKeys));
await shares.rebuildPermissions(tx, { entityTypeId: 'list', entityId: entity.id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'list', entityId: entity.id });
});
}
@ -90,11 +91,25 @@ async function remove(context, id) {
await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', id, 'delete');
await fields.removeAllByListIdTx(tx, context, id);
await segments.removeAllByListIdTx(tx, context, id);
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});
}
});
}
module.exports = {
UnsubscriptionMode,
@ -103,5 +118,6 @@ module.exports = {
getById,
create,
updateWithConsistencyCheck,
remove
remove,
removeFormFromAllTx
};

View file

@ -126,7 +126,7 @@ async function create(context, entity) {
const id = ids[0];
// We don't have to rebuild all entity types, because no entity can be a child of the namespace at this moment.
await shares.rebuildPermissions(tx, { entityTypeId: 'namespace', entityId: id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'namespace', entityId: id });
return id;
});
@ -166,7 +166,7 @@ async function updateWithConsistencyCheck(context, entity) {
await tx('namespaces').where('id', entity.id).update(filterObject(entity, allowedKeys));
await shares.rebuildPermissions(tx);
await shares.rebuildPermissionsTx(tx);
});
}

View file

@ -7,6 +7,7 @@ const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors');
const namespaceHelpers = require('../lib/namespace-helpers');
const shares = require('./shares');
const reports = require('./reports');
const allowedKeys = new Set(['name', 'description', 'mime_type', 'user_fields', 'js', 'hbs', 'namespace']);
@ -42,7 +43,7 @@ async function create(context, entity) {
const ids = await tx('report_templates').insert(filterObject(entity, allowedKeys));
const id = ids[0];
await shares.rebuildPermissions(tx, { entityTypeId: 'reportTemplate', entityId: id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'reportTemplate', entityId: id });
return id;
});
@ -68,14 +69,18 @@ async function updateWithConsistencyCheck(context, entity) {
await tx('report_templates').where('id', entity.id).update(filterObject(entity, allowedKeys));
await shares.rebuildPermissions(tx, { entityTypeId: 'reportTemplate', entityId: entity.id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'reportTemplate', entityId: entity.id });
});
}
async function remove(context, id) {
await shares.enforceEntityPermission(context, 'reportTemplate', id, 'delete');
await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'reportTemplate', id, 'delete');
await knex('report_templates').where('id', id).del();
await reports.removeAllByReportTemplateIdTx(tx, context, id);
await tx('report_templates').where('id', id).del();
});
}
async function getUserFieldsById(context, id) {

View file

@ -68,7 +68,7 @@ async function create(context, entity) {
const ids = await tx('reports').insert(filterObject(entity, allowedKeys));
id = ids[0];
await shares.rebuildPermissions(tx, { entityTypeId: 'report', entityId: id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'report', entityId: id });
});
const reportProcessor = require('../lib/report-processor');
@ -103,7 +103,7 @@ async function updateWithConsistencyCheck(context, entity) {
await tx('reports').where('id', entity.id).update(filteredUpdates);
await shares.rebuildPermissions(tx, { entityTypeId: 'report', entityId: entity.id });
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'report', entityId: entity.id });
});
// This require is here to avoid cyclic dependency
@ -111,12 +111,28 @@ async function updateWithConsistencyCheck(context, entity) {
await reportProcessor.start(entity.id);
}
async function remove(context, id) {
await shares.enforceEntityPermission(context, 'report', id, 'delete');
async function removeTx(tx, context, id) {
await shares.enforceEntityPermissionTx(tx, context, 'report', id, 'delete');
await knex('reports').where('id', id).del();
await tx('reports').where('id', id).del();
// FIXME: Remove generated files
}
async function remove(context, id) {
await knex.transaction(async tx => {
await removeTx(tx, 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);
}
@ -186,8 +202,9 @@ module.exports = {
create,
updateWithConsistencyCheck,
remove,
removeAllByReportTemplateIdTx,
updateFields,
listByState,
bulkChangeState,
getCampaignResults
getCampaignResults,
};

View file

@ -5,17 +5,11 @@ const dtHelpers = require('../lib/dt-helpers');
const interoperableErrors = require('../shared/interoperable-errors');
const shares = require('./shares');
//const allowedKeys = new Set(['cid', 'email']);
const allowedKeys = new Set(['name', 'settings']);
/*
function hash(entity) {
const allowedKeys = allowedKeysBase.slice();
// TODO add keys from custom fields
return hasher.hash(filterObject(entity, allowedKeys));
}
*/
async function listDTAjax(context, listId, params) {
return await knex.transaction(async tx => {
@ -27,12 +21,11 @@ async function listDTAjax(context, listId, params) {
builder => builder
.from('segments')
.where('list', listId),
['id', 'name', 'type']
['id', 'name']
);
});
}
async function list(context, listId) {
return await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'viewSubscriptions');
@ -41,7 +34,82 @@ async function list(context, listId) {
});
}
async function getById(context, listId, id) {
return await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'viewSubscriptions');
const entity = await tx('segments').where({id, list: listId}).first();
entity.settings = JSON.parse(entity.settings);
return entity;
});
}
async function create(context, listId, entity) {
return await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageSegments');
entity.settings = JSON.stringify(entity.params);
const filteredEntity = filterObject(entity, allowedKeys);
filteredEntity.list = listId;
const ids = await tx('segments').insert(filteredEntity);
const id = ids[0];
return id;
});
}
async function updateWithConsistencyCheck(context, listId, entity) {
await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageSegments');
const existing = await tx('segments').where({list: listId, id: entity.id}).first();
if (!existing) {
throw new interoperableErrors.NotFoundError();
}
const existingHash = hash(existing);
if (existingHash !== entity.originalHash) {
throw new interoperableErrors.ChangedError();
}
entity.settings = JSON.stringify(entity.params);
await tx('segments').where('id', entity.id).update(filterObject(entity, allowedKeys));
});
}
async function removeTx(tx, context, listId, id) {
await shares.enforceEntityPermissionTx(tx, context, 'list', listId, 'manageSegments');
// 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: id}).del();
}
async function remove(context, listId, id) {
await knex.transaction(async tx => {
await removeTx(tx, context, listId, id);
});
}
async function removeAllByListIdTx(tx, context, listId) {
const entities = await tx('segments').where('list', listId).select(['id']);
for (const entity of entities) {
await removeTx(tx, context, entity.id);
}
}
async function removeRulesByFieldIdTx(tx, context, listId, fieldId) {
// FIXME
}
module.exports = {
listDTAjax,
list
list,
create,
updateWithConsistencyCheck,
remove,
removeAllByListIdTx,
removeRulesByFieldIdTx
};

View file

@ -115,14 +115,16 @@ async function assign(context, entityTypeId, entityId, userId, role) {
await tx(entityType.permissionsTable).where({user: userId, entity: entityId}).del();
if (entityTypeId === 'namespace') {
await rebuildPermissions(tx, {userId});
await rebuildPermissionsTx(tx, {userId});
} else if (role) {
await rebuildPermissions(tx, { entityTypeId, entityId, userId });
await rebuildPermissionsTx(tx, { entityTypeId, entityId, userId });
}
});
}
async function _rebuildPermissions(tx, restriction) {
async function rebuildPermissionsTx(tx, restriction) {
restriction = restriction || {};
const namespaceEntityType = permissions.getEntityType('namespace');
// Collect entity types we care about
@ -358,16 +360,10 @@ async function _rebuildPermissions(tx, restriction) {
}
}
async function rebuildPermissions(tx, restriction) {
restriction = restriction || {};
if (tx) {
await _rebuildPermissions(tx, restriction);
} else {
await knex.transaction(async tx => {
await _rebuildPermissions(tx, restriction);
});
}
async function rebuildPermissions(restriction) {
await knex.transaction(async tx => {
await rebuildPermissionsTx(tx, restriction);
});
}
async function regenerateRoleNamesTable() {
@ -556,6 +552,7 @@ module.exports = {
listUnassignedUsersDTAjax,
listRolesDTAjax,
assign,
rebuildPermissionsTx,
rebuildPermissions,
removeDefaultShares,
enforceEntityPermission,

View file

@ -183,7 +183,7 @@ async function create(context, user) {
id = ids[0];
}
await shares.rebuildPermissions(tx, { userId: id });
await shares.rebuildPermissionsTx(tx, { userId: id });
});
return id;
@ -231,7 +231,7 @@ async function updateWithConsistencyCheck(context, user, isOwnAccount) {
await shares.removeDefaultShares(tx, existing);
}
await shares.rebuildPermissions(tx, { userId: user.id });
await shares.rebuildPermissionsTx(tx, { userId: user.id });
});
}