work in progress on custom fields

This commit is contained in:
Tomas Bures 2017-08-11 08:51:30 +02:00
parent 361af18384
commit 86fce404a9
29 changed files with 1088 additions and 198 deletions

View file

@ -1,4 +1,4 @@
exports.up = function(knex, Promise) {
exports.up = (knex, Promise) => (async() => {
/* This is shows what it would look like when we specify the "users" table with Knex.
In some sense, this is probably the most complicated table we have in Mailtrain.
@ -36,25 +36,22 @@ exports.up = function(knex, Promise) {
// We should check here if the tables already exist and upgrade them to db_schema_version 28, which is the baseline.
// For now, we just check whether our DB is up-to-date based on the existing SQL migration infrastructure in Mailtrain.
return knex('settings').where({key: 'db_schema_version'}).first('value')
.then(row => {
if (!row || Number(row.value) !== 29) {
throw new Error('Unsupported DB schema version: ' + row.value);
}
})
const row = await knex('settings').where({key: 'db_schema_version'}).first('value');
if (!row || Number(row.value) !== 29) {
throw new Error('Unsupported DB schema version: ' + row.value);
}
// We have to update data types of primary keys and related foreign keys. Mailtrain uses unsigned int(11), while
// Knex uses unsigned int (which is unsigned int(10) ).
.then(() => knex.schema
.raw('ALTER TABLE `users` MODIFY `id` int unsigned not null auto_increment')
.raw('ALTER TABLE `lists` MODIFY `id` int unsigned not null auto_increment')
.raw('ALTER TABLE `confirmations` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `custom_fields` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `importer` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `segments` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `triggers` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `custom_forms` MODIFY `list` int unsigned not null')
)
await knex.schema
.raw('ALTER TABLE `users` MODIFY `id` int unsigned not null auto_increment')
.raw('ALTER TABLE `lists` MODIFY `id` int unsigned not null auto_increment')
.raw('ALTER TABLE `confirmations` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `custom_fields` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `importer` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `segments` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `triggers` MODIFY `list` int unsigned not null')
.raw('ALTER TABLE `custom_forms` MODIFY `list` int unsigned not null');
/*
Remaining foreign keys:
@ -68,8 +65,8 @@ exports.up = function(knex, Promise) {
custom_forms_data form custom_forms id
report_template report_template report_templates id
*/
};
})();
exports.down = function(knex, Promise) {
exports.down = (knex, Promise) => (async() => {
// return knex.schema.dropTable('users');
};
})();

View file

@ -1,33 +1,33 @@
exports.up = function(knex, Promise) {
exports.up = (knex, Promise) => (async() => {
const entityTypesAddNamespace = ['list', 'custom_form', 'report', 'report_template', 'user'];
let promise = knex.schema.createTable('namespaces', table => {
table.increments('id').primary();
table.string('name');
table.text('description');
table.integer('namespace').unsigned().references('namespaces.id').onDelete('CASCADE');
})
.then(() => knex('namespaces').insert({
id: 1, /* Global namespace id */
name: 'Root',
description: 'Root namespace'
}));
await knex.schema.createTable('namespaces', table => {
table.increments('id').primary();
table.string('name');
table.text('description');
table.integer('namespace').unsigned().references('namespaces.id').onDelete('CASCADE');
});
await knex('namespaces').insert({
id: 1, /* Global namespace id */
name: 'Root',
description: 'Root namespace'
});
for (const entityType of entityTypesAddNamespace) {
promise = promise
.then(() => knex.schema.table(`${entityType}s`, table => {
table.integer('namespace').unsigned().notNullable();
}))
.then(() => knex(`${entityType}s`).update({
namespace: 1 /* Global namespace id */
}))
.then(() => knex.schema.table(`${entityType}s`, table => {
table.foreign('namespace').references('namespaces.id').onDelete('CASCADE');
}));
await knex.schema.table(`${entityType}s`, table => {
table.integer('namespace').unsigned().notNullable();
});
await knex(`${entityType}s`).update({
namespace: 1 /* Global namespace id */
});
await knex.schema.table(`${entityType}s`, table => {
table.foreign('namespace').references('namespaces.id').onDelete('CASCADE');
});
}
})();
return promise;
};
exports.down = function(knex, Promise) {
return knex.schema.dropTable('namespaces');
};
exports.down = (knex, Promise) => (async() => {
await knex.schema.dropTable('namespaces');
})();

View file

