Skip to content

Commit

Permalink
Merge pull request #3 from vivienherq/merge-1
Browse files Browse the repository at this point in the history
Merge master into ui-patching-general
  • Loading branch information
vivienherq authored Apr 14, 2024
2 parents 8f70c9b + 53a6e42 commit 5d2c0d2
Show file tree
Hide file tree
Showing 101 changed files with 1,654 additions and 812 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# ignoring any env files and node_modules in each microservice, will be helpful for local development
**/.env*
**/node_modules/**
**/node_modules/**
node_modules
.env*
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 CS3213 Project Group 9 - FMDevs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Intelligent Tutoring System (ITS)

## Description

Intelligent Tutoring System (ITS) is a platform that can provide high-level feedbacks to coding assignment automatically. It aims to alleviate the workload required for grading coding assignments.

## Project Structure

This project represents the frontend user interfaces of the ITS platform. We are running microservice architecture on the project:

```
├── backend
│ ├── assignment-service
│ ├── user-service
| └── grading-service
├── frontend
├── package.json
├── LICENSE
├── docker-compose.yml
├── .gitignore
└── README.md
```

## Prerequisites

Before running the project, make sure you have access to the following:

- [NodeJS](https://nodejs.org/en/download) environment with version 20 and above
- [Environmental secrets](https://drive.google.com/drive/folders/1yuXEM5f18HtmWPlxYBW2Lmy--jwZ68ck?usp=sharing) for each microservice

## Local Development

Follow these steps to set up and run the project for local development:

1. Clone the repository: `git clone https://github.com/tryyang2001/CS3213-Frontend-Management-System.git`
2. Copy `.env` files obtained from the drive into directories: `frontend`, `backend/assignment-service`, `backend/user-service`, and `backend/grading-service` respectively
3. At the root directory, run `yarn setup` to install all dependencies for all microservices. Take note that this process might take longer to finish (< 10 mins)
4. At the root directory, you may start the development server: `yarn dev`

To run service individually, you will need to change path directory to the target directory, and follow by `yarn dev`. For example, to run only `assignment-service`:

```
cd backend/assignment-service
yarn dev
```

## Production Build and Deployment

Follow these steps to build and run the project in production environment:

1. Follow steps 1, 2, and 3 in local development for setting up the project
2. At the root directory, you may start the server by running `yarn start`

## Contact

If you encountered any problem or need clarification from the developers, kindly contact tanruiyang01@u.nus.edu.
10 changes: 4 additions & 6 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

This folder is intended to contain all the backend related microservices such as authentication, user, grading services, etc.

When working on this folder, ensure you have created a folder for the microservice. Eg:
When working on this folder, ensure you have created a folder for the microservice. Current microservices include:

```
backend
auth
<start your work here...>
user
grading
...
assignment-service
grading-service
user-service
```
5 changes: 4 additions & 1 deletion backend/assignment-service/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
]
],
"@typescript-eslint/explicit-function-return-type": 2,
"@typescript-eslint/explicit-module-boundary-types": 2,
"@typescript-eslint/no-explicit-any": 2
}
}
2 changes: 1 addition & 1 deletion backend/assignment-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"scripts": {
"dev": "prisma generate && nodemon src/app.ts",
"pure-dev": "nodemon src/app.ts",
"build": "prisma generate && tsc -p .",
"build": "prisma generate && yarn lint && tsc -p .",
"start": "node dist/app.js",
"test": "jest --coverage --verbose",
"db": "prisma studio",
Expand Down
37 changes: 26 additions & 11 deletions backend/assignment-service/src/controllers/assignment-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { PutHandler } from "../services/assignments/put-handler";
import { formatZodErrorMessage } from "../libs/utils/error-message-utils";
import { GetAssignmentsQueryValidator } from "../libs/validators/assignments/get-assignments-validator";

const getAssignmentsByUserId = async (request: Request, response: Response) => {
const getAssignmentsByUserId = async (
request: Request,
response: Response
): Promise<void> => {
try {
// obtain userId from the query param

Expand All @@ -24,12 +27,12 @@ const getAssignmentsByUserId = async (request: Request, response: Response) => {

const { userId, includePast, isPublished } =
GetAssignmentsQueryValidator.parse(request.query);
const assignments = await GetHandler.getAssignmentsByUserId(
userId,
includePast,
isPublished
);

const assignments = await GetHandler.getAssignmentsByUserId(
userId,
includePast,
isPublished
);

if (!assignments) {
response.status(HttpStatusCode.NOT_FOUND).json({
Expand All @@ -56,7 +59,10 @@ const getAssignmentsByUserId = async (request: Request, response: Response) => {
}
};

const getAssignmentById = async (request: Request, response: Response) => {
const getAssignmentById = async (
request: Request,
response: Response
): Promise<void> => {
try {
const assignmentId = request.params.id;

Expand All @@ -79,7 +85,10 @@ const getAssignmentById = async (request: Request, response: Response) => {
}
};

const createAssignment = async (request: Request, response: Response) => {
const createAssignment = async (
request: Request,
response: Response
): Promise<void> => {
try {
// request body cannot be empty
if (!request.body || Object.keys(request.body).length === 0) {
Expand Down Expand Up @@ -123,7 +132,10 @@ const createAssignment = async (request: Request, response: Response) => {
}
};

const updateAssignmentById = async (request: Request, response: Response) => {
const updateAssignmentById = async (
request: Request,
response: Response
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down Expand Up @@ -177,7 +189,10 @@ const updateAssignmentById = async (request: Request, response: Response) => {
}
};

const deleteAssignmentById = async (request: Request, response: Response) => {
const deleteAssignmentById = async (
request: Request,
response: Response
): Promise<void> => {
try {
const assignmentId = request.params.id;

Expand Down
4 changes: 2 additions & 2 deletions backend/assignment-service/src/controllers/base-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Request, Response } from "express";
import HttpStatusCode from "../libs/enums/HttpStatusCode";
import db from "../models/db";

const getHealth = async (_: Request, response: Response) => {
const getHealth = async (_: Request, response: Response): Promise<void> => {
try {
const result = await db.$queryRaw`SELECT 1`;
await db.$queryRaw`SELECT 1`;

response.status(HttpStatusCode.OK).json({ message: "Healthy" });
} catch (_error) {
Expand Down
34 changes: 23 additions & 11 deletions backend/assignment-service/src/controllers/question-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { CreateQuestionValidator } from "../libs/validators/questions/create-que
import { formatZodErrorMessage } from "../libs/utils/error-message-utils";
import DuplicateReferenceSolutionError from "../libs/errors/DuplicateReferenceSolutionError";

const getQuestionById = async (request: Request, response: Response) => {
const getQuestionById = async (
request: Request,
response: Response
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand All @@ -40,7 +43,7 @@ const getQuestionById = async (request: Request, response: Response) => {
const getQuestionTestCasesById = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand All @@ -66,7 +69,7 @@ const getQuestionTestCasesById = async (
const getQuestionReferenceSolutionById = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand All @@ -90,7 +93,10 @@ const getQuestionReferenceSolutionById = async (
}
};

const createQuestion = async (request: Request, response: Response) => {
const createQuestion = async (
request: Request,
response: Response
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down Expand Up @@ -147,7 +153,7 @@ const createQuestion = async (request: Request, response: Response) => {
const createQuestionReferenceSolution = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down Expand Up @@ -216,7 +222,7 @@ const createQuestionReferenceSolution = async (
const createQuestionTestCases = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down Expand Up @@ -273,7 +279,10 @@ const createQuestionTestCases = async (
}
};

const updateQuestionById = async (request: Request, response: Response) => {
const updateQuestionById = async (
request: Request,
response: Response
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down Expand Up @@ -331,7 +340,7 @@ const updateQuestionById = async (request: Request, response: Response) => {
const updateQuestionReferenceSolution = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand Down Expand Up @@ -390,7 +399,10 @@ const updateQuestionReferenceSolution = async (
}
};

const deleteQuestionById = async (request: Request, response: Response) => {
const deleteQuestionById = async (
request: Request,
response: Response
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand All @@ -416,7 +428,7 @@ const deleteQuestionById = async (request: Request, response: Response) => {
const deleteQuestionReferenceSolutionById = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
const questionId = request.params.questionId;

Expand All @@ -443,7 +455,7 @@ const deleteQuestionReferenceSolutionById = async (
const deleteQuestionTestCasesById = async (
request: Request,
response: Response
) => {
): Promise<void> => {
try {
if (!request.body || Object.keys(request.body).length === 0) {
response.status(HttpStatusCode.BAD_REQUEST).json({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ZodError } from "zod";

export function formatZodErrorMessage(error: ZodError<any>) {
export function formatZodErrorMessage(error: ZodError<unknown>): string {
let errorMessage = JSON.parse(error.message)[0];

if (errorMessage.message === "Required") {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import db from "../../models/db";
import { Assignment } from "../../types/assignment";

const deleteAssignmentById = async (id: string) => {
const deleteAssignmentById = async (id: string): Promise<Assignment | null> => {
const assignmentExists = await db.assignment.findUnique({
where: {
id: id,
Expand All @@ -17,7 +18,19 @@ const deleteAssignmentById = async (id: string) => {
},
});

return assignment;
const deletedAssignment: Assignment = {
id: assignment.id,
title: assignment.title,
deadline: assignment.deadline.getTime(),
description: assignment.description ?? undefined,
isPublished: assignment.isPublished,
numberOfQuestions: assignment.numberOfQuestions,
authors: assignment.authors,
createdOn: assignment.createdOn.getTime(),
updatedOn: assignment.updatedOn.getTime(),
};

return deletedAssignment;
};

export const DeleteHandler = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import db from "../../models/db";
import { Assignment } from "../../models/types/assignment";
import { Question } from "../../models/types/question";
import { Assignment } from "../../types/assignment";
import { Question } from "../../types/question";

const getAssignmentsByUserId = async (
userId: number,
includePast?: boolean,
isPublishedOnly?: boolean
) => {
): Promise<Assignment[] | null> => {
// check if the user exists
const user = await db.user.findUnique({
where: {
Expand All @@ -29,8 +29,6 @@ const getAssignmentsByUserId = async (
},
});

// TODO: search user under courses, what assignments are there

const assignmentsDto: Assignment[] = assignments.map((assignment) => {
return {
id: assignment.id,
Expand All @@ -47,7 +45,7 @@ const getAssignmentsByUserId = async (
return assignmentsDto;
};

const getAssignmentById = async (id: string) => {
const getAssignmentById = async (id: string): Promise<Assignment | null> => {
const assignment = await db.assignment.findUnique({
where: {
id: id,
Expand Down
Loading

0 comments on commit 5d2c0d2

Please sign in to comment.