431 lines
14 KiB
JavaScript
431 lines
14 KiB
JavaScript
import { OakOperationUnpermittedException } 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 } }, '不允许执行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是root,to也得赋上
|
||
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 [passport] = await context.select('passport', {
|
||
data: {
|
||
id: 1,
|
||
type: 1,
|
||
config: 1,
|
||
systemId: 1,
|
||
},
|
||
filter: {
|
||
systemId,
|
||
type: 'password',
|
||
}
|
||
}, { forUpdate: true });
|
||
assert(passport);
|
||
const config = passport.config;
|
||
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 userDate = {}, changeCreateDate = {};
|
||
if (mode === 'all') {
|
||
userDate = {
|
||
password: newPassword,
|
||
passwordSha1: encryptPasswordSha1(newPassword),
|
||
};
|
||
changeCreateDate = {
|
||
prevPassword,
|
||
newPassword,
|
||
prevPasswordSha1: encryptPasswordSha1(prevPassword),
|
||
newPasswordSha1: encryptPasswordSha1(newPassword),
|
||
};
|
||
}
|
||
else if (mode === 'plain') {
|
||
userDate = {
|
||
password: newPassword,
|
||
};
|
||
changeCreateDate = {
|
||
prevPassword,
|
||
newPassword,
|
||
};
|
||
}
|
||
else if (mode === 'sha1') {
|
||
userDate = {
|
||
passwordSha1: newPassword,
|
||
};
|
||
changeCreateDate = {
|
||
prevPasswordSha1: prevPassword,
|
||
newPasswordSha1: newPassword,
|
||
};
|
||
}
|
||
if (allowUpdate) {
|
||
await context.operate('user', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'update',
|
||
data: userDate,
|
||
filter: {
|
||
id: userId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
await context.operate('changePasswordTemp', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'create',
|
||
data: {
|
||
id: await generateNewIdAsync(),
|
||
userId,
|
||
result: 'success',
|
||
...changeCreateDate,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
closeRootMode();
|
||
return {
|
||
result: 'success'
|
||
};
|
||
}
|
||
else {
|
||
await context.operate('changePasswordTemp', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'create',
|
||
data: {
|
||
id: await generateNewIdAsync(),
|
||
userId,
|
||
result: 'fail',
|
||
...changeCreateDate,
|
||
},
|
||
}, {
|
||
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 userDate = {}, changeCreateDate = {};
|
||
if (mode === 'all') {
|
||
userDate = {
|
||
password: newPassword,
|
||
passwordSha1: encryptPasswordSha1(newPassword),
|
||
};
|
||
changeCreateDate = {
|
||
prevPassword: user.password,
|
||
newPassword,
|
||
prevPasswordSha1: user.passwordSha1,
|
||
newPasswordSha1: encryptPasswordSha1(newPassword),
|
||
};
|
||
}
|
||
else if (mode === 'plain') {
|
||
userDate = {
|
||
password: newPassword,
|
||
};
|
||
changeCreateDate = {
|
||
prevPassword: user.password,
|
||
newPassword,
|
||
};
|
||
}
|
||
else if (mode === 'sha1') {
|
||
userDate = {
|
||
passwordSha1: newPassword,
|
||
};
|
||
changeCreateDate = {
|
||
prevPasswordSha1: user.passwordSha1,
|
||
newPasswordSha1: newPassword,
|
||
};
|
||
}
|
||
await context.operate('user', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'update',
|
||
data: userDate,
|
||
filter: {
|
||
id: userId,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
await context.operate('changePasswordTemp', {
|
||
id: await generateNewIdAsync(),
|
||
action: 'create',
|
||
data: {
|
||
id: await generateNewIdAsync(),
|
||
userId,
|
||
result: 'success',
|
||
...changeCreateDate,
|
||
},
|
||
}, {
|
||
dontCollect: true,
|
||
});
|
||
closeRootMode();
|
||
return {
|
||
result: 'success'
|
||
};
|
||
}
|
||
else {
|
||
closeRootMode();
|
||
return {
|
||
result: '验证码错误',
|
||
};
|
||
}
|
||
}
|
||
closeRootMode();
|
||
return {
|
||
result: '缺少原密码或验证码,请检查后再进行操作'
|
||
};
|
||
}
|
||
catch (err) {
|
||
closeRootMode();
|
||
throw err;
|
||
}
|
||
}
|