Skip to content

Commit

Permalink
Feature/admin (#232)
Browse files Browse the repository at this point in the history
  • Loading branch information
aimenhamed authored Aug 24, 2023
1 parent 3ffeebd commit 09a9c5a
Show file tree
Hide file tree
Showing 146 changed files with 688 additions and 19,575 deletions.
44 changes: 4 additions & 40 deletions backend/src/controllers/course.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@ import { Router, Request, Response, NextFunction } from "express";
import { formatError, getLogger } from "../utils/logger";
import { IController } from "../interfaces/IController";
import { CourseService } from "../services/course.service";

import {
BookmarkCourseSchema,
UpdateCourseSchema,
CourseBody,
BookmarkCourse,
} from "../api/schemas/course.schema";
import validationMiddleware from "../api/middlewares/validation";
import { HTTPError } from "../utils/errors";
import { badRequest } from "../utils/constants";
import verifyToken from "../api/middlewares/auth";

export class CourseController implements IController {
private readonly logger = getLogger();
Expand Down Expand Up @@ -49,35 +40,6 @@ export class CourseController implements IController {
}
},
)
.put(
"/courses/:courseCode",
validationMiddleware(UpdateCourseSchema, "body"),
async (
req: Request<{ courseCode: string }, unknown, CourseBody>,
res: Response,
next: NextFunction,
) => {
const { courseCode } = req.params;
this.logger.debug(`Received request in PUT /courses/${courseCode}`);
try {
const { course } = req.body;
if (courseCode !== course.courseCode)
throw new HTTPError(badRequest);
const result = await this.courseService.updateCourse(course);
this.logger.info(
`Responding to client in PUT /courses/${courseCode}`,
);
return res.status(200).json(result);
} catch (err: any) {
this.logger.warn(
`An error occurred when trying to PUT /courses/${courseCode} ${formatError(
err,
)}`,
);
return next(err);
}
},
)
.get(
"/course/:courseCode",
async (
Expand Down Expand Up @@ -129,6 +91,7 @@ export class CourseController implements IController {
)
.delete(
"/cached/:key",
[verifyToken],
async (
req: Request<{ key: string }, unknown>,
res: Response,
Expand All @@ -137,7 +100,8 @@ export class CourseController implements IController {
this.logger.debug(`Received request in DELETE /cached/:key`);
try {
const key: string = req.params.key;
const result = await this.courseService.flushKey(key);
const zid = req.headers.zid as string;
const result = await this.courseService.flushKey(zid, key);
this.logger.info(`Responding to client in DELETE /cached/${key}`);
return res.status(200).json(result);
} catch (err: any) {
Expand Down
9 changes: 6 additions & 3 deletions backend/src/controllers/report.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router, Request, Response, NextFunction } from "express";
import { formatError, getLogger } from "../utils/logger";
import { ReportService } from "../services/report.service";
import verifyToken from "../api/middlewares/auth";
import validationMiddleware from "../api/middlewares/validation";
import {
CreateReport,
Expand All @@ -23,10 +24,12 @@ export class ReportController implements IController {
return Router()
.get(
"/reports",
[verifyToken],
async (req: Request, res: Response, next: NextFunction) => {
this.logger.debug(`Received GET request in /reports`);
try {
const result = await this.reportService.getAllReports();
const zid = req.headers.zid as string;
const result = await this.reportService.getAllReports(zid);
this.logger.info(`Responding to client in /reports`);
return res.status(200).json(result);
} catch (err: any) {
Expand All @@ -41,7 +44,7 @@ export class ReportController implements IController {
)
.post(
"/reports",
validationMiddleware(CreateReportSchema, "body"),
[verifyToken, validationMiddleware(CreateReportSchema, "body")],
async (
req: Request<Record<string, never>, unknown, CreateReport>,
res: Response,
Expand All @@ -65,7 +68,7 @@ export class ReportController implements IController {
)
.put(
"/reports",
validationMiddleware(UpdateReportStatusSchema, "body"),
[verifyToken, validationMiddleware(UpdateReportStatusSchema, "body")],
async (
req: Request<Record<string, never>, unknown, UpdateReportStatus>,
res: Response,
Expand Down
10 changes: 6 additions & 4 deletions backend/src/controllers/review.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router, Request, Response, NextFunction } from "express";
import { formatError, getLogger } from "../utils/logger";
import { ReviewService } from "../services/review.service";
import verifyToken from "../api/middlewares/auth";
import validationMiddleware from "../api/middlewares/validation";
import { HTTPError } from "../utils/errors";
import { badRequest } from "../utils/constants";
Expand Down Expand Up @@ -73,7 +74,7 @@ export class ReviewController implements IController {
)
.post(
"/reviews",
validationMiddleware(PostReviewSchema, "body"),
[verifyToken, validationMiddleware(PostReviewSchema, "body")],
async (
req: Request<Record<string, never>, unknown, PostReviewRequestBody>,
res: Response,
Expand All @@ -98,7 +99,7 @@ export class ReviewController implements IController {
)
.put(
"/reviews/:reviewId",
validationMiddleware(PutReviewRequestBodySchema, "body"),
[verifyToken, validationMiddleware(PutReviewRequestBodySchema, "body")],
async (
req: Request<{ reviewId: string }, unknown, PutReviewRequestBody>,
res: Response,
Expand Down Expand Up @@ -129,6 +130,7 @@ export class ReviewController implements IController {
)
.delete(
"/reviews/:reviewId",
[verifyToken],
async (
req: Request<{ reviewId: string }, unknown>,
res: Response,
Expand All @@ -155,7 +157,7 @@ export class ReviewController implements IController {
)
.post(
"/reviews/bookmark",
validationMiddleware(BookmarkReviewSchema, "body"),
[verifyToken, validationMiddleware(BookmarkReviewSchema, "body")],
async (
req: Request<Record<string, never>, unknown, BookmarkReview>,
res: Response,
Expand All @@ -182,7 +184,7 @@ export class ReviewController implements IController {
)
.post(
"/reviews/upvote",
validationMiddleware(UpvoteReviewSchema, "body"),
[verifyToken, validationMiddleware(UpvoteReviewSchema, "body")],
async (
req: Request<Record<string, never>, unknown, UpvoteReview>,
res: Response,
Expand Down
9 changes: 0 additions & 9 deletions backend/src/repositories/course.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,4 @@ export class CourseRepository {
const courses = rawCourses.map((course) => CourseSchema.parse(course));
return courses;
}

async save(course: Course): Promise<Course> {
const newCourseData = await this.prisma.courses.update({
where: { courseCode: course.courseCode },
data: { ...course },
});
const newCourse = CourseSchema.parse(newCourseData);
return newCourse;
}
}
27 changes: 8 additions & 19 deletions backend/src/repositories/report.repository.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { PrismaClient } from "@prisma/client";
import {
CreateReport,
Report,
ReportSchema,
UpdateReportStatus,
} from "../api/schemas/report.schema";
import { CreateReport, UpdateReportStatus } from "../api/schemas/report.schema";

export class ReportRepository {
constructor(private readonly prisma: PrismaClient) {}

async getAllReports(): Promise<Report[]> {
async getAllReports() {
const rawReports = await this.prisma.reports.findMany({
include: {
users: true,
},
});
const reports = rawReports.map((report) => ReportSchema.parse(report));
return reports;
return rawReports;
}

async getReportByUser(zid: string): Promise<Report[]> {
async getReportByUser(zid: string) {
const rawReports = await this.prisma.reports.findMany({
where: {
zid: zid,
Expand All @@ -28,8 +22,7 @@ export class ReportRepository {
reviews: true,
},
});
const reports = rawReports.map((report) => ReportSchema.parse(report));
return reports;
return rawReports;
}

async getReportByUserAndReview(zid: string, reviewId: string) {
Expand Down Expand Up @@ -70,19 +63,15 @@ export class ReportRepository {
return rawReport;
}

async saveReport(report: UpdateReportStatus): Promise<Report> {
const rawReport = await this.prisma.reports.update({
async updateReport(report: UpdateReportStatus) {
const updatedReport = await this.prisma.reports.update({
where: {
reportId: report.reportId,
},
data: {
...report,
},
include: {
users: true,
},
});
const savedReport = ReportSchema.parse(rawReport);
return savedReport;
return updatedReport;
}
}
23 changes: 0 additions & 23 deletions backend/src/services/course.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,6 @@ describe("CourseService", () => {
});
});

describe("updateCourse", () => {
it("should throw HTTP 400 error if no courses in database", () => {
const service = courseService();
const course = getMockCourses()[0];
courseRepository.getCourse = jest.fn().mockResolvedValue(undefined);

const errorResult = new HTTPError(badRequest);
expect(service.updateCourse(course)).rejects.toThrow(errorResult);
});

it("should resolve and return new updated course", () => {
const service = courseService();
const entity = getCourseEntity();
const course = getMockCourses()[0];
courseRepository.getCourse = jest.fn().mockResolvedValue(entity);
courseRepository.save = jest.fn().mockResolvedValue(entity);

expect(service.updateCourse(course)).resolves.toEqual({
course: course,
});
});
});

describe("getCourse", () => {
it("should throw HTTP 500 error if there is no course in database", () => {
const service = courseService();
Expand Down
32 changes: 13 additions & 19 deletions backend/src/services/course.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { getLogger } from "../utils/logger";
import { HTTPError } from "../utils/errors";
import { badRequest, internalServerError } from "../utils/constants";
import {
badRequest,
internalServerError,
unauthorizedError,
} from "../utils/constants";
import { CourseRepository } from "../repositories/course.repository";
import { UserRepository } from "../repositories/user.repository";
import RedisClient from "../modules/redis";
import {
BookmarkCourse,
Course,
CourseBody,
CoursesSuccessResponse,
Expand Down Expand Up @@ -85,27 +88,18 @@ export class CourseService {
return { courses };
}

async updateCourse(updatedCourse: Course): Promise<CourseBody | undefined> {
let course = await this.courseRepository.getCourse(
updatedCourse.courseCode,
);

if (!course) {
this.logger.error(
`There is no course with courseCode ${updatedCourse.courseCode}.`,
);
async flushKey(zid: string, key: string) {
const userInfo = await this.userRepository.getUser(zid);
if (!userInfo) {
this.logger.error(`Database could not find user with zid ${zid}`);
throw new HTTPError(badRequest);
}

course = await this.courseRepository.save(course);

this.logger.info(
`Successfully updated course with courseCode ${updatedCourse.courseCode}.`,
);
return { course };
}
if (!userInfo.isAdmin) {
this.logger.error(`Non-admin ${zid} tried retrieving reports`);
throw new HTTPError(unauthorizedError);
}

async flushKey(key: string) {
await this.redis.del(key);
}
}
Loading

0 comments on commit 09a9c5a

Please sign in to comment.