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

508 lines
16 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 { OakOperationUnpermittedException, OakPreConditionUnsetException } from "oak-domain/lib/types";
import { generateNewIdAsync } from "oak-domain/lib/utils/uuid";
import { encryptPasswordSha1 } from '../utils/password';
import { assert } from 'oak-domain/lib/utils/assert';
import dayjs from 'dayjs';
export async function mergeUser(params, context, innerLogic) {
const { from, to, mergeMobile, mergeEmail, mergeWechatUser } = params;
if (!innerLogic && !context.isRoot()) {
throw new OakOperationUnpermittedException('user', { id: 'merge', action: 'merge', data: {}, filter: { id: from } }, context.getCurrentUserId(), '不允许执行mergeUser操作');
}
assert(from);
assert(to);
assert(from !== to, '不能merge到相同user');
const schema = context.getSchema();
/* for (const entity in schema) {
if (['oper', 'modi', 'operEntity', 'modiEntity', 'userEntityGrant', 'wechatQrCode'].includes(entity)) {
continue;
}
const entityDesc = schema[entity];
if (entityDesc.view) {
continue;
}
const { attributes } = entityDesc;
for (const attr in attributes) {
const attrDef = attributes[attr as keyof typeof attributes];
if (attrDef.type === 'ref' && attrDef.ref === 'user') {
await context.operate(entity, {
action: 'update',
data: {
[attr]: to,
},
filter: {
[attr]: from,
}
} as any, { dontCollect: true });
}
if (attr === 'entity' && attributes.hasOwnProperty('entityId')) {
await context.operate(entity, {
action: 'update',
data: {
entityId: to,
},
filter: {
entity: 'user',
entityId: from,
}
} as any, { dontCollect: true });
}
}
} */
// 如果from是rootto也得赋上
const [fromUser] = await context.select('user', {
data: {
id: 1,
isRoot: 1,
},
filter: {
id: from,
}
}, { dontCollect: true });
if (fromUser.isRoot) {
await context.operate('user', {
id: await generateNewIdAsync(),
action: 'update',
data: {
isRoot: true,
},
filter: {
id: to,
},
}, {});
}
await context.operate('token', {
id: await generateNewIdAsync(),
action: 'disable',
data: {},
filter: {
ableState: 'enabled',
playerId: from, // todo 这里是playerId, root如果正在扮演该用户待处理
},
}, { dontCollect: true });
await context.operate('user', {
id: await generateNewIdAsync(),
action: 'merge',
data: {
refId: to,
userState: 'merged',
},
filter: {
$or: [
{
id: from,
},
{
userState: 'merged',
refId: from,
}
],
},
}, {});
if (mergeEmail) {
await context.operate('email', {
id: await generateNewIdAsync(),
action: 'update',
data: {
userId: to,
},
filter: {
userId: from,
}
}, { dontCollect: true });
}
if (mergeMobile) {
await context.operate('mobile', {
id: await generateNewIdAsync(),
action: 'update',
data: {
userId: to,
},
filter: {
userId: from,
}
}, { dontCollect: true });
}
if (mergeWechatUser) {
await context.operate('wechatUser', {
id: await generateNewIdAsync(),
action: 'update',
data: {
userId: to,
},
filter: {
userId: from,
}
}, { dontCollect: true });
}
}
export async function getChangePasswordChannels(params, context, innerLogic) {
const { userId } = params;
const mobileList = await context.select('mobile', {
data: {
id: 1,
mobile: 1,
userId: 1,
},
filter: {
userId,
ableState: 'enabled',
},
}, {
dontCollect: true,
});
const [user] = await context.select('user', {
data: {
id: 1,
password: 1,
passwordSha1: 1,
},
filter: {
id: userId,
}
}, {
dontCollect: true
});
const result = [];
if (mobileList.length > 0) {
result.push('mobile');
}
if (user.password || user.passwordSha1) {
result.push('password');
}
return result;
}
export async function updateUserPassword(params, context, innerLogic) {
const { userId, prevPassword, captcha, mobile, newPassword } = params;
const systemId = context.getSystemId();
const closeRootMode = context.openRootMode();
try {
const [system] = await context.select('system', {
data: {
id: 1,
config: 1,
},
filter: {
id: systemId,
}
}, { forUpdate: true });
assert(system);
const config = system.config?.Password;
const mode = config?.mode ?? 'all';
const [user] = await context.select('user', {
data: {
id: 1,
password: 1,
passwordSha1: 1,
},
filter: {
id: userId,
},
}, {
dontCollect: true
});
if (prevPassword) {
const [lastSuccessfulTemp] = await context.select('changePasswordTemp', {
data: {
id: 1,
$$seq$$: 1,
},
filter: {
userId,
$$createAt$$: {
$gt: dayjs().startOf('day').valueOf(),
},
result: 'success',
},
sorter: [
{
$attr: {
$$seq$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
}, {
dontCollect: true,
});
const count1 = await context.count('changePasswordTemp', {
filter: lastSuccessfulTemp
? {
userId,
$$seq$$: {
$gt: lastSuccessfulTemp.$$seq$$,
},
result: 'fail',
}
: {
userId,
$$createAt$$: {
$gt: dayjs().startOf('day').valueOf(),
},
result: 'fail',
},
}, {
dontCollect: true,
});
if (count1 >= 5) {
closeRootMode();
return {
result: '您今天已尝试过太多次,请稍候再进行操作',
times: count1,
};
}
const allowUpdate = mode === 'sha1' ? user.passwordSha1 === prevPassword : user.password === prevPassword; //sha1密文模式判断密文是否相等
let userData = {}, changeCreateData = {};
if (mode === 'all') {
userData = {
password: newPassword,
passwordSha1: encryptPasswordSha1(newPassword),
};
changeCreateData = {
prevPassword,
newPassword,
prevPasswordSha1: encryptPasswordSha1(prevPassword),
newPasswordSha1: encryptPasswordSha1(newPassword),
};
}
else if (mode === 'plain') {
userData = {
password: newPassword,
};
changeCreateData = {
prevPassword,
newPassword,
};
}
else if (mode === 'sha1') {
userData = {
passwordSha1: newPassword,
};
changeCreateData = {
prevPasswordSha1: prevPassword,
newPasswordSha1: newPassword,
};
}
if (allowUpdate) {
await context.operate('user', {
id: await generateNewIdAsync(),
action: 'update',
data: userData,
filter: {
id: userId,
},
}, {
dontCollect: true,
});
await context.operate('changePasswordTemp', {
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
userId,
result: 'success',
...changeCreateData,
},
}, {
dontCollect: true,
});
closeRootMode();
return {
result: 'success'
};
}
else {
await context.operate('changePasswordTemp', {
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
userId,
result: 'fail',
...changeCreateData,
},
}, {
dontCollect: true,
});
closeRootMode();
return {
result: '原密码不正确,请检查后输入',
times: count1,
};
}
}
if (mobile && captcha) {
const [aliveCaptcha] = await context.select('captcha', {
data: {
id: 1,
},
filter: {
origin: 'mobile',
content: mobile,
code: captcha,
expired: false,
},
indexFrom: 0,
count: 1,
}, {
dontCollect: true,
});
if (aliveCaptcha) {
let userData = {}, changeCreateData = {};
if (mode === 'all') {
userData = {
password: newPassword,
passwordSha1: encryptPasswordSha1(newPassword),
};
changeCreateData = {
prevPassword: user.password,
newPassword,
prevPasswordSha1: user.passwordSha1,
newPasswordSha1: encryptPasswordSha1(newPassword),
};
}
else if (mode === 'plain') {
userData = {
password: newPassword,
};
changeCreateData = {
prevPassword: user.password,
newPassword,
};
}
else if (mode === 'sha1') {
userData = {
passwordSha1: newPassword,
};
changeCreateData = {
prevPasswordSha1: user.passwordSha1,
newPasswordSha1: newPassword,
};
}
await context.operate('user', {
id: await generateNewIdAsync(),
action: 'update',
data: userData,
filter: {
id: userId,
},
}, {
dontCollect: true,
});
await context.operate('changePasswordTemp', {
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
userId,
result: 'success',
...changeCreateData,
},
}, {
dontCollect: true,
});
closeRootMode();
return {
result: 'success'
};
}
else {
closeRootMode();
return {
result: '验证码错误',
};
}
}
closeRootMode();
return {
result: '缺少原密码或验证码,请检查后再进行操作'
};
}
catch (err) {
closeRootMode();
throw err;
}
}
/**
* 用户账号注册
* @param params
* @param context
*/
export async function registerUserByLoginName(params, context) {
const { loginName, password } = params;
const systemId = context.getSystemId();
const closeRootMode = context.openRootMode();
try {
// 检查loginName是否重复
const [existLoginName] = await context.select('loginName', {
data: {
id: 1,
name: 1,
},
filter: {
name: loginName,
ableState: 'enabled',
},
}, { dontCollect: true, forUpdate: true });
if (existLoginName) {
closeRootMode();
throw new OakPreConditionUnsetException('账号已存在,请重新设置');
}
// 创建user并附上密码级联创建loginName
const [system] = await context.select('system', {
data: {
id: 1,
config: 1,
},
filter: {
id: systemId,
}
}, { forUpdate: true });
assert(system);
const config = system.config?.Password;
const mode = config?.mode ?? 'all';
let passwordData = {};
if (mode === 'all') {
passwordData = {
password: password,
passwordSha1: encryptPasswordSha1(password),
};
}
else if (mode === 'plain') {
passwordData = {
password: password,
};
}
else if (mode === 'sha1') {
passwordData = {
passwordSha1: password,
};
}
const userData = {
id: await generateNewIdAsync(),
loginName$user: [
{
id: await generateNewIdAsync(),
action: 'create',
data: {
id: await generateNewIdAsync(),
name: loginName,
}
}
]
};
Object.assign(userData, passwordData);
await context.operate('user', {
id: await generateNewIdAsync(),
action: 'create',
data: userData,
}, {});
}
catch (err) {
closeRootMode();
throw err;
}
}