Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f6849f0
Add routes for adding and removing course
jason4193 Jun 19, 2025
b5f21bf
Update routes by moving validation to controller
jason4193 Jun 19, 2025
90a36c3
Add route for update course colour
jason4193 Jun 19, 2025
7b086e5
add OpenAPI for api-docs for backend using swagger library
jason4193 Jun 19, 2025
f10340d
Add ApiProperty for user's route
jason4193 Jun 26, 2025
8351ba5
Add get route for courses and classes with update of routing urls
jason4193 Jun 30, 2025
7a5767b
Update PUT request for setCourseColour to PATCH request
jason4193 Jun 30, 2025
5c78771
Update user routes to using AuthenticatedRequest Type
jason4193 Jun 30, 2025
b0adab4
Add selectClass & removeClass route
jason4193 Jul 3, 2025
48c8a21
Remove OpenAPI and Swagger Library, switched to use Postman
jason4193 Jul 3, 2025
6ba206d
Update route for select and remove class
jason4193 Jul 3, 2025
738fde3
Remove unwanted routes with forwarding functions
jason4193 Jul 3, 2025
7ddde09
Resolve usage of null and undefined
jason4193 Jul 11, 2025
9249ba9
Resolve PR review comments
jason4193 Jul 11, 2025
cb14284
Slim down the Course and Class detail for graphql, and add validation…
jason4193 Jul 11, 2025
ac96945
Update routes returning status code
jason4193 Jul 11, 2025
c7e9e79
Refactor user.controller, move all business validation into service l…
jason4193 Jul 14, 2025
9a98db7
Remove duplicate getCourse request in addSelectedClass
jason4193 Jul 14, 2025
984c7e1
Resolve issues on the PR code review
jason4193 Jul 17, 2025
cbc8ec2
Resolve minor issue on function call, optimise prisma call
jason4193 Jul 17, 2025
20fea88
Resolve function name typo
jason4193 Jul 17, 2025
10326d7
Update service level function name corresponds to control level
jason4193 Jul 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions server/src/graphql/graphql.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { GraphQLClient } from 'graphql-request';
import { getSdk } from '../generated/graphql';
import type { ClassDetails } from './types';

const HASURAGRES_GRAPHQL_API = 'https://graphql.csesoc.app/v1/graphql';

Expand All @@ -21,4 +22,9 @@ export class GraphqlService {

return courseExists.aggregate != null && courseExists.aggregate.count > 0;
}

async getClassDetails(classId: string): Promise<ClassDetails | undefined> {
const { classDetails } = await this.sdk.ClassDetails({ classId });
return classDetails ? classDetails : undefined;
}
}
9 changes: 9 additions & 0 deletions server/src/graphql/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,12 @@ export const COURSE_EXISTS = gql(`
}
}
`);

export const CLASS_DETAILS = gql(`
query ClassDetails($classId: String!) {
classDetails: classes_by_pk(class_id: $classId) {
activity
section
}
}
`);
4 changes: 4 additions & 0 deletions server/src/graphql/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class ClassDetails {
activity: string;
section: string;
}
9 changes: 9 additions & 0 deletions server/src/user/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ export class UserSettings {
unscheduleClassesByDefault: boolean;
hideExamClasses: boolean;
}

export class AddCourseDto {
term: string;
colour: string;
}
export class CourseDetails {
id: string;
selectedClasses: string[];
}
113 changes: 111 additions & 2 deletions server/src/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { Body, Controller, Get, Post, Req, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
Delete,
Get,
HttpStatus,
Param,
Patch,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import { UserService } from './user.service';
import { AuthenticatedGuard } from 'src/auth/authenticated.guard';
import { Request } from 'express';
import { UserSettings } from './types';
import { UserSettings, AddCourseDto } from './types';

interface AuthenticatedRequest extends Request {
user: {
Expand Down Expand Up @@ -49,4 +60,102 @@ export class UserController {
await this.userService.setSettings(req.user.id, settings);
return;
}

@Get('courses/:timetableId')
@UseGuards(AuthenticatedGuard)
async getCourseIds(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
) {
return await this.userService.getCourseIds(req.user.id, timetableId);
}

@Post('course/:timetableId/:courseId')
@UseGuards(AuthenticatedGuard)
async addCourse(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
@Body() addCourseDto: AddCourseDto,
) {
await this.userService.addCourse(
req.user.id,
timetableId,
courseId,
addCourseDto,
);
return HttpStatus.CREATED;
}

@Delete('course/:timetableId/:courseId')
@UseGuards(AuthenticatedGuard)
async removeCourse(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
) {
await this.userService.removeCourse(req.user.id, timetableId, courseId);
}

@Patch('course/:timetableId/:courseId/colour')
@UseGuards(AuthenticatedGuard)
async setCourseColour(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
@Body('colour') colour: string,
) {
await this.userService.setCourseColour(
req.user.id,
timetableId,
courseId,
colour,
);
}

@Get('classes/:timetableId/:courseId')
@UseGuards(AuthenticatedGuard)
async getSelectedClassIds(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
) {
return await this.userService.getSelectedClassIds(
req.user.id,
timetableId,
courseId,
);
}

@Patch('class/:timetableId/:courseId')
@UseGuards(AuthenticatedGuard)
async updateSelectedClass(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
@Body('classId') classId: string,
) {
await this.userService.updateSelectedClass(
req.user.id,
timetableId,
courseId,
classId,
);
}

@Delete('class/:timetableId/:courseId/:classId')
@UseGuards(AuthenticatedGuard)
async removeSelectedClass(
@Req() req: AuthenticatedRequest,
@Param('timetableId') timetableId: string,
@Param('courseId') courseId: string,
@Param('classId') classId: string,
) {
await this.userService.removeSelectedClass(
req.user.id,
timetableId,
courseId,
classId,
);
}
}
3 changes: 2 additions & 1 deletion server/src/user/user.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { GraphqlService } from 'src/graphql/graphql.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
providers: [UserService, PrismaService],
providers: [UserService, PrismaService, GraphqlService],
controllers: [UserController],
})
export class UserModule {}
Loading