392 lines
18 KiB
JavaScript
392 lines
18 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.createRelationHierarchyCheckers = exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0;
|
||
var tslib_1 = require("tslib");
|
||
var assert_1 = tslib_1.__importDefault(require("assert"));
|
||
var filter_1 = require("../store/filter");
|
||
var Exception_1 = require("../types/Exception");
|
||
var actionDef_1 = require("./actionDef");
|
||
var string_1 = require("../utils/string");
|
||
function translateCheckerInAsyncContext(checker) {
|
||
var _this = this;
|
||
var entity = checker.entity, type = checker.type;
|
||
switch (type) {
|
||
case 'data': {
|
||
var checkerFn_1 = checker.checker;
|
||
return (function (_a, context) {
|
||
var operation = _a.operation;
|
||
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||
var data;
|
||
return tslib_1.__generator(this, function (_b) {
|
||
data = operation.data;
|
||
checkerFn_1(data, context);
|
||
return [2 /*return*/, 0];
|
||
});
|
||
});
|
||
});
|
||
}
|
||
case 'row': {
|
||
var filter_2 = checker.filter, errMsg_1 = checker.errMsg, inconsistentRows_1 = checker.inconsistentRows;
|
||
return (function (_a, context, option) {
|
||
var operation = _a.operation;
|
||
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||
var operationFilter, action, filter2, entity2, selection2, rows2, data_1, rows2, data_2;
|
||
var _b, _c;
|
||
return tslib_1.__generator(this, function (_d) {
|
||
switch (_d.label) {
|
||
case 0:
|
||
operationFilter = operation.filter, action = operation.action;
|
||
filter2 = typeof filter_2 === 'function' ? filter_2(operation, context, option) : filter_2;
|
||
if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 1];
|
||
operation.filter = (0, filter_1.addFilterSegment)(operationFilter || {}, filter2);
|
||
return [2 /*return*/, 0];
|
||
case 1: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {})];
|
||
case 2:
|
||
if (_d.sent()) {
|
||
return [2 /*return*/, 0];
|
||
}
|
||
if (!inconsistentRows_1) return [3 /*break*/, 4];
|
||
entity2 = inconsistentRows_1.entity, selection2 = inconsistentRows_1.selection;
|
||
return [4 /*yield*/, context.select(entity2, selection2(operationFilter), {
|
||
dontCollect: true,
|
||
blockTrigger: true,
|
||
})];
|
||
case 3:
|
||
rows2 = _d.sent();
|
||
data_1 = {};
|
||
rows2.forEach(function (ele) {
|
||
var _a;
|
||
return Object.assign(data_1, (_a = {},
|
||
_a[ele.id] = ele,
|
||
_a));
|
||
});
|
||
throw new Exception_1.OakRowInconsistencyException({
|
||
a: 's',
|
||
d: (_b = {},
|
||
_b[entity2] = data_1,
|
||
_b)
|
||
}, errMsg_1);
|
||
case 4: return [4 /*yield*/, context.select(entity, {
|
||
data: (0, actionDef_1.getFullProjection)(entity, context.getSchema()),
|
||
filter: Object.assign({}, operationFilter, {
|
||
$not: filter2,
|
||
})
|
||
}, {
|
||
dontCollect: true,
|
||
blockTrigger: true,
|
||
})];
|
||
case 5:
|
||
rows2 = _d.sent();
|
||
data_2 = {};
|
||
rows2.forEach(function (ele) {
|
||
var _a;
|
||
return Object.assign(data_2, (_a = {},
|
||
_a[ele.id] = ele,
|
||
_a));
|
||
});
|
||
throw new Exception_1.OakRowInconsistencyException({
|
||
a: 's',
|
||
d: (_c = {},
|
||
_c[entity] = data_2,
|
||
_c)
|
||
}, errMsg_1);
|
||
}
|
||
});
|
||
});
|
||
});
|
||
}
|
||
case 'relation': {
|
||
var relationFilter_1 = checker.relationFilter;
|
||
return (function (_a, context, option) {
|
||
var operation = _a.operation;
|
||
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_b) {
|
||
if (context.isRoot()) {
|
||
return [2 /*return*/, 0];
|
||
}
|
||
// 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤)
|
||
operation.filter = (0, filter_1.combineFilters)([operation.filter, relationFilter_1(operation, context, option)]);
|
||
return [2 /*return*/, 0];
|
||
});
|
||
});
|
||
});
|
||
}
|
||
case 'expression':
|
||
case 'expressionRelation': {
|
||
var expression_1 = checker.expression, errMsg_2 = checker.errMsg;
|
||
return (function (_a, context, option) {
|
||
var operation = _a.operation;
|
||
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||
var exprResult, expressionEntity, expr, expressionFilter, _b, result;
|
||
return tslib_1.__generator(this, function (_c) {
|
||
switch (_c.label) {
|
||
case 0:
|
||
if (context.isRoot() && type === 'expressionRelation') {
|
||
return [2 /*return*/, 0];
|
||
}
|
||
exprResult = expression_1(operation, context, option);
|
||
if (!(typeof exprResult === 'string')) return [3 /*break*/, 1];
|
||
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2);
|
||
case 1:
|
||
if (!(exprResult === undefined)) return [3 /*break*/, 2];
|
||
return [2 /*return*/, 0];
|
||
case 2:
|
||
expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
|
||
return [4 /*yield*/, context.select(expressionEntity, {
|
||
data: {
|
||
$expr: expr,
|
||
},
|
||
filter: expressionFilter,
|
||
}, Object.assign({}, option, { dontCollect: true }))];
|
||
case 3:
|
||
_b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0];
|
||
if (!result) {
|
||
// 条件判定为假,抛异常
|
||
throw new Exception_1.OakUserUnpermittedException(errMsg_2);
|
||
}
|
||
_c.label = 4;
|
||
case 4: return [2 /*return*/, 0];
|
||
}
|
||
});
|
||
});
|
||
});
|
||
}
|
||
default: {
|
||
(0, assert_1.default)(false);
|
||
}
|
||
}
|
||
}
|
||
exports.translateCheckerInAsyncContext = translateCheckerInAsyncContext;
|
||
function translateCheckerInSyncContext(checker) {
|
||
var entity = checker.entity, type = checker.type;
|
||
switch (type) {
|
||
case 'data': {
|
||
var checkerFn_2 = checker.checker;
|
||
return function (operation, context) { return checkerFn_2(operation.data, context); };
|
||
}
|
||
case 'row': {
|
||
var filter_3 = checker.filter, errMsg_3 = checker.errMsg;
|
||
return function (operation, context, option) {
|
||
var operationFilter = operation.filter, action = operation.action;
|
||
var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3;
|
||
(0, assert_1.default)(operationFilter);
|
||
if (['select', 'count', 'stat'].includes(action)) {
|
||
operation.filter = (0, filter_1.addFilterSegment)(operationFilter, filter2);
|
||
return 0;
|
||
}
|
||
else {
|
||
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) {
|
||
return;
|
||
}
|
||
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3);
|
||
}
|
||
};
|
||
}
|
||
case 'relation': {
|
||
var filter_4 = checker.relationFilter, errMsg_4 = checker.errMsg;
|
||
return function (operation, context, option) {
|
||
if (context.isRoot()) {
|
||
return;
|
||
}
|
||
var filter2 = typeof filter_4 === 'function' ? filter_4(operation, context, option) : filter_4;
|
||
var operationFilter = operation.filter;
|
||
(0, assert_1.default)(operationFilter);
|
||
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) {
|
||
return;
|
||
}
|
||
throw new Exception_1.OakUserUnpermittedException(errMsg_4);
|
||
};
|
||
}
|
||
case 'expression':
|
||
case 'expressionRelation': {
|
||
var expression_2 = checker.expression, errMsg_5 = checker.errMsg;
|
||
return function (operation, context, option) {
|
||
if (context.isRoot() && type === 'expressionRelation') {
|
||
return;
|
||
}
|
||
var exprResult = expression_2(operation, context, option);
|
||
if (typeof exprResult === 'string') {
|
||
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_5);
|
||
}
|
||
else if (exprResult === undefined) {
|
||
return 0;
|
||
}
|
||
else {
|
||
var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
|
||
var _a = tslib_1.__read(context.select(expressionEntity, {
|
||
data: {
|
||
$expr: expr,
|
||
},
|
||
filter: expressionFilter,
|
||
}, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0];
|
||
if (!result.$expr) {
|
||
// 条件判定为假,抛异常
|
||
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5);
|
||
}
|
||
return;
|
||
}
|
||
};
|
||
}
|
||
default: {
|
||
(0, assert_1.default)(false);
|
||
}
|
||
}
|
||
}
|
||
exports.translateCheckerInSyncContext = translateCheckerInSyncContext;
|
||
function createRelationHierarchyCheckers(schema) {
|
||
var checkers = [];
|
||
var _loop_1 = function (entity) {
|
||
var e_1, _a;
|
||
var relationHierarchy = schema[entity].relationHierarchy;
|
||
if (relationHierarchy) {
|
||
// 先build反向hierarchy的map
|
||
var reverseHierarchy_1 = {};
|
||
for (var r in relationHierarchy) {
|
||
try {
|
||
for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) {
|
||
var r2 = _c.value;
|
||
if (!reverseHierarchy_1[r2]) {
|
||
reverseHierarchy_1[r2] = [r];
|
||
}
|
||
else {
|
||
reverseHierarchy_1[r2].push(r);
|
||
}
|
||
}
|
||
}
|
||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||
finally {
|
||
try {
|
||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
||
}
|
||
finally { if (e_1) throw e_1.error; }
|
||
}
|
||
}
|
||
// 对userEntity对象的授权和回收建立checker
|
||
var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity));
|
||
var entityIdAttr_1 = "".concat(entity, "Id");
|
||
checkers.push({
|
||
entity: userEntityName_1,
|
||
action: 'create',
|
||
type: 'expressionRelation',
|
||
expression: function (operation, context) {
|
||
var _a;
|
||
var data = operation.data;
|
||
var _b = data, relation = _b.relation, _c = entityIdAttr_1, entityId = _b[_c];
|
||
var legalRelations = reverseHierarchy_1[relation];
|
||
if (!legalRelations) {
|
||
return undefined;
|
||
}
|
||
if (legalRelations.length === 0) {
|
||
return '这是不应该跑出来的情况,请杀程序员祭天';
|
||
}
|
||
var userId = context.getCurrentUserId();
|
||
return {
|
||
entity: userEntityName_1,
|
||
expr: {
|
||
$gt: [{
|
||
'#attr': '$$createAt$$',
|
||
}, 0]
|
||
},
|
||
filter: (_a = {
|
||
userId: userId
|
||
},
|
||
_a[entityIdAttr_1] = entityId,
|
||
_a.relation = {
|
||
$in: legalRelations,
|
||
},
|
||
_a)
|
||
};
|
||
},
|
||
errMsg: '越权操作',
|
||
});
|
||
var _loop_2 = function (r) {
|
||
checkers.push({
|
||
entity: userEntityName_1,
|
||
action: 'remove',
|
||
type: 'expressionRelation',
|
||
conditionalFilter: {
|
||
relation: r,
|
||
},
|
||
expression: function (operation, context) {
|
||
var _a, _b;
|
||
var userId = context.getCurrentUserId();
|
||
var filter = operation.filter;
|
||
var legalRelations = reverseHierarchy_1[r];
|
||
if (legalRelations.length === 0) {
|
||
return '这是不应该跑出来的情况,请杀程序员祭天';
|
||
}
|
||
return {
|
||
entity: userEntityName_1,
|
||
expr: {
|
||
$gt: [{
|
||
'#attr': '$$createAt$$',
|
||
}, 0]
|
||
},
|
||
filter: (_a = {
|
||
userId: userId
|
||
},
|
||
_a[entityIdAttr_1] = {
|
||
$in: {
|
||
entity: userEntityName_1,
|
||
data: (_b = {},
|
||
_b[entityIdAttr_1] = 1,
|
||
_b),
|
||
filter: filter,
|
||
}
|
||
},
|
||
_a.relation = {
|
||
$in: legalRelations,
|
||
},
|
||
_a),
|
||
};
|
||
},
|
||
errMsg: '越权操作',
|
||
});
|
||
};
|
||
for (var r in reverseHierarchy_1) {
|
||
_loop_2(r);
|
||
}
|
||
/* // 一个人不能授权给自己,也不能删除自己的授权
|
||
checkers.push({
|
||
entity: userEntityName as keyof ED,
|
||
action: 'create' as ED[keyof ED]['Action'],
|
||
type: 'data',
|
||
checker: (data, context) => {
|
||
assert(!(data instanceof Array));
|
||
const { userId } = data as ED[keyof ED]['CreateSingle']['data'];
|
||
const userId2 = context.getCurrentUserId(true);
|
||
if (userId === userId2) {
|
||
throw new OakDataException('不允许授权给自己');
|
||
}
|
||
}
|
||
});
|
||
|
||
checkers.push({
|
||
entity: userEntityName as keyof ED,
|
||
action: 'remove' as ED[keyof ED]['Action'],
|
||
type: 'row',
|
||
filter: (operation, context) => {
|
||
const userId = context.getCurrentUserId(true);
|
||
if (userId) {
|
||
return {
|
||
userId: {
|
||
$ne: userId,
|
||
},
|
||
};
|
||
}
|
||
console.warn(`没有当前用户但在删除权限,请检查。对象是${entity}`);
|
||
return {};
|
||
},
|
||
errMsg: '不允许回收自己的授权',
|
||
}); */
|
||
// 转让权限现在用update动作,只允许update userId给其它人
|
||
// todo 等实现的时候再写
|
||
}
|
||
};
|
||
for (var entity in schema) {
|
||
_loop_1(entity);
|
||
}
|
||
return checkers;
|
||
}
|
||
exports.createRelationHierarchyCheckers = createRelationHierarchyCheckers;
|