WiP on permissions

Doesn't run. This commit is just to backup the changes.
This commit is contained in:
Tomas Bures 2017-07-26 22:42:05 +03:00
parent 5df444f641
commit 89c9615592
37 changed files with 913 additions and 366 deletions

View file

@ -1,36 +1,64 @@
'use strict';
const knex = require('../lib/knex');
const permissions = require('../lib/permissions');
async function ajaxList(params, queryFun, columns) {
async function ajaxList(params, queryFun, columns, mapFun) {
return await knex.transaction(async (tx) => {
const query = queryFun(tx);
const columnsNames = [];
const columnsSelect = [];
for (const col of columns) {
if (typeof col === 'string') {
columnsNames.push(col);
columnsSelect.push(col);
} else {
columnsNames.push(col.name);
if (col.raw) {
columnsSelect.push(tx.raw(col.raw));
} else if (col.query) {
columnsSelect.push(function () { return col.query(this); });
}
}
}
if (params.operation === 'getBy') {
query.whereIn(columns[parseInt(params.column)], params.values);
query.select(columns);
const query = queryFun(tx);
query.whereIn(columnsNames[parseInt(params.column)], params.values);
query.select(columnsSelect);
const rows = await query;
const rowsOfArray = rows.map(row => Object.keys(row).map(key => row[key]));
return rowsOfArray;
} else {
const recordsTotalQuery = query.clone().count('* as recordsTotal').first();
const recordsTotal = (await recordsTotalQuery).recordsTotal;
query.where(function() {
const whereFun = function() {
let searchVal = '%' + params.search.value.replace(/\\/g, '\\\\').replace(/([%_])/g, '\\$1') + '%';
for (let colIdx = 0; colIdx < params.columns.length; colIdx++) {
const col = params.columns[colIdx];
if (col.searchable) {
this.orWhere(columns[parseInt(col.data)], 'like', searchVal);
this.orWhere(columnsNames[parseInt(col.data)], 'like', searchVal);
}
}
});
}
const recordsFilteredQuery = query.clone().count('* as recordsFiltered').first();
/* There are a few SQL peculiarities that make this query a bit weird:
- Group by (which is used in getting permissions) don't go well with count(*). Thus we run the actual query
as a sub-query and then count the number of results.
- SQL does not like if it have columns with the same name in the subquery. This happens multiple tables are joined.
To circumvent this, we select only the first column (whatever it is). Since this is not "distinct", it is supposed
to give us the right number of rows anyway.
*/
const recordsTotalQuery = tx.count('* as recordsTotal').from(function () { return queryFun(this).select(columnsSelect[0]).as('records'); }).first();
const recordsTotal = (await recordsTotalQuery).recordsTotal;
const recordsFilteredQuery = tx.count('* as recordsFiltered').from(function () { return queryFun(this).select(columnsSelect[0]).where(whereFun).as('records'); }).first();
const recordsFiltered = (await recordsFilteredQuery).recordsFiltered;
const query = queryFun(tx);
query.where(whereFun);
query.offset(parseInt(params.start));
const limit = parseInt(params.length);
@ -38,16 +66,25 @@ async function ajaxList(params, queryFun, columns) {
query.limit(limit);
}
query.select(columns);
query.select(columnsSelect);
for (const order of params.order) {
query.orderBy(columns[params.columns[order.column].data], order.dir);
query.orderBy(columnsNames[params.columns[order.column].data], order.dir);
}
query.options({rowsAsArray:true});
const rows = await query;
const rowsOfArray = rows.map(row => Object.keys(row).map(field => row[field]));
const rowsOfArray = rows.map(row => {
const arr = Object.keys(row).map(field => row[field]);
if (mapFun) {
const result = mapFun(arr);
return result || arr;
} else {
return arr;
}
});
const result = {
draw: params.draw,
@ -61,6 +98,51 @@ async function ajaxList(params, queryFun, columns) {
});
}
async function ajaxListWithPermissions(context, fetchSpecs, params, queryFun, columns) {
const permCols = [];
for (const fetchSpec of fetchSpecs) {
const entityType = permissions.getEntityType(fetchSpec.entityTypeId);
permCols.push({
name: `permissions_${fetchSpec.entityTypeId}`,
query: builder => builder
.from(entityType.permissionsTable)
.select(knex.raw('GROUP_CONCAT(operation SEPARATOR \';\')'))
.whereRaw(`${entityType.permissionsTable}.entity = ${entityType.entitiesTable}.id`)
.where(`${entityType.permissionsTable}.user`, context.user.id)
.as(`permissions_${fetchSpec.entityTypeId}`)
});
}
return await ajaxList(
params,
builder => {
let query = queryFun(builder);
for (const fetchSpec of fetchSpecs) {
const entityType = permissions.getEntityType(fetchSpec.entityTypeId);
query = query.innerJoin(
function () {
return this.from(entityType.permissionsTable).select('entity').where('user', context.user.id).whereIn('operation', fetchSpec.requiredOperations).as(`permitted__${fetchSpec.entityTypeId}`);
},
`permitted__${fetchSpec.entityTypeId}.entity`, `${entityType.entitiesTable}.id`)
}
return query;
},
[
...columns,
...permCols
],
data => {
for (let idx = 0; idx < fetchSpecs.length; idx++) {
data[columns.length + idx] = data[columns.length + idx].split(';');
}
}
);
}
module.exports = {
ajaxList
ajaxList,
ajaxListWithPermissions
};