@ -1,10 +1,9 @@
const shareableEntityTypes = ['list', 'custom_form', 'report', 'report_template', 'namespace'];
exports.up = function(knex, Promise) {
let schema = knex.schema;
exports.up = (knex, Promise) => (async() => {
for (const entityType of shareableEntityTypes) {
schema = schema
await knex.schema
.createTable(`shares_${entityType}`, table => {
table.integer('entity').unsigned().notNullable().references(`${entityType}s.id`).onDelete('CASCADE');
table.integer('user').unsigned().notNullable().references('users.id').onDelete('CASCADE');
@ -21,7 +20,7 @@ exports.up = function(knex, Promise) {
}
/* The global share for admin is set automatically in rebuildPermissions, which is called upon every start */
schema = schema
await knex.schema
.createTable('generated_role_names', table => {
table.string('entity_type', 32).notNullable();
table.string('role', 128).notNullable();
@ -30,18 +29,12 @@ exports.up = function(knex, Promise) {
table.primary(['entity_type', 'role']);
});
/* The generate_role_names table is repopulated in regenerateRoleNamesTable, which is called upon every start */
})();
return schema;
};
exports.down = function(knex, Promise) {
let schema = knex.schema;
exports.down = (knex, Promise) => (async() => {
for (const entityType of shareableEntityTypes) {
schema = schema
await knex.schema
.dropTable(`shares_${entityType}`)
.dropTable(`permissions_${entityType}`);
}
return schema;
};
})();

View file

@ -1,13 +1,14 @@
exports.up = function(knex, Promise) {
return knex.schema.table('users', table => {
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('users', table => {
// name and password can be null in case of LDAP login
table.string('name');
table.string('password').alter();
})
.then(() => knex('users').where('id', 1 /* Admin user id */).update({
name: 'Administrator'
}));
};
});
exports.down = function(knex, Promise) {
};
await knex('users').where('id', 1 /* Admin user id */).update({
name: 'Administrator'
});
})();
exports.down = (knex, Promise) => (async() => {
})();

View file

@ -1,9 +1,9 @@
exports.up = function(knex, Promise) {
return knex.schema.table('users', table => {
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('users', table => {
table.string('role');
});
/* The user role is set automatically in rebuild permissions, which is called upon every start */
};
})();
exports.down = function(knex, Promise) {
};
exports.down = (knex, Promise) => (async() => {
})();

View file

@ -1,10 +1,10 @@
exports.up = function(knex, Promise) {
return knex.schema.table('custom_forms_data', table => {
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('custom_forms_data', table => {
table.dropColumn('id');
table.string('data_key', 128).alter();
table.primary(['form', 'data_key']);
})
};
})();
exports.down = function(knex, Promise) {
};
exports.down = (knex, Promise) => (async() => {
})();

View file

@ -1,9 +1,9 @@
exports.up = function(knex, Promise) {
return knex.schema.table('custom_forms', table => {
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('custom_forms', table => {
table.dropForeign('list', 'custom_forms_ibfk_1');
table.dropColumn('list');
})
};
})();
exports.down = function(knex, Promise) {
};
exports.down = (knex, Promise) => (async() => {
})();

View file

@ -25,7 +25,7 @@ exports.up = (knex, Promise) => (async() => {
key: 'FIRST_NAME',
type: 'text',
column: 'first_name',
visible: 1 // FIXME - Revise the need for this field
visible: 1
});
const [lastNameFieldId] = await knex('custom_fields').insert({
@ -34,7 +34,7 @@ exports.up = (knex, Promise) => (async() => {
key: 'LAST_NAME',
type: 'text',
column: 'last_name',
visible: 1 // FIXME - Revise the need for this field
visible: 1
});
let orderSubscribe;
@ -66,6 +66,11 @@ exports.up = (knex, Promise) => (async() => {
}
const orderList = [firstNameFieldId, lastNameFieldId];
for (const fld of fields) {
if (fld.visible && fld.type === 'text') {
orderList.push(fld.id);
}
}
let idx = 0;
for (const fldId of orderSubscribe) {
@ -90,8 +95,12 @@ exports.up = (knex, Promise) => (async() => {
table.dropColumn('fields_shown_on_subscribe');
table.dropColumn('fields_shown_on_manage');
});
await knex.schema.table('custom_fields', table => {
table.dropColumn('visible');
});
})();
exports.down = function(knex, Promise) {
};
exports.down = (knex, Promise) => (async() => {
})();

View file

@ -0,0 +1,57 @@
"use strict";
exports.up = (knex, Promise) => (async() => {
await knex.schema.table('custom_fields', table => {
table.json('settings');
});
const fields = await knex('custom_fields');
for (const field of fields) {
const settings = {};
let type = field.type;
if (type === 'json') {
settings.groupTemplate = field.group_template;
}
if (type === 'checkbox') {
settings.groupTemplate = field.group_template;
}
if (['dropdown', 'radio'].includes(type)) {
settings.groupTemplate = field.group_template;
type = type + '-grouped';
}
if (type === 'date-eur') {
type = 'date';
settings.dateFormat = 'eur';
}
if (type === 'date-us') {
type = 'date';
settings.dateFormat = 'us';
}
if (type === 'birthday-eur') {
type = 'birthday';
settings.dateFormat = 'eur';
}
if (type === 'birthday-us') {
type = 'birthday';
settings.dateFormat = 'us';
}
await knex('custom_fields').where('id', field.id).update({type, settings: JSON.stringify(settings)});
}
await knex.schema.table('custom_fields', table => {
table.dropColumn('group_template');
});
})();
exports.down = (knex, Promise) => (async() => {
})();