Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
211d03b
Add ux ui mockups link (#4)
kevin-lann Jan 28, 2025
c880b5d
Add Product.md file (#5) - Scrum 19
minhhaitran08 Jan 30, 2025
68ba14f
Finish all sections of README.md apart from the Installation section …
Austin-X Jan 30, 2025
40cb488
Ty/scrum 63 added product_backlog.md (#11)
thomasyzy7 Jan 31, 2025
61030d1
Kl/scrum 21 installation (#10)
kevin-lann Jan 31, 2025
18ac6de
Kl/scrum 20 project setup (#12)
kevin-lann Jan 31, 2025
9230bbf
Ms/scrum 23 added personas (#9)
MasahisaSekita Jan 31, 2025
eaf04ba
Fix: README .env typo (#13)
kevin-lann Jan 31, 2025
ab8a7e1
Release/0.1 - Develop (#15)
thomasyzy7 Feb 1, 2025
ccf59f9
[Hotfix]: Add missing section in README.md for "Tech Stack and Softwa…
Austin-X Feb 1, 2025
e27c8ee
Kl/scrum 69 extract info (#18)
kevin-lann Feb 9, 2025
a90b064
Setup redux store and api slice (#19)
kevin-lann Feb 10, 2025
e59147e
Kl/scrum 71 course list frontend (#21)
kevin-lann Feb 11, 2025
5d9786d
Set up /api/courses and /api/departments endpoints in backend (#22)
Austin-X Feb 12, 2025
ac83923
Ms/scrum 26 login and signup (#25)
MasahisaSekita Feb 13, 2025
e0338e7
Integrate Course List and Entries display (#23)
kevin-lann Feb 13, 2025
b94deb2
Ty/scrum 80 user auth backend (#26)
thomasyzy7 Feb 14, 2025
16c3993
Add User Menu Dropdown Component (#27)
Austin-X Feb 14, 2025
a2d17a2
Integrate Login and Signup (#28)
kevin-lann Feb 14, 2025
bf85a8f
Account Logout Functionality (#29)
Austin-X Feb 14, 2025
66229ba
SCRUM70 - Mt/scrum 70 sprint1 documentation (#20)
minhhaitran08 Feb 15, 2025
d859df0
Release/1.0 - Develop (#31)
thomasyzy7 Feb 15, 2025
0c61165
[SCRUM-107]: Set up Github Workflow to auto-format unformatted code u…
Austin-X Feb 18, 2025
0209f3e
Ty/scrum 95 Reset Password Backend (#32)
thomasyzy7 Feb 18, 2025
0dc08b2
Kl/scrum 110 document frontend (#35)
kevin-lann Feb 19, 2025
3e47072
Ax/scrum 111 document backend (#36)
Austin-X Feb 19, 2025
6c36d1c
Kl/scrum 112 Bugfix add password max length validation (#40)
kevin-lann Feb 19, 2025
76339d3
Kl/scrum 113 Set user session after login to handle RLS & Modify back…
kevin-lann Feb 20, 2025
64f971a
Kl/scrum 114 fix redirect login (#41)
kevin-lann Feb 20, 2025
b67705d
Kl/scrum 117 fix auth middleware (#44)
kevin-lann Feb 21, 2025
2830739
Kl/scrum 115 setup assistant UI (#45)
kevin-lann Feb 28, 2025
69e3275
Ty/scrum 119 sprint2 iteration (#47)
thomasyzy7 Mar 4, 2025
218c1bb
Ms/scrum 95 account edit (#43)
MasahisaSekita Mar 4, 2025
de664e4
Mt/scrum 46 child 102 create user timetable backend endpoints (#46)
minhhaitran08 Mar 5, 2025
88a1b55
Kl/scrum 116 chatbot rag (#48)
kevin-lann Mar 6, 2025
79f091b
kl/scrum-121 Fix cors line in index.ts (#57)
kevin-lann Mar 7, 2025
46f0384
Kl/scrum 36 chats (#51)
kevin-lann Mar 7, 2025
6f15fb9
Ax/scrum 123 Set up Unit Testing Template and Testing Workflow (#58)
Austin-X Mar 8, 2025
f57f4de
Ax/scrum 101 Finish Timetable Home Page (#50)
Austin-X Mar 8, 2025
5a910a8
Ms/scrum 124 sprint2 retrospective (#59)
thomasyzy7 Mar 8, 2025
3f1c6aa
Release/1.2 - Develop (#61)
thomasyzy7 Mar 8, 2025
8de4414
Ax/scrum 125 Fix Module Import Linting Errors (#63)
Austin-X Mar 9, 2025
a982d8e
Update README.md (#62)
MasahisaSekita Mar 13, 2025
2c6d152
Kl/scrum-132 Improved querying of year level and breadth requirement …
kevin-lann Mar 15, 2025
8479c79
kl/SCRUM-129: Fix restriction and form related bugs (#67)
kevin-lann Mar 16, 2025
3d814b0
Mt/scrum-57-child-133-update-timetable-endpoints-for-favorites (#68)
minhhaitran08 Mar 16, 2025
ea8454e
Mt/scrum 137 check timetable duplicated name (#70)
minhhaitran08 Mar 16, 2025
e71811e
Mt/scrum 58 child 60 sharing timetable backend (#73)
minhhaitran08 Mar 18, 2025
e34ce55
Ty/scrum 52 timetable generation (#74)
thomasyzy7 Mar 20, 2025
8bba298
Hotfix 1.0.3 - Revert "Ty/scrum 52 timetable generation (#74)" (#80)
kevin-lann Mar 20, 2025
c12fbd0
Ty/scrum 52 timetable generation (#81)
thomasyzy7 Mar 20, 2025
ad6c9c3
Kl/scrum 56 email notifications (#78)
kevin-lann Mar 20, 2025
f8adc57
Ms/scrum 127 update sprint 3 documentation (#72)
MasahisaSekita Mar 20, 2025
e93d766
Ax/scrum 122 Timetable Basics Integration (#69)
Austin-X Mar 21, 2025
9c358fc
Ax/scrum 144 Add integration tests (#83)
Austin-X Mar 21, 2025
fbb2a44
Kl/scrum 41 ai timetable generate (#75)
kevin-lann Mar 21, 2025
4bb785f
Kl/scrum 55 timetable generation integration (#85)
kevin-lann Mar 21, 2025
202c807
Mt/scrum 138 child 139 backend testing timetablesController, restrict…
minhhaitran08 Mar 21, 2025
6a3acc6
Merge branch 'main' of https://github.com/UTSC-CSCC01-Software-Engine…
kevin-lann Mar 22, 2025
751da96
Ty/scrum 128 sprint restrospective (#89) to Release (#90)
thomasyzy7 Mar 22, 2025
46bc077
Disabled semester selct
kevin-lann Mar 22, 2025
5ebc3e5
Merge branch 'release/1.3' of https://github.com/UTSC-CSCC01-Software…
kevin-lann Mar 22, 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ The `DATABASE_URL` variable should contain your Supabase project url and the `DA

```
VITE_SERVER_URL="http://localhost:8081"
VITE_PUBLIC_ASSISTANT_BASE_URL=[Insert vite public assistant bas URL]
VITE_ASSISTANT_UI_KEY=[Insert vite assistant UI key]
```

### Running the Application
Expand Down
119 changes: 119 additions & 0 deletions course-matrix/backend/__tests__/analyzeQuery.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { analyzeQuery } from "../src/utils/analyzeQuery";
import { describe, test, expect, jest } from "@jest/globals";
import {
NAMESPACE_KEYWORDS,
ASSISTANT_TERMS,
DEPARTMENT_CODES,
} from "../src/constants/promptKeywords";

// Mock the constants if needed
jest.mock("../src/constants/promptKeywords", () => ({
NAMESPACE_KEYWORDS: {
courses_v3: ["course", "class", "description"],
offerings: ["offering", "schedule", "timetable"],
prerequisites: ["prerequisite", "prereq"],
corequisites: ["corequisite", "coreq"],
departments: ["department", "faculty"],
programs: ["program", "major", "minor"],
},
ASSISTANT_TERMS: ["you", "your", "morpheus", "assistant"],
DEPARTMENT_CODES: ["cs", "math", "eng"],
GENERAL_ACADEMIC_TERMS: ["academic", "study", "education"],
}));

describe("analyzeQuery", () => {
test("should return no search required for assistant-related queries", () => {
const result = analyzeQuery("Can you help me with something?");
expect(result).toEqual({
requiresSearch: false,
relevantNamespaces: [],
});
});

test("should detect course-related keywords and return appropriate namespaces", () => {
const result = analyzeQuery("Tell me about this course");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("courses_v3");
});

test("should detect course codes and include relevant namespaces", () => {
const result = analyzeQuery("What is CSC108 about?");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("courses_v3");
expect(result.relevantNamespaces).toContain("offerings");
expect(result.relevantNamespaces).toContain("prerequisites");
});

test("should detect department codes and include relevant namespaces", () => {
const result = analyzeQuery("What math courses are available?");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("departments");
expect(result.relevantNamespaces).toContain("courses_v3");
});

test("should detect offering-related keywords", () => {
const result = analyzeQuery("What is the schedule for winter semester?");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("offerings");
});

test("should detect prerequisite-related keywords", () => {
const result = analyzeQuery("What are the prerequisites for this class?");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("prerequisites");
});

test("should detect corequisite-related keywords", () => {
const result = analyzeQuery("Are there any corequisites for this course?");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("corequisites");
});

test("should return all namespaces when search is required but no specific namespaces identified", () => {
// Assuming GENERAL_ACADEMIC_TERMS includes 'academic'
const result = analyzeQuery("I need academic information");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toEqual([
"courses_v3",
"offerings",
"prerequisites",
"corequisites",
"departments",
"programs",
]);
});

test("should be case insensitive", () => {
const result = analyzeQuery("TELL ME ABOUT THIS COURSE");
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("courses_v3");
});

test("should detect multiple namespaces in a single query", () => {
const result = analyzeQuery(
"What are the prerequisites and schedule for CSC108?",
);
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("prerequisites");
expect(result.relevantNamespaces).toContain("offerings");
expect(result.relevantNamespaces).toContain("courses_v3");
});

test("should correctly identify course codes with different formats", () => {
const formats = [
"CSC108", // Standard format
"CSC108H", // With suffix
"CSCA08", // Four letters
"MAT224", // Different department
"ECO100Y", // Another format
];

formats.forEach((code) => {
const result = analyzeQuery(`Tell me about ${code}`);
expect(result.requiresSearch).toBe(true);
expect(result.relevantNamespaces).toContain("courses_v3");
expect(result.relevantNamespaces).toContain("offerings");
expect(result.relevantNamespaces).toContain("prerequisites");
});
});
});
81 changes: 81 additions & 0 deletions course-matrix/backend/__tests__/auth.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import request from "supertest";
import { describe, expect, it, test } from "@jest/globals";
import app from "../src/index";

describe("Authentication API", () => {
// The unit tests below are currently commented out because they require a database connection.
// They will be uncommented out once all the necessary mocks are in place.

// describe('POST /auth/login', () => {
// it('should return 200 and a token for valid credentials', async () => {
// const response = await request(app)
// .post('/auth/login')
// .send({ username: 'validUser', password: 'validPassword' });
// expect(response.status).toBe(200);
// expect(response.body).toHaveProperty('token');
// });
// it('should return 401 for invalid credentials', async () => {
// const response = await request(app)
// .post('/auth/login')
// .send({ username: 'invalidUser', password: 'wrongPassword' });
// expect(response.status).toBe(401);
// expect(response.body).toHaveProperty('error', 'Invalid credentials');
// });
// it('should return 400 if username or password is missing', async () => {
// const response = await request(app)
// .post('/auth/login')
// .send({ username: 'validUser' });
// expect(response.status).toBe(400);
// expect(response.body).toHaveProperty('error', 'Username and password are required');
// });
// });
// describe('POST /auth/register', () => {
// it('should return 201 and create a new user for valid input', async () => {
// const response = await request(app)
// .post('/auth/register')
// .send({ username: 'newUser', password: 'newPassword' });
// expect(response.status).toBe(201);
// expect(response.body).toHaveProperty('message', 'User registered successfully');
// });
// it('should return 400 if username is already taken', async () => {
// await request(app)
// .post('/auth/register')
// .send({ username: 'existingUser', password: 'password123' });
// const response = await request(app)
// .post('/auth/register')
// .send({ username: 'existingUser', password: 'password123' });
// expect(response.status).toBe(400);
// expect(response.body).toHaveProperty('error', 'Username is already taken');
// });
// it('should return 400 if username or password is missing', async () => {
// const response = await request(app)
// .post('/auth/register')
// .send({ username: '' });
// expect(response.status).toBe(400);
// expect(response.body).toHaveProperty('error', 'Username and password are required');
// });
// });
// describe('GET /auth/profile', () => {
// it('should return 200 and user profile for valid token', async () => {
// const loginResponse = await request(app)
// .post('/auth/login')
// .send({ username: 'validUser', password: 'validPassword' });
// const token = loginResponse.body.token;
// const response = await request(app)
// .get('/auth/profile')
// .set('Authorization', `Bearer ${token}`);
// expect(response.status).toBe(200);
// expect(response.body).toHaveProperty('username', 'validUser');
// });
// it('should return 401 if token is missing or invalid', async () => {
// const response = await request(app)
// .get('/auth/profile')
// .set('Authorization', 'Bearer invalidToken');
// expect(response.status).toBe(401);
// expect(response.body).toHaveProperty('error', 'Unauthorized');
// });
// });
it("template test", () => {
expect(2 + 3).toEqual(5);
});
});
118 changes: 118 additions & 0 deletions course-matrix/backend/__tests__/canInsert.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { describe, expect, it, test } from "@jest/globals";

import { createOffering, canInsert } from "../src/utils/generatorHelpers";
import { Offering } from "../src/types/generatorTypes";

describe("canInsert function", () => {
const offering1: Offering = createOffering({
id: 1,
course_id: 101,
day: "MO",
start: "09:00:00",
end: "10:00:00",
});
const offering2: Offering = createOffering({
id: 2,
course_id: 102,
day: "MO",
start: "10:00:00",
end: "11:00:00",
});
const offering3: Offering = createOffering({
id: 3,
course_id: 103,
day: "MO",
start: "11:00:00",
end: "12:00:00",
});

it("should return true if there is no overlap with existing offerings", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "MO",
start: "12:00:00",
end: "13:00:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(true); // No overlap, should return true
});

it("should return false if there is an overlap with an existing offering", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "MO",
start: "09:30:00",
end: "10:30:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(false); // There is an overlap with offering1, should return false
});

it("should return true if the new offering starts after the last one ends", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "MO",
start: "13:00:00",
end: "14:00:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(true); // No overlap, should return true
});

it("should return true if the new offering ends before the first one starts", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "MO",
start: "07:00:00",
end: "08:00:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(true); // No overlap, should return true
});

it("should return false if the new offering is completely inside an existing one", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "MO",
start: "09:30:00",
end: "09:45:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(false); // Overlaps with offering1, should return false
});

it("should return true if the day is different (no overlap)", async () => {
const toInsert: Offering = createOffering({
id: 4,
course_id: 104,
day: "TU",
start: "09:00:00",
end: "10:00:00",
});
const curList: Offering[] = [offering1, offering2, offering3];

const result = await canInsert(toInsert, curList);

expect(result).toBe(true); // Different day, no overlap
});
});
Loading