import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, OneToMany, OneToOne, JoinColumn, CreateDateColumn, MoreThanOrEqual } from "typeorm";
|
|
import bcrypt from "bcrypt";
|
|
import { MovieTicket } from "./MovieTicket";
|
|
import { MovieQuota } from "./MovieQuota";
|
|
import { DiscordAccount } from "./DiscordAccount";
|
|
|
|
@Entity()
|
|
export class User extends BaseEntity
|
|
{
|
|
@PrimaryGeneratedColumn()
|
|
id!: number;
|
|
|
|
@Column()
|
|
isAdmin!: boolean;
|
|
|
|
@Column({ length: 50 })
|
|
name!: string;
|
|
|
|
@Column({ length: 255 })
|
|
email!: string;
|
|
|
|
@Column({ type: "char", length: 60 })
|
|
password!: string;
|
|
|
|
@CreateDateColumn()
|
|
createdAt!: Date;
|
|
|
|
@OneToOne(() => MovieQuota, { nullable: true })
|
|
@JoinColumn()
|
|
quota!: MovieQuota | null;
|
|
|
|
@OneToMany(() => User, user => user.movieTickets)
|
|
movieTickets!: MovieTicket[];
|
|
|
|
@OneToMany(() => DiscordAccount, account => account.user)
|
|
discordAccounts!: DiscordAccount[];
|
|
|
|
/**
|
|
* Authenticate a user and return an auth token upon success
|
|
*/
|
|
public static async authenticate(email: string, password: string) {
|
|
let user = <User>await User.findOne({ email });
|
|
if (user === undefined || !(await bcrypt.compare(password, user.password))) {
|
|
return null;
|
|
}
|
|
return user;
|
|
}
|
|
|
|
/**
|
|
* Create a new user
|
|
*/
|
|
public static async createUser(name: string, email: string, password: string, quota: number|null = 5) {
|
|
let user = new User();
|
|
user.isAdmin = false;
|
|
user.name = name;
|
|
user.email = email;
|
|
user.password = await bcrypt.hash(password, 8);
|
|
// Create a quota if necessary
|
|
if (quota !== null) {
|
|
user.quota = new MovieQuota;
|
|
user.quota.moviesPerWeek = quota;
|
|
await user.quota.save();
|
|
}
|
|
return await user.save();
|
|
}
|
|
|
|
/**
|
|
* Determine the user's available quota
|
|
*/
|
|
public async availableQuota() {
|
|
let quota = await this.fetchQuota();
|
|
if (quota === null) {
|
|
return null;
|
|
}
|
|
let oneWeekAgo = new Date(Date.now() - 1000*60*60*24*7);
|
|
let numTicketsThisWeek = await MovieTicket.count({
|
|
user: this,
|
|
createdAt: MoreThanOrEqual(oneWeekAgo),
|
|
isCanceled: false
|
|
});
|
|
return quota.moviesPerWeek - numTicketsThisWeek;
|
|
}
|
|
|
|
/**
|
|
* Get the user's quota, fetching it if undefined
|
|
*/
|
|
public async fetchQuota() {
|
|
if (this.quota !== undefined) {
|
|
return this.quota;
|
|
}
|
|
let user = <User>await User.findOne(this.id, { relations: ["quota"] });
|
|
return user.quota;
|
|
}
|
|
|
|
/**
|
|
* Fetch active movie tickets for this user
|
|
*/
|
|
public async activeMovieTickets() {
|
|
return await MovieTicket.find({
|
|
where: { user: this, isCanceled: false, isFulfilled: false },
|
|
relations: ["info"]
|
|
});
|
|
}
|
|
}
|