oak-general-business/es/checkers/user.js

201 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { judgeRelation } from "oak-domain/lib/store/relation";
import { OakInputIllegalException, OakOperationUnpermittedException } from "oak-domain/lib/types";
import { checkFilterContains } from 'oak-domain/lib/store/filter';
import { isIdCardNumber, isHkCardNumber, isTwCardNumber, isAmCardNumber, isPassportNumber, } from 'oak-domain/lib/utils/validator';
import { pipeline } from 'oak-domain/lib/utils/executor';
import assert from "assert";
import { OakHasToVerifyPassword } from "../types/Exception";
import { getUserSafetyFilter } from "../utils/user";
const checkers = [
{
type: 'row',
action: 'remove',
entity: 'user',
filter: {
userState: 'shadow',
}
},
{
type: 'logical',
action: ['remove', 'disable', 'enable'],
entity: 'user',
checker: (operation, context) => {
// 只有root才能进行操作
if (!context.isRoot()) {
throw new OakOperationUnpermittedException('user', { id: 'disable', action: 'disable', data: {} }, context.getCurrentUserId());
}
}
},
{
type: 'data',
action: 'grant',
entity: 'user',
checker: (data) => {
if (Object.keys(data).filter(ele => !ele.includes('$')).length > 0) {
throw new OakInputIllegalException('user', Object.keys(data), '授权不允许传入其它属性');
}
}
},
{
type: 'row',
action: 'disable',
entity: 'user',
filter: {
isRoot: false,
},
errMsg: '不能禁用root用户',
},
{
type: 'logicalData',
action: 'verify',
entity: 'user',
checker(operation, context) {
const { data, filter } = operation;
const { idCardType, idNumber, extraFile$entity: photos, name } = data;
assert(typeof filter.id === 'string');
const system = context.getApplication().system;
const { config } = system;
return pipeline(() => context.select('user', {
data: {
id: 1,
name: 1,
idCardType: 1,
idNumber: 1,
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
tag2: 1,
}
},
},
filter: {
id: filter.id,
}
}, {}), (users) => {
const [user] = users;
const idCardType = data.idCardType || user.idCardType;
const idNumber = data.idNumber || user.idNumber;
const name = data.name || user.name;
const photo1 = data.extraFile$entity && data.extraFile$entity.find(ele => ele.action === 'create' && ele.data.tag1 === idCardType &&
ele.data.tag2 === 'file1') || user.extraFile$entity && user.extraFile$entity.find(ele => ele.tag1 === idCardType && ele.tag2 === 'file1');
const photo2 = data.extraFile$entity && data.extraFile$entity.find(ele => ele.action === 'create' && ele.data.tag1 === idCardType &&
ele.data.tag2 === 'file2') || user.extraFile$entity && user.extraFile$entity.find(ele => ele.tag1 === idCardType && ele.tag2 === 'file2');
if (!name) {
throw new OakInputIllegalException('user', ['name'], 'error::user.verifyNameEmpty');
}
if (!idCardType) {
throw new OakInputIllegalException('user', ['idCardType'], 'error::user.verifyIdCardTypeEmpty');
}
if (!idNumber) {
throw new OakInputIllegalException('user', ['idNumber'], 'error::user.verifyIdNumberTypeEmpty');
}
if (config.App.needUploadIDCardPhoto) {
if (!photo1) {
throw new OakInputIllegalException('user', ['extraFile$entity'], 'error::user.verifyLackOfPhoto1');
}
if (!photo2) {
throw new OakInputIllegalException('user', ['extraFile$entity'], 'error::user.verifyLackOfPhoto2');
}
}
switch (idCardType) {
case 'ID-Card': {
if (!isIdCardNumber(idNumber)) {
throw new OakInputIllegalException('user', ['idNumber'], 'error::user.verifyIdNumberIllegal');
}
break;
}
case 'Mainland-passport': {
if (!isHkCardNumber(idNumber) && isTwCardNumber(idNumber) && isAmCardNumber(idNumber)) {
throw new OakInputIllegalException('user', ['idNumber'], 'error::user.verifyIdNumberIllegal');
}
break;
}
case 'passport': {
if (!isPassportNumber(idNumber)) {
throw new OakInputIllegalException('user', ['idNumber'], 'error::user.verifyIdNumberIllegal');
}
break;
}
}
});
}
},
{
type: 'row',
entity: 'user',
action: 'update',
filter(operation, context) {
const isRoot = context.isRoot();
if (isRoot) {
return undefined;
}
const { data } = operation;
if (data?.hasOwnProperty('password')) {
return getUserSafetyFilter(context);
}
},
err: OakHasToVerifyPassword,
},
{
type: 'row',
entity: 'user',
action: 'update',
filter(operation, context) {
const isRoot = context.isRoot();
if (isRoot) {
return undefined;
}
const { data } = operation;
if (data?.hasOwnProperty('name') || data?.hasOwnProperty('idCardType')
|| data?.hasOwnProperty('idNumber') || data?.hasOwnProperty('gender')
|| data?.hasOwnProperty('birth')) {
return {
idState: {
$nin: ['verified'],
},
};
}
},
err: OakHasToVerifyPassword,
}
];
export default checkers;
export const UserCheckers = [
{
entity: 'user',
action: 'update',
type: 'logical',
checker: (operation, context) => {
// 在大部分应用中除了root其他人不应该有权利更新其他人信息但是shadow用户应当除外
// 但这些条件不一定对所有的应用都成立应用如果有更复杂的用户相互更新策略就不要引入这个checker
// 这也是个例子如何对user这样的特殊对象进行权限控制
const userId = context.getCurrentUserId();
if (context.isRoot()) {
return;
}
const { filter, data } = operation;
for (const attr in data) {
const rel = judgeRelation(context.getSchema(), 'user', attr);
if (rel !== 1) {
throw new OakOperationUnpermittedException('user', operation, context.getCurrentUserId(), '您不能更新他人信息');
}
}
const result = checkFilterContains('user', context, {
id: userId,
}, filter, true);
if (result instanceof Promise) {
return result.then((r) => {
if (!r) {
throw new OakOperationUnpermittedException('user', operation, context.getCurrentUserId(), '您不能更新他人信息');
}
});
}
if (!result) {
throw new OakOperationUnpermittedException('user', operation, context.getCurrentUserId(), '您不能更新他人信息');
}
},
}
];