Skip to main content
Glama
user.entity.ts5.14 kB
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany, ManyToMany, JoinTable, Index, BeforeInsert, BeforeUpdate, } from 'typeorm'; import * as bcrypt from 'bcrypt'; import { Role } from './role.entity'; import { AuditLog } from './audit-log.entity'; export enum UserStatus { ACTIVE = 'active', INACTIVE = 'inactive', SUSPENDED = 'suspended', PENDING = 'pending', } @Entity('users') @Index(['email'], { unique: true }) @Index(['username'], { unique: true }) export class User { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'varchar', length: 100, unique: true }) username: string; @Column({ type: 'varchar', length: 255, unique: true }) email: string; @Column({ type: 'varchar', length: 255 }) password: string; @Column({ type: 'varchar', length: 100, nullable: true }) firstName?: string; @Column({ type: 'varchar', length: 100, nullable: true }) lastName?: string; @Column({ type: 'enum', enum: UserStatus, default: UserStatus.PENDING, }) status: UserStatus; @Column({ type: 'boolean', default: false }) emailVerified: boolean; @Column({ type: 'varchar', length: 255, nullable: true }) emailVerificationToken?: string; @Column({ type: 'varchar', length: 255, nullable: true }) passwordResetToken?: string; @Column({ type: 'timestamp', nullable: true }) passwordResetExpires?: Date; @Column({ type: 'timestamp', nullable: true }) lastLoginAt?: Date; @Column({ type: 'inet', nullable: true }) lastLoginIp?: string; @Column({ type: 'int', default: 0 }) loginAttempts: number; @Column({ type: 'timestamp', nullable: true }) lockedUntil?: Date; @Column({ type: 'jsonb', nullable: true }) preferences?: { theme?: 'light' | 'dark'; language?: string; timezone?: string; notifications?: { email?: boolean; push?: boolean; sms?: boolean; }; [key: string]: any; }; @Column({ type: 'jsonb', nullable: true }) metadata?: { department?: string; position?: string; phone?: string; avatar?: string; [key: string]: any; }; @ManyToMany(() => Role, role => role.users, { eager: true }) @JoinTable({ name: 'user_roles', joinColumn: { name: 'userId', referencedColumnName: 'id' }, inverseJoinColumn: { name: 'roleId', referencedColumnName: 'id' }, }) roles: Role[]; @OneToMany(() => AuditLog, auditLog => auditLog.user) auditLogs: AuditLog[]; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; @BeforeInsert() @BeforeUpdate() async hashPassword() { if (this.password && !this.password.startsWith('$2b$')) { const salt = await bcrypt.genSalt(12); this.password = await bcrypt.hash(this.password, salt); } } async validatePassword(password: string): Promise<boolean> { return bcrypt.compare(password, this.password); } get isLocked(): boolean { return this.lockedUntil ? new Date() < this.lockedUntil : false; } get isActive(): boolean { return this.status === UserStatus.ACTIVE && this.emailVerified && !this.isLocked; } get fullName(): string { return [this.firstName, this.lastName].filter(Boolean).join(' ') || this.username; } // 获取用户所有权限 get permissions(): string[] { const permissions = new Set<string>(); this.roles?.forEach(role => { role.permissions?.forEach(permission => { permissions.add(permission.name); }); }); return Array.from(permissions); } // 检查用户是否有特定权限 hasPermission(permissionName: string): boolean { return this.permissions.includes(permissionName); } // 检查用户是否有特定角色 hasRole(roleName: string): boolean { return this.roles?.some(role => role.name === roleName) || false; } // 增加登录失败次数 async incrementLoginAttempts(): Promise<void> { this.loginAttempts += 1; // 如果登录失败次数超过5次,锁定账户1小时 if (this.loginAttempts >= 5) { this.lockedUntil = new Date(Date.now() + 60 * 60 * 1000); // 1小时后解锁 } } // 重置登录失败次数 resetLoginAttempts(): void { this.loginAttempts = 0; this.lockedUntil = null; this.lastLoginAt = new Date(); } // 生成密码重置令牌 generatePasswordResetToken(): string { const token = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); this.passwordResetToken = token; this.passwordResetExpires = new Date(Date.now() + 60 * 60 * 1000); // 1小时有效 return token; } // 生成邮箱验证令牌 generateEmailVerificationToken(): string { const token = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); this.emailVerificationToken = token; return token; } // 清理敏感信息(用于API响应) toSafeObject() { const { password, passwordResetToken, emailVerificationToken, ...safeUser } = this; return safeUser; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zaizaizhao/mcp-swagger-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server