import { request } from '../api/request'; import { buildCachedRequest } from '../cache/utils'; import { sharedEvent } from '../event'; import { SYSTEM_USERID } from '../utils/consts'; import { createAutoMergedRequest, createAutoSplitRequest, } from '../utils/request'; import _pick from 'lodash/pick'; import _uniq from 'lodash/uniq'; import _flatten from 'lodash/flatten'; import _zipObject from 'lodash/zipObject'; import { t } from '../i18n'; export interface UserBaseInfo { _id: string; email: string; nickname: string; discriminator: string; avatar: string | null; temporary: boolean; emailVerified: boolean; banned: boolean; extra?: Record; } export interface UserLoginInfo extends UserBaseInfo { token: string; createdAt: string; } export interface UserSettings { /** * 消息列表虚拟化 */ messageListVirtualization?: boolean; /** * 消息通知免打扰(静音) */ messageNotificationMuteList?: string[]; /** * 群组排序, 内容为群组id */ groupOrderList?: string[]; /** * 其他的设置项 */ [key: string]: any; } export function pickUserBaseInfo(userInfo: UserLoginInfo): UserBaseInfo { return _pick(userInfo, [ '_id', 'email', 'nickname', 'discriminator', 'avatar', 'temporary', 'emailVerified', 'banned', ]); } // 内置用户信息 const builtinUserInfo: Record UserBaseInfo> = { [SYSTEM_USERID]: () => ({ _id: SYSTEM_USERID, email: 'admin@msgbyte.com', nickname: t('系统'), discriminator: '0000', avatar: null, temporary: false, emailVerified: false, banned: false, }), }; /** * 用户私信列表 */ export interface UserDMList { userId: string; converseIds: string[]; } /** * 邮箱登录 * @param email 邮箱 * @param password 密码 */ export async function loginWithEmail( email: string, password: string ): Promise { const { data } = await request.post('/api/user/login', { email, password, }); sharedEvent.emit('loginSuccess', pickUserBaseInfo(data)); return data; } /** * 使用 Token 登录 * @param token JWT令牌 */ export async function loginWithToken(token: string): Promise { const { data } = await request.post('/api/user/resolveToken', { token, }); sharedEvent.emit('loginSuccess', pickUserBaseInfo(data)); return data; } /** * 发送邮箱校验码 * @param email 邮箱 */ export async function verifyEmail(email: string): Promise { const { data } = await request.post('/api/user/verifyEmail', { email, }); return data; } /** * 检查邮箱校验码并更新用户字段 * @param email 邮箱 */ export async function verifyEmailWithOTP( emailOTP: string ): Promise { const { data } = await request.post('/api/user/verifyEmailWithOTP', { emailOTP, }); return data; } /** * 邮箱注册账号 * @param email 邮箱 * @param password 密码 */ export async function registerWithEmail({ email, password, nickname, emailOTP, }: { email: string; password: string; nickname?: string; emailOTP?: string; }): Promise { const { data } = await request.post('/api/user/register', { email, nickname, password, emailOTP, }); return data; } /** * 修改密码 */ export async function modifyUserPassword( oldPassword: string, newPassword: string ): Promise { await request.post('/api/user/modifyPassword', { oldPassword, newPassword, }); } /** * 忘记密码 * @param email 邮箱 */ export async function forgetPassword(email: string) { await request.post('/api/user/forgetPassword', { email, }); } /** * 忘记密码 * @param email 邮箱 */ export async function resetPassword( email: string, password: string, otp: string ) { await request.post('/api/user/resetPassword', { email, password, otp, }); } /** * 创建访客账号 * @param nickname 访客昵称 */ export async function createTemporaryUser( nickname: string ): Promise { const { data } = await request.post('/api/user/createTemporaryUser', { nickname, }); return data; } /** * 认领访客账号 */ export async function claimTemporaryUser( userId: string, email: string, password: string, emailOTP?: string ): Promise { const { data } = await request.post('/api/user/claimTemporaryUser', { userId, email, password, emailOTP, }); return data; } /** * 使用唯一标识名搜索用户 * @param uniqueName 唯一标识用户昵称: 用户昵称#0000 */ export async function searchUserWithUniqueName( uniqueName: string ): Promise { const { data } = await request.post('/api/user/searchUserWithUniqueName', { uniqueName, }); return data; } const _fetchUserInfo = createAutoMergedRequest( createAutoSplitRequest( async (userIds) => { // 这里用post是为了防止一次性获取的userId过多超过url限制 const { data } = await request.post('/api/user/getUserInfoList', { userIds, }); return data; }, 'serial', 1000 ) ); /** * 获取用户基本信息 * @param userId 用户ID */ export async function fetchUserInfo(userId: string): Promise { if ( builtinUserInfo[userId] && typeof builtinUserInfo[userId] === 'function' ) { return builtinUserInfo[userId](); } const userInfo = await _fetchUserInfo(userId); return userInfo; } const _fetchUserOnlineStatus = createAutoMergedRequest( createAutoSplitRequest( async (userIdsList) => { const uniqList = _uniq(_flatten(userIdsList)); // 这里用post是为了防止一次性获取的userId过多超过url限制 const { data } = await request.post('/api/gateway/checkUserOnline', { userIds: uniqList, }); const map = _zipObject(uniqList, data); // 将请求结果根据传输来源重新分组 return userIdsList.map((userIds) => userIds.map((userId) => map[userId] ?? false) ); }, 'serial', 1000 ) ); /** * 获取用户在线状态 */ export async function getUserOnlineStatus( userIds: string[] ): Promise { return _fetchUserOnlineStatus(userIds); } /** * 将会话添加到用户私信列表 * 如果已添加则后端忽略 */ export async function appendUserDMConverse( converseId: string ): Promise { const { data } = await request.post( '/api/user/dmlist/addConverse', { converseId, } ); return data; } /** * 移除会话列表 */ export async function removeUserDMConverse( converseId: string ): Promise { const { data } = await request.post( '/api/user/dmlist/removeConverse', { converseId, } ); return data; } /** * 修改用户属性 * @param fieldName 要修改的属性名 * @param fieldValue 要修改的属性的值 */ type AllowedModifyField = 'nickname' | 'avatar'; export async function modifyUserField( fieldName: AllowedModifyField, fieldValue: unknown ): Promise { const { data } = await request.post('/api/user/updateUserField', { fieldName, fieldValue, }); return data; } export async function modifyUserExtra( fieldName: string, fieldValue: unknown ): Promise { const { data } = await request.post('/api/user/updateUserExtra', { fieldName, fieldValue, }); return data; } /** * 获取用户设置 */ export async function getUserSettings(): Promise { const { data } = await request.get('/api/user/getUserSettings'); sharedEvent.emit('userSettingsUpdate', data); return data; } /** * 设置用户设置 */ export async function setUserSettings( settings: UserSettings ): Promise { const { data } = await request.post('/api/user/setUserSettings', { settings, }); return data; } /** * 检查Token是否可用 */ export const checkTokenValid = buildCachedRequest( 'tokenValid', async (token: string): Promise => { const { data } = await request.post('/api/user/checkTokenValid', { token, }); return data; } );