You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailchat/server/models/user/user.ts

192 lines
3.2 KiB
TypeScript

import {
getModelForClass,
prop,
DocumentType,
ReturnModelType,
modelOptions,
Severity,
index,
} from '@typegoose/typegoose';
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses';
import type { Types } from 'mongoose';
import { UserType, userType } from 'tailchat-server-sdk';
type BaseUserInfo = Pick<User, 'nickname' | 'discriminator' | 'avatar'>;
/**
* 用户设置
*/
export interface UserSettings {
/**
* 消息列表虚拟化
*/
messageListVirtualization?: boolean;
[key: string]: any;
}
export interface UserLoginRes extends User {
token: string;
}
@modelOptions({
options: {
allowMixed: Severity.ALLOW,
},
})
@index({ avatar: 1 })
export class User extends TimeStamps implements Base {
_id: Types.ObjectId;
id: string;
/**
* 用户名 不可被修改
* 与email必有一个
*/
@prop()
username?: string;
/**
* 邮箱 不可被修改
* 必填
*/
@prop({
index: true,
unique: true,
})
email: string;
@prop()
password!: string;
/**
* 可以被修改的显示名
*/
@prop({
trim: true,
maxlength: 20,
})
nickname!: string;
/**
* 识别器, 跟username构成全局唯一的用户名
* 用于搜索
* <username>#<discriminator>
*/
@prop()
discriminator: string;
/**
* 是否为临时用户
* @default false
*/
@prop({
default: false,
})
temporary: boolean;
/**
* 头像
*/
@prop()
avatar?: string;
/**
* 用户类型
*/
@prop({
enum: userType,
type: () => String,
default: 'normalUser',
})
type: UserType;
/**
* 邮箱是否可用
*/
@prop({
default: false,
})
emailVerified: boolean;
/**
* 是否被封禁
*/
@prop({
default: false,
})
banned: boolean;
/**
* 用户的额外信息
*/
@prop()
extra?: object;
/**
* 用户设置
*/
@prop({
default: {},
})
settings: UserSettings;
/**
* 生成身份识别器
* 0001 - 9999
*/
public static generateDiscriminator(
this: ReturnModelType<typeof User>,
nickname: string
): Promise<string> {
let restTimes = 10; // 最多找10次
const checkDiscriminator = async () => {
const discriminator = String(
Math.floor(Math.random() * 9999) + 1
).padStart(4, '0');
const doc = await this.findOne({
nickname,
discriminator,
}).exec();
restTimes--;
if (doc !== null) {
// 已存在, 换一个
if (restTimes <= 0) {
throw new Error('Cannot find space discriminator');
}
return checkDiscriminator();
}
return discriminator;
};
return checkDiscriminator();
}
/**
* 获取用户基本信息
*/
static async getUserBaseInfo(
this: ReturnModelType<typeof User>,
userId: string
): Promise<BaseUserInfo> {
const user = await this.findById(String(userId));
return {
nickname: user.nickname,
discriminator: user.discriminator,
avatar: user.avatar,
};
}
}
export type UserDocument = DocumentType<User>;
const model = getModelForClass(User);
export type UserModel = typeof model;
export default model;