Browse Source

Added quota checks to movie requests

master
David Ludwig 4 years ago
parent
commit
80a9c4611f
4 changed files with 45 additions and 15 deletions
  1. +30
    -2
      src/server/database/entities/User.ts
  2. +1
    -1
      src/server/services/WebServer/middleware/auth.ts
  3. +10
    -10
      src/server/services/WebServer/requests/Request.ts
  4. +4
    -2
      src/server/services/WebServer/requests/RequestMovieRequest.ts

+ 30
- 2
src/server/database/entities/User.ts View File

@ -1,4 +1,4 @@
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, OneToMany, OneToOne, JoinColumn, CreateDateColumn } from "typeorm";
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, OneToMany, OneToOne, JoinColumn, CreateDateColumn, MoreThanOrEqual } from "typeorm";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { MovieTicket } from "./MovieTicket";
@ -28,7 +28,7 @@ export class User extends BaseEntity
@OneToOne(() => MovieQuota, { nullable: true })
@JoinColumn()
quota!: MovieQuota;
quota!: MovieQuota | null;
@OneToMany(() => User, user => user.movieTickets)
movieTickets!: MovieTicket[];
@ -69,4 +69,32 @@ export class User extends BaseEntity
}
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;
}
}

+ 1
- 1
src/server/services/WebServer/middleware/auth.ts View File

@ -29,7 +29,7 @@ async function authenticateJwtToken(request: FastifyRequest, reply: FastifyReply
let user: User;
try {
let decoded = <ITokenSchema>jwt.verify(token, Application.instance().APP_KEY);
user = await User.findOneOrFail(decoded.id);
user = await User.findOneOrFail(decoded.id, { relations: [ "quota" ] });
} catch(e) {
reply.status(401);
reply.send({ status: "Unauthorized" });


+ 10
- 10
src/server/services/WebServer/requests/Request.ts View File

@ -7,18 +7,18 @@ export default class Request<T = unknown>
* Handle the incoming request
*/
public async handle(request: MiddlewareRequest<T>, reply: FastifyReply) {
if (!this.isAuthorized(request)) {
reply.status(403);
return {
status: "Forbidden"
};
}
if (!this.checkFormat(request)) {
reply.status(400);
return {
status: "Bad request"
};
}
if (!await this.isAuthorized(request)) {
reply.status(403);
return {
status: "Forbidden"
};
}
try {
await this.validate(request);
} catch(errors) {
@ -33,16 +33,16 @@ export default class Request<T = unknown>
// Overridable ---------------------------------------------------------------------------------
/**
* Check if the user is authorized to make this request
* Check the format of the given request
*/
public isAuthorized(request: MiddlewareRequest<T>) {
public checkFormat(request: MiddlewareRequest<T>) {
return true;
}
/**
* Check the format of the given request
* Check if the user is authorized to make this request
*/
public checkFormat(request: MiddlewareRequest<T>) {
public async isAuthorized(request: MiddlewareRequest<T>) {
return true;
}


+ 4
- 2
src/server/services/WebServer/requests/RequestMovieRequest.ts View File

@ -7,7 +7,9 @@ export default class RequestMovieRequest<T extends IAuthMiddlewareParams> extend
/**
* Ensure the user is able to request movies
*/
public isAuthorized(request: MiddlewareRequest<T>) {
return true;
public async isAuthorized(request: MiddlewareRequest<T>) {
let user = request.middlewareParams.auth.user;
let quota = await user.availableQuota();
return quota === null || quota > 0;
}
}

Loading…
Cancel
Save