eduverse-backend / src /modules /auth /entities /user.entity.ts
Awab-Elsadig's picture
fix(database): normalize FK column types for refactored schema sync
fcab6da
Raw
History Blame Contribute Delete
3.28 kB
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
DeleteDateColumn,
ManyToMany,
JoinTable,
OneToMany,
BeforeInsert,
BeforeUpdate,
} from 'typeorm';
import type { Relation } from 'typeorm';
import { Exclude } from 'class-transformer';
import * as bcrypt from 'bcrypt';
import { Role } from './role.entity';
import { Session } from './session.entity';
import { PasswordReset } from './password-reset.entity';
import { TwoFactorAuth } from './two-factor-auth.entity';
export enum UserStatus {
ACTIVE = 'active',
INACTIVE = 'inactive',
SUSPENDED = 'suspended',
PENDING = 'pending',
}
@Entity('users')
export class User {
@PrimaryGeneratedColumn({ type: 'bigint', unsigned: true, name: 'user_id' })
userId: number;
@Column({ unique: true, length: 100 })
email: string;
@Column({ name: 'password_hash', length: 255 })
@Exclude()
passwordHash: string;
@Column({ name: 'first_name', length: 50 })
firstName: string;
@Column({ name: 'last_name', length: 50 })
lastName: string;
@Column({ length: 20, nullable: true })
phone?: string;
@Column({ name: 'profile_picture_url', type: 'text', nullable: true })
profilePictureUrl?: string;
@Column({ type: 'text', nullable: true })
bio?: string;
@Column({ name: 'social_links', type: 'json', nullable: true })
socialLinks?: Record<string, string>;
@Column({ name: 'academic_interests', type: 'json', nullable: true })
academicInterests?: string[];
@Column({ name: 'skills', type: 'json', nullable: true })
skills?: string[];
@Column({ name: 'campus_id', nullable: true })
campusId?: number;
@Column({
type: 'enum',
enum: UserStatus,
default: UserStatus.PENDING,
})
status: UserStatus;
@Column({ name: 'email_verified', default: false })
emailVerified: boolean;
@Column({ name: 'last_login_at', type: 'datetime', nullable: true })
lastLoginAt?: Date;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt?: Date;
// Relationships
@ManyToMany(() => Role, (role) => role.users)
@JoinTable({
name: 'user_roles',
joinColumn: { name: 'user_id', referencedColumnName: 'userId' },
inverseJoinColumn: { name: 'role_id', referencedColumnName: 'roleId' },
})
roles: Relation<Role>[];
@OneToMany(() => Session, (session) => session.user)
sessions: Relation<Session>[];
@OneToMany(() => PasswordReset, (passwordReset) => passwordReset.user)
passwordResets: Relation<PasswordReset>[];
@OneToMany(() => TwoFactorAuth, (twoFactorAuth) => twoFactorAuth.user)
twoFactorAuths: Relation<TwoFactorAuth>[];
// Hooks for password hashing
@BeforeInsert()
@BeforeUpdate()
async hashPassword() {
if (this.passwordHash && !this.passwordHash.startsWith('$2b$')) {
this.passwordHash = await bcrypt.hash(this.passwordHash, 10);
}
}
// Method to validate password
async validatePassword(password: string): Promise<boolean> {
return bcrypt.compare(password, this.passwordHash);
}
// Computed property for full name
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}