mirror of
https://github.com/agregarr/agregarr.git
synced 2026-01-15 01:42:56 +08:00
144 lines
3.5 KiB
TypeScript
144 lines
3.5 KiB
TypeScript
import { UserType } from '@server/constants/user';
|
|
// getSettings import removed - not used in simplified Agregarr User entity
|
|
import bcrypt from 'bcrypt';
|
|
import { randomUUID } from 'crypto';
|
|
import { default as generatePassword } from 'secure-random-password';
|
|
import {
|
|
AfterLoad,
|
|
Column,
|
|
CreateDateColumn,
|
|
Entity,
|
|
OneToOne,
|
|
PrimaryGeneratedColumn,
|
|
UpdateDateColumn,
|
|
} from 'typeorm';
|
|
import { UserSettings } from './UserSettings';
|
|
|
|
@Entity()
|
|
export class User {
|
|
public static filterMany(
|
|
users: User[],
|
|
showFiltered?: boolean
|
|
): Partial<User>[] {
|
|
return users.map((u) => u.filter(showFiltered));
|
|
}
|
|
|
|
static readonly filteredFields: string[] = ['email', 'plexId'];
|
|
|
|
public displayName: string;
|
|
|
|
@PrimaryGeneratedColumn()
|
|
public id: number;
|
|
|
|
@Column({
|
|
unique: true,
|
|
transformer: {
|
|
from: (value: string): string => (value ?? '').toLowerCase(),
|
|
to: (value: string): string => (value ?? '').toLowerCase(),
|
|
},
|
|
})
|
|
public email: string;
|
|
|
|
@Column({ nullable: true })
|
|
public plexUsername?: string;
|
|
|
|
@Column({ nullable: true })
|
|
public plexTitle?: string;
|
|
|
|
@Column({ type: 'boolean', default: false })
|
|
public hasPlexPass = false;
|
|
|
|
@Column({ nullable: true })
|
|
public username?: string;
|
|
|
|
@Column({ nullable: true, select: false })
|
|
public password?: string;
|
|
|
|
@Column({ nullable: true, select: false })
|
|
public resetPasswordGuid?: string;
|
|
|
|
@Column({ type: 'date', nullable: true })
|
|
public recoveryLinkExpirationDate?: Date | null;
|
|
|
|
@Column({ type: 'integer', default: UserType.PLEX })
|
|
public userType: UserType;
|
|
|
|
@Column({ nullable: true, select: true })
|
|
public plexId?: number;
|
|
|
|
@Column({ nullable: true })
|
|
public externalOverseerrId?: number;
|
|
|
|
@Column({ nullable: true, select: false })
|
|
public plexToken?: string;
|
|
|
|
@Column({ type: 'integer', default: 0 })
|
|
public permissions = 0;
|
|
|
|
@Column()
|
|
public avatar: string;
|
|
|
|
@OneToOne(() => UserSettings, (settings) => settings.user, {
|
|
cascade: true,
|
|
eager: true,
|
|
onDelete: 'CASCADE',
|
|
})
|
|
public settings?: UserSettings;
|
|
|
|
@CreateDateColumn()
|
|
public createdAt: Date;
|
|
|
|
@UpdateDateColumn()
|
|
public updatedAt: Date;
|
|
|
|
constructor(init?: Partial<User>) {
|
|
Object.assign(this, init);
|
|
}
|
|
|
|
public filter(showFiltered?: boolean): Partial<User> {
|
|
const filtered: Partial<User> = Object.assign(
|
|
{},
|
|
...(Object.keys(this) as (keyof User)[])
|
|
.filter((k) => showFiltered || !User.filteredFields.includes(k))
|
|
.map((k) => ({ [k]: this[k] }))
|
|
);
|
|
|
|
return filtered;
|
|
}
|
|
|
|
public passwordMatch(password: string): Promise<boolean> {
|
|
return new Promise((resolve) => {
|
|
if (this.password) {
|
|
resolve(bcrypt.compare(password, this.password));
|
|
} else {
|
|
return resolve(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async setPassword(password: string): Promise<void> {
|
|
const hashedPassword = await bcrypt.hash(password, 12);
|
|
this.password = hashedPassword;
|
|
}
|
|
|
|
public async generatePassword(): Promise<void> {
|
|
const password = generatePassword.randomPassword({ length: 16 });
|
|
this.setPassword(password);
|
|
}
|
|
|
|
public async resetPassword(): Promise<void> {
|
|
const guid = randomUUID();
|
|
this.resetPasswordGuid = guid;
|
|
|
|
// 24 hours into the future
|
|
const targetDate = new Date();
|
|
targetDate.setDate(targetDate.getDate() + 1);
|
|
this.recoveryLinkExpirationDate = targetDate;
|
|
}
|
|
|
|
@AfterLoad()
|
|
public setDisplayName(): void {
|
|
this.displayName = this.username || this.plexUsername || this.email;
|
|
}
|
|
}
|