支持自主查找并建立deduceFilter模式
This commit is contained in:
parent
e3b215bbf2
commit
9df1b0bd98
|
|
@ -1364,8 +1364,9 @@ var RelationAuth = /** @class */ (function () {
|
|||
}
|
||||
}
|
||||
};
|
||||
RelationAuth.prototype.getDeducedEntityFilters = function (entity, filter, actions) {
|
||||
RelationAuth.prototype.getDeducedEntityFilters = function (entity, filter, actions, context) {
|
||||
var e_4, _a;
|
||||
var _this = this;
|
||||
var entityFilters = [
|
||||
{
|
||||
entity: entity,
|
||||
|
|
@ -1402,11 +1403,53 @@ var RelationAuth = /** @class */ (function () {
|
|||
finally { if (e_4) throw e_4.error; }
|
||||
}
|
||||
}
|
||||
if (deduceEntity && deduceFilter) {
|
||||
var excludeActions_3 = action_1.readOnlyActions.concat(['create', 'remove']);
|
||||
var updateActions = this.schema[deduceEntity].actions.filter(function (a) { return !excludeActions_3.includes(a); });
|
||||
var deducedSelections = this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions);
|
||||
var addDeduceEntityFilter_1 = function (deduceEntity, deduceFilter) {
|
||||
var excludeActions = action_1.readOnlyActions.concat(['create', 'remove']);
|
||||
var updateActions = _this.schema[deduceEntity].actions.filter(function (a) { return !excludeActions.includes(a); });
|
||||
var deducedSelections = _this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
|
||||
if (deducedSelections instanceof Promise) {
|
||||
return deducedSelections.then(function (ds) {
|
||||
entityFilters.push.apply(entityFilters, tslib_1.__spreadArray([], tslib_1.__read(ds), false));
|
||||
return entityFilters;
|
||||
});
|
||||
}
|
||||
entityFilters.push.apply(entityFilters, tslib_1.__spreadArray([], tslib_1.__read(deducedSelections), false));
|
||||
return entityFilters;
|
||||
};
|
||||
if (deduceEntity && deduceFilter) {
|
||||
return addDeduceEntityFilter_1(deduceEntity, deduceFilter);
|
||||
}
|
||||
else {
|
||||
// 这种情况说明从filter中无法确定相应的deduceFilter,需要查找
|
||||
var rows2 = context.select(entity, {
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: filter,
|
||||
}, { dontCollect: true });
|
||||
var dealWithData_1 = function (rows) {
|
||||
(0, assert_1.default)(rows.length > 0, "\u67E5\u8BE2\u65E0\u6CD5\u754C\u5B9A\u51FA\u76F8\u5E94\u7684deduce\u5BF9\u8C61".concat(entity, "\uFF0C\u67E5\u8BE2\u6761\u4EF6\u4E3A").concat(JSON.stringify(filter)));
|
||||
var entity2 = rows[0].entity;
|
||||
var entityIds2 = [];
|
||||
rows.forEach(function (row) {
|
||||
(0, assert_1.default)(row.entity === entity2, "\u5355\u4E2A\u67E5\u8BE2\u6240\u63A8\u5BFC\u51FA\u7684\u5BF9\u8C61\u4E0D\u552F\u4E00\uFF0C\u76F8\u5E94\u7684deduce\u5BF9\u8C61".concat(entity, "\uFF0C\u67E5\u8BE2\u6761\u4EF6\u4E3A").concat(JSON.stringify(filter)));
|
||||
(0, assert_1.default)(typeof row.entityId === 'string');
|
||||
entityIds2.push(row.entityId);
|
||||
});
|
||||
var deduceFilter2 = {
|
||||
entity: entity2,
|
||||
id: entityIds2.length === 1 ? entityIds2[0] : {
|
||||
$in: entityIds2,
|
||||
},
|
||||
};
|
||||
return addDeduceEntityFilter_1(entity2, deduceFilter2);
|
||||
};
|
||||
if (rows2 instanceof Promise) {
|
||||
return rows2.then(function (r2) { return dealWithData_1(r2); });
|
||||
}
|
||||
return dealWithData_1(rows2);
|
||||
}
|
||||
}
|
||||
return entityFilters;
|
||||
|
|
@ -1651,85 +1694,93 @@ var RelationAuth = /** @class */ (function () {
|
|||
var leafSelections = this.destructSelection(entity, selection);
|
||||
var deducedLeafSelections = leafSelections.map(function (_a) {
|
||||
var entity = _a.entity, filter = _a.filter;
|
||||
return _this.getDeducedEntityFilters(entity, filter, ['select']);
|
||||
}).filter(function (ele) {
|
||||
var entities = ele.map(function (ele) { return ele.entity; });
|
||||
// 同一个leaf的deducedSelections中只要有一个能通过就足够了
|
||||
if ((0, lodash_1.intersection)(_this.selectFreeEntities, entities).length > 0) {
|
||||
return false;
|
||||
}
|
||||
if ((0, lodash_1.intersection)(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return _this.getDeducedEntityFilters(entity, filter, ['select'], context);
|
||||
});
|
||||
if (deducedLeafSelections.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!context.getCurrentUserId()) {
|
||||
throw new types_1.OakUnloggedInException();
|
||||
}
|
||||
var allEntities = [];
|
||||
deducedLeafSelections.forEach(function (ele) { return ele.forEach(function (_a) {
|
||||
var entity = _a.entity;
|
||||
allEntities.push(entity);
|
||||
}); });
|
||||
var actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
var checkDeducedLeafSelections = function (dlSelections2) {
|
||||
var dlSelections = dlSelections2.filter(function (ele) {
|
||||
var entities = ele.map(function (ele2) { return ele2.entity; });
|
||||
// 同一个leaf的deducedSelections中只要有一个能通过就足够了
|
||||
if ((0, lodash_1.intersection)(_this.selectFreeEntities, entities).length > 0) {
|
||||
return false;
|
||||
}
|
||||
if ((0, lodash_1.intersection)(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (dlSelections.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!context.getCurrentUserId()) {
|
||||
throw new types_1.OakUnloggedInException();
|
||||
}
|
||||
var allEntities = [];
|
||||
dlSelections.forEach(function (ele) { return ele.forEach(function (_a) {
|
||||
var entity = _a.entity;
|
||||
allEntities.push(entity);
|
||||
}); });
|
||||
var actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
deActions: {
|
||||
$contains: 'select',
|
||||
},
|
||||
destEntity: {
|
||||
$in: allEntities,
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
/**
|
||||
* 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以,第三层为所有可能的actionAuth,通过一个就可以
|
||||
* @param result
|
||||
* @returns
|
||||
*/
|
||||
var checkResult = function (result) {
|
||||
var r = !result.find(function (ele) {
|
||||
var eleFlated = ele.flat();
|
||||
return !eleFlated.find(function (ele2) { return !!ele2; });
|
||||
});
|
||||
if (!r && process.env.NODE_ENV === 'development') {
|
||||
deducedLeafSelections.forEach(function (ele, idx) {
|
||||
var r2 = result[idx].flat();
|
||||
if (!r2.find(function (ele2) { return !!ele; })) {
|
||||
console.warn('对象的select权限被否决,请检查', ele);
|
||||
filter: {
|
||||
deActions: {
|
||||
$contains: 'select',
|
||||
},
|
||||
destEntity: {
|
||||
$in: allEntities,
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
/**
|
||||
* 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以,第三层为所有可能的actionAuth,通过一个就可以
|
||||
* @param result
|
||||
* @returns
|
||||
*/
|
||||
var checkResult = function (result) {
|
||||
var r = !result.find(function (ele) {
|
||||
var eleFlated = ele.flat();
|
||||
return !eleFlated.find(function (ele2) { return !!ele2; });
|
||||
});
|
||||
if (!r && process.env.NODE_ENV === 'development') {
|
||||
dlSelections.forEach(function (ele, idx) {
|
||||
var r2 = result[idx].flat();
|
||||
if (!r2.find(function (ele2) { return !!ele; })) {
|
||||
console.warn('对象的select权限被否决,请检查', ele);
|
||||
}
|
||||
});
|
||||
}
|
||||
return r;
|
||||
};
|
||||
if (actionAuths instanceof Promise) {
|
||||
(0, assert_1.default)(context instanceof AsyncRowStore_1.AsyncContext);
|
||||
return actionAuths.then(function (aas) { return Promise.all(dlSelections.map(function (ele) { return Promise.all(ele.map(function (ele2) { return Promise.all(_this.checkSingleOperation(ele2.entity, ele2.filter, aas, context, ['select'])); })); })).then(function (result) { return checkResult(result); }); });
|
||||
}
|
||||
return r;
|
||||
return checkResult(dlSelections.map(function (ele) { return ele.map(function (ele2) { return _this.checkSingleOperation(ele2.entity, ele2.filter, actionAuths, context, ['select']); }); }));
|
||||
};
|
||||
if (actionAuths instanceof Promise) {
|
||||
(0, assert_1.default)(context instanceof AsyncRowStore_1.AsyncContext);
|
||||
return actionAuths.then(function (aas) { return Promise.all(deducedLeafSelections.map(function (ele) { return Promise.all(ele.map(function (ele2) { return Promise.all(_this.checkSingleOperation(ele2.entity, ele2.filter, aas, context, ['select'])); })); })).then(function (result) { return checkResult(result); }); });
|
||||
if (deducedLeafSelections[0] instanceof Promise) {
|
||||
return Promise.all(deducedLeafSelections)
|
||||
.then(function (dls) { return checkDeducedLeafSelections(dls); });
|
||||
}
|
||||
return checkResult(deducedLeafSelections.map(function (ele) { return ele.map(function (ele2) { return _this.checkSingleOperation(ele2.entity, ele2.filter, actionAuths, context, ['select']); }); }));
|
||||
return checkDeducedLeafSelections(deducedLeafSelections);
|
||||
};
|
||||
RelationAuth.prototype.findActionAuthsOnNode = function (node, context) {
|
||||
var _this = this;
|
||||
|
|
@ -1738,70 +1789,76 @@ var RelationAuth = /** @class */ (function () {
|
|||
// 特殊对象不用查询
|
||||
return [];
|
||||
}
|
||||
var deducedEntityFilters = this.getDeducedEntityFilters(entity, filter, [action]);
|
||||
var allEntities = deducedEntityFilters.map(function (ele) { return ele.entity; });
|
||||
// todo 这里其实可以在查询条件里通过userRelation过滤一次,但问题不大
|
||||
var actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
var deducedEntityFilters2 = this.getDeducedEntityFilters(entity, filter, [action], context);
|
||||
var dealWithDeducedEntityFilters = function (deducedEntityFilters) {
|
||||
var allEntities = deducedEntityFilters.map(function (ele) { return ele.entity; });
|
||||
// todo 这里其实可以在查询条件里通过userRelation过滤一次,但问题不大
|
||||
var actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
destEntity: {
|
||||
$in: allEntities,
|
||||
filter: {
|
||||
destEntity: {
|
||||
$in: allEntities,
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
var getActionAuths = function (result) {
|
||||
var aas = [];
|
||||
result.forEach(function (ele) { return ele.forEach(function (ele2) {
|
||||
if (!!ele2) {
|
||||
aas.push(ele2);
|
||||
}
|
||||
}); });
|
||||
return aas;
|
||||
};
|
||||
var findOwnCreateUserRelation = function (actionAuths) {
|
||||
if (userRelations) {
|
||||
var ars = actionAuths.filter(function (ar) { return !!userRelations.find(function (ur) { return ur.relationId === ar.relationId; }); });
|
||||
if (ars.length > 0) {
|
||||
// 这里能找到actionAuth,其必然是本对象上的授权
|
||||
(0, assert_1.default)(!ars.find(function (ele) { return ele.path !== '' || ele.destEntity !== entity; }));
|
||||
return ars;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (actionAuths instanceof Promise) {
|
||||
return actionAuths.then(function (ars) {
|
||||
var created = findOwnCreateUserRelation(ars);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return Promise.all(deducedEntityFilters.map(function (ele) { return Promise.all(_this.checkSingleOperation(ele.entity, ele.filter, ars, context, ele.actions)); })).then(function (result) { return getActionAuths(result); });
|
||||
});
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
var getActionAuths = function (result) {
|
||||
var aas = [];
|
||||
result.forEach(function (ele) { return ele.forEach(function (ele2) {
|
||||
if (!!ele2) {
|
||||
aas.push(ele2);
|
||||
}
|
||||
}); });
|
||||
return aas;
|
||||
};
|
||||
var findOwnCreateUserRelation = function (actionAuths) {
|
||||
if (userRelations) {
|
||||
var ars = actionAuths.filter(function (ar) { return !!userRelations.find(function (ur) { return ur.relationId === ar.relationId; }); });
|
||||
if (ars.length > 0) {
|
||||
// 这里能找到actionAuth,其必然是本对象上的授权
|
||||
(0, assert_1.default)(!ars.find(function (ele) { return ele.path !== '' || ele.destEntity !== entity; }));
|
||||
return ars;
|
||||
}
|
||||
(0, assert_1.default)(context instanceof SyncRowStore_1.SyncContext);
|
||||
var created = findOwnCreateUserRelation(actionAuths);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return getActionAuths(deducedEntityFilters.map(function (ele) { return _this.checkSingleOperation(ele.entity, ele.filter, actionAuths, context, ele.actions); }));
|
||||
};
|
||||
if (actionAuths instanceof Promise) {
|
||||
return actionAuths.then(function (ars) {
|
||||
var created = findOwnCreateUserRelation(ars);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return Promise.all(deducedEntityFilters.map(function (ele) { return Promise.all(_this.checkSingleOperation(ele.entity, ele.filter, ars, context, ele.actions)); })).then(function (result) { return getActionAuths(result); });
|
||||
});
|
||||
if (deducedEntityFilters2 instanceof Promise) {
|
||||
return deducedEntityFilters2.then(function (def2) { return dealWithDeducedEntityFilters(def2); });
|
||||
}
|
||||
(0, assert_1.default)(context instanceof SyncRowStore_1.SyncContext);
|
||||
var created = findOwnCreateUserRelation(actionAuths);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return getActionAuths(deducedEntityFilters.map(function (ele) { return _this.checkSingleOperation(ele.entity, ele.filter, actionAuths, context, ele.actions); }));
|
||||
return dealWithDeducedEntityFilters(deducedEntityFilters2);
|
||||
};
|
||||
RelationAuth.prototype.checkOperationTree = function (tree, context) {
|
||||
var _this = this;
|
||||
|
|
|
|||
|
|
@ -1600,15 +1600,20 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
}
|
||||
|
||||
|
||||
private getDeducedEntityFilters<T extends keyof ED>(
|
||||
private getDeducedEntityFilters<T extends keyof ED, Cxt extends SyncContext<ED> | AsyncContext<ED>>(
|
||||
entity: T,
|
||||
filter: ED[T]['Selection']['filter'],
|
||||
actions: ED[T]['Action'][],
|
||||
context: Cxt
|
||||
): Array<{
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
actions: ED[T]['Action'][];
|
||||
}> {
|
||||
}> | Promise<Array<{
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
actions: ED[T]['Action'][];
|
||||
}>> {
|
||||
const entityFilters: Array<{
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
|
|
@ -1642,13 +1647,67 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
}
|
||||
}
|
||||
|
||||
if (deduceEntity && deduceFilter) {
|
||||
const addDeduceEntityFilter = (deduceEntity: keyof ED, deduceFilter: ED[keyof ED]['Selection']['filter']) => {
|
||||
const excludeActions = readOnlyActions.concat(['create', 'remove']);
|
||||
const updateActions = this.schema[deduceEntity].actions.filter(
|
||||
(a) => !excludeActions.includes(a)
|
||||
);
|
||||
const deducedSelections = this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions);
|
||||
const deducedSelections = this.getDeducedEntityFilters(deduceEntity, deduceFilter, actions[0] === 'select' ? actions : updateActions, context);
|
||||
if (deducedSelections instanceof Promise) {
|
||||
return deducedSelections.then(
|
||||
(ds) => {
|
||||
entityFilters.push(...ds);
|
||||
return entityFilters;
|
||||
}
|
||||
)
|
||||
}
|
||||
entityFilters.push(...deducedSelections);
|
||||
return entityFilters;
|
||||
};
|
||||
|
||||
if (deduceEntity && deduceFilter) {
|
||||
return addDeduceEntityFilter(deduceEntity, deduceFilter);
|
||||
}
|
||||
else {
|
||||
// 这种情况说明从filter中无法确定相应的deduceFilter,需要查找
|
||||
const rows2 = context.select(entity, {
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter,
|
||||
}, { dontCollect: true });
|
||||
|
||||
const dealWithData = (rows: Partial<ED[keyof ED]['OpSchema']>[]) => {
|
||||
assert(rows.length > 0, `查询无法界定出相应的deduce对象${entity as string},查询条件为${JSON.stringify(filter)}`);
|
||||
let entity2 = rows[0].entity;
|
||||
const entityIds2 = [] as string[];
|
||||
|
||||
rows.forEach(
|
||||
(row) => {
|
||||
assert(row.entity === entity2, `单个查询所推导出的对象不唯一,相应的deduce对象${entity as string},查询条件为${JSON.stringify(filter)}`);
|
||||
assert(typeof row.entityId === 'string');
|
||||
entityIds2.push(row.entityId);
|
||||
}
|
||||
);
|
||||
|
||||
const deduceFilter2 = {
|
||||
entity: entity2,
|
||||
id: entityIds2.length === 1 ? entityIds2[0] : {
|
||||
$in: entityIds2,
|
||||
},
|
||||
};
|
||||
|
||||
return addDeduceEntityFilter(entity2 as keyof ED, deduceFilter2);
|
||||
};
|
||||
|
||||
if (rows2 instanceof Promise) {
|
||||
return rows2.then(
|
||||
(r2) => dealWithData(r2)
|
||||
);
|
||||
}
|
||||
return dealWithData(rows2);
|
||||
}
|
||||
}
|
||||
return entityFilters;
|
||||
|
|
@ -1719,7 +1778,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
* @param entity
|
||||
* @param selection
|
||||
*/
|
||||
private destructOperation<T extends keyof ED>(entity2: T, operation2: Omit<ED[T]['Operation'], 'id'>, userId: string) {
|
||||
private destructOperation<T extends keyof ED>(entity2: T, operation2: Omit<ED[T]['Operation'], 'id'>, userId: string) {
|
||||
/**
|
||||
* 对create动作,把data中的cascade部分剔除后作为filter参与后续的检验
|
||||
* @param operation
|
||||
|
|
@ -1925,117 +1984,136 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
) {
|
||||
const leafSelections = this.destructSelection(entity, selection);
|
||||
const deducedLeafSelections = leafSelections.map(
|
||||
({ entity, filter }) => this.getDeducedEntityFilters(entity, filter, ['select'])
|
||||
).filter(
|
||||
(ele) => {
|
||||
const entities = ele.map(ele => ele.entity);
|
||||
// 同一个leaf的deducedSelections中只要有一个能通过就足够了
|
||||
if (intersection(this.selectFreeEntities, entities).length > 0) {
|
||||
return false;
|
||||
}
|
||||
({ entity, filter }) => this.getDeducedEntityFilters(entity, filter, ['select'], context)
|
||||
);
|
||||
|
||||
if (intersection(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
|
||||
// todo
|
||||
return false;
|
||||
const checkDeducedLeafSelections = (dlSelections2: {
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
actions: ED[T]['Action'][];
|
||||
}[][]) => {
|
||||
const dlSelections = dlSelections2.filter(
|
||||
(ele) => {
|
||||
const entities = ele.map(ele2 => ele2.entity);
|
||||
// 同一个leaf的deducedSelections中只要有一个能通过就足够了
|
||||
if (intersection(this.selectFreeEntities, entities).length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intersection(RelationAuth.SPECIAL_ENTITIES, entities).length > 0) {
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
if (dlSelections.length === 0) {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if (deducedLeafSelections.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!context.getCurrentUserId()) {
|
||||
throw new OakUnloggedInException();
|
||||
}
|
||||
|
||||
if (!context.getCurrentUserId()) {
|
||||
throw new OakUnloggedInException();
|
||||
}
|
||||
const allEntities: (keyof ED)[] = [];
|
||||
dlSelections.forEach(
|
||||
(ele) => ele.forEach(
|
||||
({ entity }) => {
|
||||
allEntities.push(entity)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const allEntities: (keyof ED)[] = [];
|
||||
deducedLeafSelections.forEach(
|
||||
(ele) => ele.forEach(
|
||||
({ entity }) => {
|
||||
allEntities.push(entity)
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
const actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
deActions: {
|
||||
$contains: 'select',
|
||||
},
|
||||
destEntity: {
|
||||
$in: allEntities as string[],
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
|
||||
/**
|
||||
* 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以,第三层为所有可能的actionAuth,通过一个就可以
|
||||
* @param result
|
||||
* @returns
|
||||
*/
|
||||
const checkResult = (result: (ED['actionAuth']['Schema'] | undefined)[][][]) => {
|
||||
const r = !result.find(
|
||||
(ele) => {
|
||||
const eleFlated = ele.flat();
|
||||
return !eleFlated.find(
|
||||
ele2 => !!ele2
|
||||
);
|
||||
}
|
||||
);
|
||||
if (!r && process.env.NODE_ENV === 'development') {
|
||||
deducedLeafSelections.forEach(
|
||||
(ele, idx) => {
|
||||
const r2 = result[idx].flat();
|
||||
if (!r2.find(ele2 => !!ele)) {
|
||||
console.warn('对象的select权限被否决,请检查', ele);
|
||||
}
|
||||
filter: {
|
||||
deActions: {
|
||||
$contains: 'select',
|
||||
},
|
||||
destEntity: {
|
||||
$in: allEntities as string[],
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
|
||||
/**
|
||||
* 返回的结果中,第一层为leafNode,必须全通过,第二层为单个leafNode上的deduce,通过一个就可以,第三层为所有可能的actionAuth,通过一个就可以
|
||||
* @param result
|
||||
* @returns
|
||||
*/
|
||||
const checkResult = (result: (ED['actionAuth']['Schema'] | undefined)[][][]) => {
|
||||
const r = !result.find(
|
||||
(ele) => {
|
||||
const eleFlated = ele.flat();
|
||||
return !eleFlated.find(
|
||||
ele2 => !!ele2
|
||||
);
|
||||
}
|
||||
);
|
||||
if (!r && process.env.NODE_ENV === 'development') {
|
||||
dlSelections.forEach(
|
||||
(ele, idx) => {
|
||||
const r2 = result[idx].flat();
|
||||
if (!r2.find(ele2 => !!ele)) {
|
||||
console.warn('对象的select权限被否决,请检查', ele);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (actionAuths instanceof Promise) {
|
||||
assert(context instanceof AsyncContext);
|
||||
return actionAuths.then(
|
||||
(aas) => Promise.all(dlSelections.map(
|
||||
(ele) => Promise.all(ele.map(
|
||||
(ele2) => Promise.all(this.checkSingleOperation(ele2.entity, ele2.filter, aas as ED['actionAuth']['Schema'][], context, ['select']))
|
||||
))
|
||||
)).then(
|
||||
(result) => checkResult(result)
|
||||
)
|
||||
)
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return checkResult(
|
||||
dlSelections.map(
|
||||
ele => ele.map(
|
||||
ele2 => (this.checkSingleOperation(ele2.entity, ele2.filter, actionAuths as ED['actionAuth']['Schema'][], context, ['select']) as (ED['actionAuth']['Schema'] | undefined)[])
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
if (actionAuths instanceof Promise) {
|
||||
assert(context instanceof AsyncContext);
|
||||
return actionAuths.then(
|
||||
(aas) => Promise.all(deducedLeafSelections.map(
|
||||
(ele) => Promise.all(ele.map(
|
||||
(ele2) => Promise.all(this.checkSingleOperation(ele2.entity, ele2.filter, aas as ED['actionAuth']['Schema'][], context, ['select']))
|
||||
))
|
||||
)).then(
|
||||
(result) => checkResult(result)
|
||||
)
|
||||
)
|
||||
if (deducedLeafSelections[0] instanceof Promise) {
|
||||
return Promise.all(deducedLeafSelections)
|
||||
.then(
|
||||
(dls) => checkDeducedLeafSelections(dls)
|
||||
);
|
||||
}
|
||||
return checkResult(
|
||||
deducedLeafSelections.map(
|
||||
ele => ele.map(
|
||||
ele2 => (this.checkSingleOperation(ele2.entity, ele2.filter, actionAuths as ED['actionAuth']['Schema'][], context, ['select']) as (ED['actionAuth']['Schema'] | undefined)[])
|
||||
)
|
||||
)
|
||||
);
|
||||
return checkDeducedLeafSelections(deducedLeafSelections as {
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
actions: ED[T]['Action'][];
|
||||
}[][]);
|
||||
}
|
||||
|
||||
private findActionAuthsOnNode<Cxt extends AsyncContext<ED> | SyncContext<ED>>(node: OperationTree<ED>, context: Cxt) {
|
||||
|
|
@ -2046,113 +2124,127 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
return [];
|
||||
}
|
||||
|
||||
const deducedEntityFilters = this.getDeducedEntityFilters(entity, filter, [action]);
|
||||
const deducedEntityFilters2 = this.getDeducedEntityFilters(entity, filter, [action], context);
|
||||
|
||||
const allEntities: (keyof ED)[] = deducedEntityFilters.map(ele => ele.entity);
|
||||
const dealWithDeducedEntityFilters = (deducedEntityFilters: {
|
||||
entity: keyof ED;
|
||||
filter: ED[keyof ED]['Selection']['filter'];
|
||||
actions: ED[keyof ED]['Action'][];
|
||||
}[]) => {
|
||||
const allEntities: (keyof ED)[] = deducedEntityFilters.map(ele => ele.entity);
|
||||
|
||||
// todo 这里其实可以在查询条件里通过userRelation过滤一次,但问题不大
|
||||
const actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
// todo 这里其实可以在查询条件里通过userRelation过滤一次,但问题不大
|
||||
const actionAuths = context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
path: 1,
|
||||
destEntity: 1,
|
||||
deActions: 1,
|
||||
relation: {
|
||||
id: 1,
|
||||
userRelation$relation: {
|
||||
$entity: 'userRelation',
|
||||
data: {
|
||||
id: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
filter: {
|
||||
userId: context.getCurrentUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
destEntity: {
|
||||
$in: allEntities as string[],
|
||||
}
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
|
||||
const getActionAuths = (result: (ED['actionAuth']['Schema'] | undefined)[][]) => {
|
||||
const aas: ED['actionAuth']['Schema'][] = [];
|
||||
result.forEach(
|
||||
(ele) => ele.forEach(
|
||||
(ele2) => {
|
||||
if (!!ele2) {
|
||||
aas.push(ele2);
|
||||
}
|
||||
filter: {
|
||||
destEntity: {
|
||||
$in: allEntities as string[],
|
||||
}
|
||||
)
|
||||
);
|
||||
return aas;
|
||||
};
|
||||
|
||||
const findOwnCreateUserRelation = (actionAuths: ED['actionAuth']['Schema'][]) => {
|
||||
if (userRelations) {
|
||||
const ars = actionAuths.filter(
|
||||
(ar) => !!userRelations.find(
|
||||
(ur) => ur.relationId === ar.relationId
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
|
||||
const getActionAuths = (result: (ED['actionAuth']['Schema'] | undefined)[][]) => {
|
||||
const aas: ED['actionAuth']['Schema'][] = [];
|
||||
result.forEach(
|
||||
(ele) => ele.forEach(
|
||||
(ele2) => {
|
||||
if (!!ele2) {
|
||||
aas.push(ele2);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if (ars.length > 0) {
|
||||
// 这里能找到actionAuth,其必然是本对象上的授权
|
||||
assert(!ars.find(
|
||||
ele => ele.path !== '' || ele.destEntity !== entity
|
||||
));
|
||||
return ars;
|
||||
return aas;
|
||||
};
|
||||
|
||||
const findOwnCreateUserRelation = (actionAuths: ED['actionAuth']['Schema'][]) => {
|
||||
if (userRelations) {
|
||||
const ars = actionAuths.filter(
|
||||
(ar) => !!userRelations.find(
|
||||
(ur) => ur.relationId === ar.relationId
|
||||
)
|
||||
);
|
||||
|
||||
if (ars.length > 0) {
|
||||
// 这里能找到actionAuth,其必然是本对象上的授权
|
||||
assert(!ars.find(
|
||||
ele => ele.path !== '' || ele.destEntity !== entity
|
||||
));
|
||||
return ars;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (actionAuths instanceof Promise) {
|
||||
return actionAuths.then(
|
||||
(ars) => {
|
||||
const created = findOwnCreateUserRelation(ars as ED['actionAuth']['Schema'][]);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return Promise.all(
|
||||
deducedEntityFilters.map(
|
||||
ele => Promise.all(
|
||||
this.checkSingleOperation(
|
||||
ele.entity,
|
||||
ele.filter,
|
||||
ars as ED['actionAuth']['Schema'][],
|
||||
context,
|
||||
ele.actions
|
||||
|
||||
if (actionAuths instanceof Promise) {
|
||||
return actionAuths.then(
|
||||
(ars) => {
|
||||
const created = findOwnCreateUserRelation(ars as ED['actionAuth']['Schema'][]);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return Promise.all(
|
||||
deducedEntityFilters.map(
|
||||
ele => Promise.all(
|
||||
this.checkSingleOperation(
|
||||
ele.entity,
|
||||
ele.filter,
|
||||
ars as ED['actionAuth']['Schema'][],
|
||||
context,
|
||||
ele.actions
|
||||
)
|
||||
)
|
||||
)
|
||||
).then(
|
||||
(result) => getActionAuths(result)
|
||||
)
|
||||
).then(
|
||||
(result) => getActionAuths(result)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
assert(context instanceof SyncContext);
|
||||
const created = findOwnCreateUserRelation(actionAuths as ED['actionAuth']['Schema'][]);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return getActionAuths(
|
||||
deducedEntityFilters.map(
|
||||
ele => (this.checkSingleOperation(
|
||||
ele.entity,
|
||||
ele.filter,
|
||||
actionAuths as ED['actionAuth']['Schema'][],
|
||||
context,
|
||||
ele.actions
|
||||
) as (ED['actionAuth']['Schema'] | undefined)[])
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
if (deducedEntityFilters2 instanceof Promise) {
|
||||
return deducedEntityFilters2.then(
|
||||
(def2) => dealWithDeducedEntityFilters(def2)
|
||||
);
|
||||
}
|
||||
|
||||
assert(context instanceof SyncContext);
|
||||
const created = findOwnCreateUserRelation(actionAuths as ED['actionAuth']['Schema'][]);
|
||||
if (created) {
|
||||
return created;
|
||||
}
|
||||
return getActionAuths(
|
||||
deducedEntityFilters.map(
|
||||
ele => (this.checkSingleOperation(
|
||||
ele.entity,
|
||||
ele.filter,
|
||||
actionAuths as ED['actionAuth']['Schema'][],
|
||||
context,
|
||||
ele.actions
|
||||
) as (ED['actionAuth']['Schema'] | undefined)[])
|
||||
)
|
||||
);
|
||||
return dealWithDeducedEntityFilters(deducedEntityFilters2);
|
||||
}
|
||||
|
||||
private checkOperationTree<Cxt extends AsyncContext<ED> | SyncContext<ED>>(tree: OperationTree<ED>, context: Cxt) {
|
||||
|
|
@ -2196,8 +2288,8 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const pathToParent = childPath.endsWith('$entity') ? node.entity as string: childPath.split('$')[1];
|
||||
|
||||
const pathToParent = childPath.endsWith('$entity') ? node.entity as string : childPath.split('$')[1];
|
||||
if (child instanceof Array) {
|
||||
const childActions = child.map(ele => ele.action);
|
||||
const childLegalAuths = realLegalPaths.map(
|
||||
|
|
@ -2254,7 +2346,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
}, { dontCollect: true })
|
||||
}
|
||||
).flat() as ED['actionAuth']['Schema'][] | Promise<ED['actionAuth']['Schema']>[];
|
||||
|
||||
|
||||
if (childLegalAuths[0] instanceof Promise) {
|
||||
return Promise.all(childLegalAuths).then(
|
||||
(clas) => checkChildNode(clas.flat(), child)
|
||||
|
|
@ -2263,7 +2355,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
return checkChildNode(childLegalAuths as ED['actionAuth']['Schema'][], child);
|
||||
}
|
||||
).flat();
|
||||
|
||||
|
||||
if (childResult[0] instanceof Promise) {
|
||||
return Promise.all(childResult).then(
|
||||
(r) => !r.includes(false)
|
||||
|
|
@ -2294,7 +2386,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (realLegalPaths.length === 0) {
|
||||
if (node === tree) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
|
|
|
|||
Loading…
Reference in New Issue