简化了checker定义
This commit is contained in:
parent
c1eae2142f
commit
a49e37a5fe
|
|
@ -3155,13 +3155,21 @@ function outputStorage(outputDir, printer) {
|
||||||
} */
|
} */
|
||||||
if (hasRelationDef) {
|
if (hasRelationDef) {
|
||||||
var type = hasRelationDef.type;
|
var type = hasRelationDef.type;
|
||||||
(0, assert_1.default)(ts.isUnionTypeNode(type));
|
if (ts.isUnionTypeNode(type)) {
|
||||||
var types = type.types;
|
var types = type.types;
|
||||||
var relationTexts = types.map(function (ele) {
|
var relationTexts = types.map(function (ele) {
|
||||||
(0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal));
|
(0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal));
|
||||||
return ele.literal.text;
|
return ele.literal.text;
|
||||||
});
|
});
|
||||||
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relationTexts.map(function (ele) { return factory.createStringLiteral(ele); }))));
|
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relationTexts.map(function (ele) { return factory.createStringLiteral(ele); }))));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(0, assert_1.default)(ts.isLiteralTypeNode(type));
|
||||||
|
(0, assert_1.default)(ts.isStringLiteral(type.literal));
|
||||||
|
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression([
|
||||||
|
type.literal
|
||||||
|
])));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var sdTypeArguments = [
|
var sdTypeArguments = [
|
||||||
factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)
|
factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)
|
||||||
|
|
|
||||||
|
|
@ -138,49 +138,22 @@ function translateCheckerInAsyncContext(checker) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
case 'expression':
|
case 'logical':
|
||||||
case 'expressionRelation': {
|
case 'logicalRelation': {
|
||||||
var expression_1 = checker.expression, errMsg_2 = checker.errMsg;
|
var checkerFn_2 = checker.checker;
|
||||||
return (function (_a, context, option) {
|
return (function (_a, context, option) {
|
||||||
var operation = _a.operation;
|
var operation = _a.operation;
|
||||||
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
||||||
var exprResult, expressionEntity, expr, expressionFilter, _b, result, isLegal;
|
return tslib_1.__generator(this, function (_b) {
|
||||||
return tslib_1.__generator(this, function (_c) {
|
switch (_b.label) {
|
||||||
switch (_c.label) {
|
|
||||||
case 0:
|
case 0:
|
||||||
if (context.isRoot() && type === 'expressionRelation') {
|
if (context.isRoot() && type === 'logicalRelation') {
|
||||||
return [2 /*return*/, 0];
|
return [2 /*return*/, 0];
|
||||||
}
|
}
|
||||||
return [4 /*yield*/, expression_1(operation, context, option)];
|
return [4 /*yield*/, checkerFn_2(operation, context, option)];
|
||||||
case 1:
|
case 1:
|
||||||
exprResult = _c.sent();
|
_b.sent();
|
||||||
if (!(typeof exprResult === 'string')) return [3 /*break*/, 2];
|
|
||||||
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2);
|
|
||||||
case 2:
|
|
||||||
if (!(exprResult === undefined)) return [3 /*break*/, 3];
|
|
||||||
return [2 /*return*/, 0];
|
return [2 /*return*/, 0];
|
||||||
case 3:
|
|
||||||
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 4:
|
|
||||||
_b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0];
|
|
||||||
isLegal = result ? result.$expr : false;
|
|
||||||
if (!isLegal) {
|
|
||||||
// 条件判定为假,抛异常
|
|
||||||
if (type === 'expression') {
|
|
||||||
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Exception_1.OakUserUnpermittedException(errMsg_2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_c.label = 5;
|
|
||||||
case 5: return [2 /*return*/, 0];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -196,11 +169,11 @@ function translateCheckerInSyncContext(checker) {
|
||||||
var entity = checker.entity, type = checker.type;
|
var entity = checker.entity, type = checker.type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'data': {
|
case 'data': {
|
||||||
var checkerFn_2 = checker.checker;
|
var checkerFn_3 = checker.checker;
|
||||||
return function (operation, context) { return checkerFn_2(operation.data, context); };
|
return function (operation, context) { return checkerFn_3(operation.data, context); };
|
||||||
}
|
}
|
||||||
case 'row': {
|
case 'row': {
|
||||||
var filter_3 = checker.filter, errMsg_3 = checker.errMsg;
|
var filter_3 = checker.filter, errMsg_2 = checker.errMsg;
|
||||||
return function (operation, context, option) {
|
return function (operation, context, option) {
|
||||||
var operationFilter = operation.filter, action = operation.action;
|
var operationFilter = operation.filter, action = operation.action;
|
||||||
var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3;
|
var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3;
|
||||||
|
|
@ -214,12 +187,12 @@ function translateCheckerInSyncContext(checker) {
|
||||||
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
|
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3);
|
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'relation': {
|
case 'relation': {
|
||||||
var filter_4 = checker.relationFilter, errMsg_4 = checker.errMsg;
|
var filter_4 = checker.relationFilter, errMsg_3 = checker.errMsg;
|
||||||
return function (operation, context, option) {
|
return function (operation, context, option) {
|
||||||
if (context.isRoot()) {
|
if (context.isRoot()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -231,43 +204,17 @@ function translateCheckerInSyncContext(checker) {
|
||||||
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
|
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Exception_1.OakUserUnpermittedException(errMsg_4);
|
throw new Exception_1.OakUserUnpermittedException(errMsg_3);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'expression':
|
case 'logical':
|
||||||
case 'expressionRelation': {
|
case 'logicalRelation': {
|
||||||
var expression_2 = checker.expression, errMsg_5 = checker.errMsg;
|
var checkerFn_4 = checker.checker;
|
||||||
return function (operation, context, option) {
|
return function (operation, context, option) {
|
||||||
if (context.isRoot() && type === 'expressionRelation') {
|
if (context.isRoot() && type === 'logicalRelation') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var exprResult = expression_2(operation, context, option);
|
checkerFn_4(operation, context, option);
|
||||||
if (typeof exprResult === 'string') {
|
|
||||||
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_5);
|
|
||||||
}
|
|
||||||
else if (exprResult === undefined) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
(0, assert_1.default)(!(exprResult instanceof Promise));
|
|
||||||
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];
|
|
||||||
var isLegal = result ? result.$expr : false;
|
|
||||||
if (!isLegal) {
|
|
||||||
// 条件判定为假,抛异常
|
|
||||||
if (type === 'expression') {
|
|
||||||
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Exception_1.OakUserUnpermittedException(errMsg_5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
@ -428,8 +375,8 @@ function createAuthCheckers(schema, authDict) {
|
||||||
checkers.push({
|
checkers.push({
|
||||||
entity: userEntityName_1,
|
entity: userEntityName_1,
|
||||||
action: 'create',
|
action: 'create',
|
||||||
type: 'expressionRelation',
|
type: 'relation',
|
||||||
expression: function (operation, context) {
|
relationFilter: function (operation, context) {
|
||||||
var data = operation.data;
|
var data = operation.data;
|
||||||
(0, assert_1.default)(!(data instanceof Array));
|
(0, assert_1.default)(!(data instanceof Array));
|
||||||
var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b];
|
var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b];
|
||||||
|
|
@ -438,15 +385,7 @@ function createAuthCheckers(schema, authDict) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var filter = raFilterMakerDict_1[relation](userId);
|
var filter = raFilterMakerDict_1[relation](userId);
|
||||||
return {
|
return filter;
|
||||||
entity: entity,
|
|
||||||
filter: (0, filter_1.combineFilters)([filter, { id: entityId }]),
|
|
||||||
expr: {
|
|
||||||
$gt: [{
|
|
||||||
'#attr': '$$createAt$$',
|
|
||||||
}, 0]
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
errMsg: '越权操作',
|
errMsg: '越权操作',
|
||||||
});
|
});
|
||||||
|
|
@ -500,34 +439,34 @@ function createAuthCheckers(schema, authDict) {
|
||||||
* create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后
|
* create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后
|
||||||
*/
|
*/
|
||||||
var _c = actionAuth[a];
|
var _c = actionAuth[a];
|
||||||
checkers.push({
|
/* checkers.push({
|
||||||
entity: entity,
|
entity,
|
||||||
action: a,
|
action: a,
|
||||||
type: 'expressionRelation',
|
type: 'expressionRelation',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
expression: function (operation, context) {
|
expression: (operation, context) => {
|
||||||
// 在插入后检查
|
// 在插入后检查
|
||||||
var makeExprInner = function (data) {
|
const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => {
|
||||||
var id = data.id;
|
const { id } = data;
|
||||||
return {
|
return {
|
||||||
entity: entity,
|
entity,
|
||||||
filter: (0, filter_1.combineFilters)([filter, { id: id }]),
|
filter: combineFilters([filter, { id }]),
|
||||||
expr: {
|
expr: {
|
||||||
$gt: [{
|
$gt: [{
|
||||||
'#attr': '$$createAt$$',
|
'#attr': '$$createAt$$',
|
||||||
}, 0]
|
}, 0] as any
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
var filter = filterMaker(context.getCurrentUserId());
|
const filter = filterMaker(context.getCurrentUserId()!);
|
||||||
var data = operation.data;
|
const { data } = operation as ED[keyof ED]['Create'];
|
||||||
if (data instanceof Array) {
|
if (data instanceof Array) {
|
||||||
throw new Error('需要expr支持count');
|
throw new Error('需要expr支持count');
|
||||||
}
|
}
|
||||||
return makeExprInner(data);
|
return makeExprInner(data);
|
||||||
},
|
},
|
||||||
errMsg: '定义的actionAuth中检查出来越权操作',
|
errMsg: '定义的actionAuth中检查出来越权操作',
|
||||||
});
|
}); */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkers.push({
|
checkers.push({
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ export declare type RelationChecker<ED extends EntityDict, T extends keyof ED, C
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'relation';
|
type: 'relation';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: Omit<ED[T]['Action'], 'create'> | Array<Omit<ED[T]['Action'], 'create'>>;
|
when?: 'after';
|
||||||
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>;
|
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>;
|
||||||
errMsg: string;
|
errMsg: string;
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Selection']['filter']>);
|
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Selection']['filter']>);
|
||||||
|
|
@ -44,27 +45,25 @@ export declare type ExpressionTask<ED extends EntityDict, T extends keyof ED> =
|
||||||
filter: ED[T]['Selection']['filter'];
|
filter: ED[T]['Selection']['filter'];
|
||||||
};
|
};
|
||||||
export declare type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
|
export declare type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
|
||||||
export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
export declare type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'expression';
|
type: 'logical';
|
||||||
when?: 'after';
|
when?: 'after';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;
|
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
|
||||||
errMsg: string;
|
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
||||||
};
|
};
|
||||||
export declare type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
export declare type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'expressionRelation';
|
type: 'logicalRelation';
|
||||||
when?: 'after';
|
when?: 'after';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;
|
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
|
||||||
errMsg: string;
|
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
||||||
};
|
};
|
||||||
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | ExpressionChecker<ED, T, Cxt> | ExpressionRelationChecker<ED, T, Cxt>;
|
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
|
||||||
export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
|
export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
|
||||||
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
|
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
|
||||||
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
|
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
|
||||||
|
|
|
||||||
|
|
@ -5899,23 +5899,39 @@ function outputStorage(outputDir: string, printer: ts.Printer) {
|
||||||
} */
|
} */
|
||||||
if (hasRelationDef) {
|
if (hasRelationDef) {
|
||||||
const { type } = hasRelationDef;
|
const { type } = hasRelationDef;
|
||||||
assert(ts.isUnionTypeNode(type));
|
if (ts.isUnionTypeNode(type)) {
|
||||||
const { types } = type;
|
const { types } = type;
|
||||||
const relationTexts = types.map(
|
const relationTexts = types.map(
|
||||||
ele => {
|
ele => {
|
||||||
assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal));
|
assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal));
|
||||||
return ele.literal.text;
|
return ele.literal.text;
|
||||||
}
|
}
|
||||||
)
|
|
||||||
propertyAssignments.push(
|
|
||||||
factory.createPropertyAssignment(
|
|
||||||
factory.createIdentifier("relation"),
|
|
||||||
factory.createArrayLiteralExpression(relationTexts.map(
|
|
||||||
ele => factory.createStringLiteral(ele)
|
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
);
|
propertyAssignments.push(
|
||||||
}
|
factory.createPropertyAssignment(
|
||||||
|
factory.createIdentifier("relation"),
|
||||||
|
factory.createArrayLiteralExpression(relationTexts.map(
|
||||||
|
ele => factory.createStringLiteral(ele)
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(ts.isLiteralTypeNode(type));
|
||||||
|
assert(ts.isStringLiteral(type.literal));
|
||||||
|
|
||||||
|
propertyAssignments.push(
|
||||||
|
factory.createPropertyAssignment(
|
||||||
|
factory.createIdentifier("relation"),
|
||||||
|
factory.createArrayLiteralExpression(
|
||||||
|
[
|
||||||
|
type.literal
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
const sdTypeArguments = [
|
const sdTypeArguments = [
|
||||||
factory.createTypeReferenceNode(
|
factory.createTypeReferenceNode(
|
||||||
factory.createIdentifier("OpSchema"),
|
factory.createIdentifier("OpSchema"),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { addFilterSegment, checkFilterRepel } from "../store/filter";
|
||||||
import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity";
|
import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity";
|
||||||
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
||||||
import { Logger } from "../types/Logger";
|
import { Logger } from "../types/Logger";
|
||||||
import { Checker, CheckerType, ExpressionChecker, RelationChecker } from '../types/Auth';
|
import { Checker, CheckerType, LogicalChecker, RelationChecker } from '../types/Auth';
|
||||||
import { Trigger, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn, SelectTriggerAfter, UpdateTrigger } from "../types/Trigger";
|
import { Trigger, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn, SelectTriggerAfter, UpdateTrigger } from "../types/Trigger";
|
||||||
import { AsyncContext } from './AsyncRowStore';
|
import { AsyncContext } from './AsyncRowStore';
|
||||||
import { SyncContext } from './SyncRowStore';
|
import { SyncContext } from './SyncRowStore';
|
||||||
|
|
@ -57,7 +57,7 @@ export class TriggerExecutor<ED extends EntityDict & BaseEntityDict> {
|
||||||
entity,
|
entity,
|
||||||
action: action as 'update',
|
action: action as 'update',
|
||||||
fn,
|
fn,
|
||||||
when: (checker as ExpressionChecker<ED, T, Cxt>).when || 'before',
|
when: (checker as LogicalChecker<ED, T, Cxt>).when || 'before',
|
||||||
filter: conditionalFilter,
|
filter: conditionalFilter,
|
||||||
} as UpdateTrigger<ED, T, Cxt>;
|
} as UpdateTrigger<ED, T, Cxt>;
|
||||||
this.registerTrigger(trigger);
|
this.registerTrigger(trigger);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter";
|
import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter";
|
||||||
import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception';
|
import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception';
|
||||||
import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types";
|
import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, LogicalRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types";
|
||||||
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
||||||
import { AsyncContext } from "./AsyncRowStore";
|
import { AsyncContext } from "./AsyncRowStore";
|
||||||
import { getFullProjection } from './actionDef';
|
import { getFullProjection } from './actionDef';
|
||||||
|
|
@ -96,39 +96,14 @@ export function translateCheckerInAsyncContext<
|
||||||
return 0;
|
return 0;
|
||||||
}) as UpdateTriggerInTxn<ED, keyof ED, Cxt>['fn'];
|
}) as UpdateTriggerInTxn<ED, keyof ED, Cxt>['fn'];
|
||||||
}
|
}
|
||||||
case 'expression':
|
case 'logical':
|
||||||
case 'expressionRelation': {
|
case 'logicalRelation': {
|
||||||
const { expression, errMsg } = checker;
|
const { checker: checkerFn } = checker;
|
||||||
return (async ({ operation }, context, option) => {
|
return (async ({ operation }, context, option) => {
|
||||||
if (context.isRoot() && type === 'expressionRelation') {
|
if (context.isRoot() && type === 'logicalRelation') {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const exprResult = await expression(operation, context, option);
|
await checkerFn(operation, context, option);
|
||||||
if (typeof exprResult === 'string') {
|
|
||||||
throw new OakUserUnpermittedException(exprResult || errMsg);
|
|
||||||
}
|
|
||||||
else if (exprResult === undefined) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult;
|
|
||||||
const [result] = await context.select(expressionEntity, {
|
|
||||||
data: {
|
|
||||||
$expr: expr,
|
|
||||||
},
|
|
||||||
filter: expressionFilter,
|
|
||||||
}, Object.assign({}, option, { dontCollect: true }));
|
|
||||||
const isLegal = result ? result.$expr as boolean : false;
|
|
||||||
if (!isLegal) {
|
|
||||||
// 条件判定为假,抛异常
|
|
||||||
if (type === 'expression') {
|
|
||||||
throw new OakRowInconsistencyException(undefined, errMsg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new OakUserUnpermittedException(errMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}) as UpdateTriggerInTxn<ED, keyof ED, Cxt>['fn'];
|
}) as UpdateTriggerInTxn<ED, keyof ED, Cxt>['fn'];
|
||||||
}
|
}
|
||||||
|
|
@ -184,40 +159,14 @@ export function translateCheckerInSyncContext<
|
||||||
throw new OakUserUnpermittedException(errMsg);
|
throw new OakUserUnpermittedException(errMsg);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 'expression':
|
case 'logical':
|
||||||
case 'expressionRelation': {
|
case 'logicalRelation': {
|
||||||
const { expression, errMsg } = checker;
|
const { checker: checkerFn } = checker;
|
||||||
return (operation, context, option) => {
|
return (operation, context, option) => {
|
||||||
if (context.isRoot() && type === 'expressionRelation') {
|
if (context.isRoot() && type === 'logicalRelation') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const exprResult = expression(operation, context, option);
|
checkerFn(operation, context, option);
|
||||||
if (typeof exprResult === 'string') {
|
|
||||||
throw new OakUserUnpermittedException(exprResult || errMsg);
|
|
||||||
}
|
|
||||||
else if (exprResult === undefined) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(!(exprResult instanceof Promise));
|
|
||||||
const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult;
|
|
||||||
const [result] = context.select(expressionEntity, {
|
|
||||||
data: {
|
|
||||||
$expr: expr,
|
|
||||||
},
|
|
||||||
filter: expressionFilter,
|
|
||||||
}, Object.assign({}, option, { dontCollect: true }));
|
|
||||||
const isLegal = result ? result.$expr as boolean : false;
|
|
||||||
if (!isLegal) {
|
|
||||||
// 条件判定为假,抛异常
|
|
||||||
if (type === 'expression') {
|
|
||||||
throw new OakRowInconsistencyException(undefined, errMsg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new OakUserUnpermittedException(errMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
@ -386,8 +335,8 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
|
||||||
checkers.push({
|
checkers.push({
|
||||||
entity: userEntityName as keyof ED,
|
entity: userEntityName as keyof ED,
|
||||||
action: 'create',
|
action: 'create',
|
||||||
type: 'expressionRelation',
|
type: 'relation',
|
||||||
expression: (operation, context) => {
|
relationFilter: (operation, context) => {
|
||||||
const { data } = operation as ED[keyof ED]['Create'];
|
const { data } = operation as ED[keyof ED]['Create'];
|
||||||
assert(!(data instanceof Array));
|
assert(!(data instanceof Array));
|
||||||
const { relation, [entityIdAttr]: entityId } = data;
|
const { relation, [entityIdAttr]: entityId } = data;
|
||||||
|
|
@ -396,15 +345,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const filter = raFilterMakerDict[relation]!(userId!);
|
const filter = raFilterMakerDict[relation]!(userId!);
|
||||||
return {
|
return filter;
|
||||||
entity,
|
|
||||||
filter: combineFilters([filter, { id: entityId }]),
|
|
||||||
expr: {
|
|
||||||
$gt: [{
|
|
||||||
'#attr': '$$createAt$$',
|
|
||||||
}, 0]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
errMsg: '越权操作',
|
errMsg: '越权操作',
|
||||||
});
|
});
|
||||||
|
|
@ -465,7 +406,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
|
||||||
* create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后
|
* create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后
|
||||||
*/
|
*/
|
||||||
const { } = actionAuth[a as ED[keyof ED]['Action']]!;
|
const { } = actionAuth[a as ED[keyof ED]['Action']]!;
|
||||||
checkers.push({
|
/* checkers.push({
|
||||||
entity,
|
entity,
|
||||||
action: a,
|
action: a,
|
||||||
type: 'expressionRelation',
|
type: 'expressionRelation',
|
||||||
|
|
@ -492,7 +433,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
|
||||||
return makeExprInner(data);
|
return makeExprInner(data);
|
||||||
},
|
},
|
||||||
errMsg: '定义的actionAuth中检查出来越权操作',
|
errMsg: '定义的actionAuth中检查出来越权操作',
|
||||||
});
|
}); */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
checkers.push({
|
checkers.push({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
||||||
import { OpSchema as Modi, Filter } from '../base-app-domain/Modi/Schema';
|
import { OpSchema as Modi, Filter } from '../base-app-domain/Modi/Schema';
|
||||||
import { Checker, Operation, StorageSchema, RowChecker, EntityDict, OakRowLockedException, Context, OperateOption, Trigger, RemoveTrigger, RelationChecker, ExpressionChecker, ExpressionRelationChecker, OakUserUnpermittedException } from '../types';
|
import { Checker, Operation, StorageSchema, RowChecker, EntityDict, OakRowLockedException, Context, OperateOption, Trigger, RemoveTrigger, RelationChecker, LogicalChecker, LogicalRelationChecker, OakUserUnpermittedException } from '../types';
|
||||||
import { appendOnlyActions } from '../actions/action';
|
import { appendOnlyActions } from '../actions/action';
|
||||||
import { difference } from '../utils/lodash';
|
import { difference } from '../utils/lodash';
|
||||||
import { AsyncContext } from './AsyncRowStore';
|
import { AsyncContext } from './AsyncRowStore';
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ export type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt exten
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'relation';
|
type: 'relation';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: Omit<ED[T]['Action'], 'create'> | Array<Omit<ED[T]['Action'], 'create'>>;
|
when?: 'after';
|
||||||
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>; // 生成一个额外的relation相关的filter,加在原先的filter上
|
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>; // 生成一个额外的relation相关的filter,加在原先的filter上
|
||||||
errMsg: string;
|
errMsg: string;
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | (
|
conditionalFilter?: ED[T]['Update']['filter'] | (
|
||||||
|
|
@ -59,39 +60,37 @@ export type ExpressionTask<ED extends EntityDict, T extends keyof ED> = {
|
||||||
|
|
||||||
export type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
|
export type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
|
||||||
|
|
||||||
export type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
export type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'expression';
|
type: 'logical';
|
||||||
when?: 'after';
|
when?: 'after';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
expression: <T2 extends keyof ED>(
|
checker: (
|
||||||
operation: ED[T]['Operation'] | ED[T]['Selection'],
|
operation: ED[T]['Operation'] | ED[T]['Selection'],
|
||||||
context: Cxt,
|
context: Cxt,
|
||||||
option: OperateOption | SelectOption
|
option: OperateOption | SelectOption
|
||||||
) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂
|
) => void | Promise<void>;
|
||||||
errMsg: string;
|
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
export type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
||||||
priority?: number;
|
priority?: number;
|
||||||
type: 'expressionRelation';
|
type: 'logicalRelation';
|
||||||
when?: 'after';
|
when?: 'after';
|
||||||
entity: T;
|
entity: T;
|
||||||
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
action: ED[T]['Action'] | Array<ED[T]['Action']>;
|
||||||
expression: <T2 extends keyof ED>(
|
checker: (
|
||||||
operation: ED[T]['Operation'] | ED[T]['Selection'],
|
operation: ED[T]['Operation'] | ED[T]['Selection'],
|
||||||
context: Cxt,
|
context: Cxt,
|
||||||
option: OperateOption | SelectOption
|
option: OperateOption | SelectOption
|
||||||
) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂
|
) => void | Promise<void>;
|
||||||
errMsg: string;
|
|
||||||
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> =
|
export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> =
|
||||||
DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | ExpressionChecker<ED, T, Cxt> | ExpressionRelationChecker<ED, T, Cxt>;
|
DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
|
||||||
|
|
||||||
|
|
||||||
export type AuthDef<ED extends EntityDict, T extends keyof ED> = {
|
export type AuthDef<ED extends EntityDict, T extends keyof ED> = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue