Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
587 commits
Select commit Hold shift + click to select a range
e5471e2
[#73] add apis to get filters and sorts for pagination
glemenneo Sep 28, 2024
6090029
[#73] fix: mismatches apostrophes
glemenneo Sep 28, 2024
fdaa67b
refactor: create custom hooks folder
Daviancold Sep 28, 2024
7c095fd
[#73] feat: add get categories api
glemenneo Sep 28, 2024
22c00b6
[#73] feat: add limit to pagination response
glemenneo Sep 28, 2024
b518b48
chore: install react-select
yunruu Sep 28, 2024
6bb6468
fix: make dialog close on successful pw reset
shishirbychapur Sep 28, 2024
ab14325
feat: add close icon
yunruu Sep 28, 2024
f46dc8a
feat: create custom modal
yunruu Sep 28, 2024
62e927d
feat: increase select popup z-index
yunruu Sep 28, 2024
5eb7621
refactor: remove sessions route code
yunruu Sep 28, 2024
83bfe3b
feat: create custom multiselect component
yunruu Sep 28, 2024
74d9697
feat: update select styles
yunruu Sep 28, 2024
9e77c91
feat: add custom form fields types
yunruu Sep 28, 2024
98b42ed
refactor: move questions datatable columns away from index file
yunruu Sep 28, 2024
3c70062
feat: add reusable custom form
yunruu Sep 28, 2024
95d843c
refactor mock data away from index file and add create new question ui
yunruu Sep 28, 2024
6b90d6f
fix: import
yunruu Sep 28, 2024
d146979
fix: temporary fix to prevent react build complaint
yunruu Sep 28, 2024
43053e2
refactor: move custom data structure properties to props file
yunruu Sep 28, 2024
f9f6a64
Merge branch 'main' into feat-question
yunruu Sep 28, 2024
302a79e
fix: resolve dialog bug
shishirbychapur Sep 28, 2024
a89b01e
fix: make submit reset
shishirbychapur Sep 28, 2024
fadf7ac
feat: add icons
yunruu Sep 28, 2024
8152a6b
feat: add option in datatable to display actions panel
yunruu Sep 28, 2024
86ea84f
fix: improve ui
shishirbychapur Sep 28, 2024
130f2c3
fix: reset all input fields
shishirbychapur Sep 28, 2024
7ac6fbe
feat: set up data table row actions ui
yunruu Sep 28, 2024
852f725
fix: make otp centralised
shishirbychapur Sep 28, 2024
75e2a30
feat: set up edit button to open edit modal
yunruu Sep 28, 2024
4125481
fix: change className for div
shishirbychapur Sep 28, 2024
ae33950
nitpick: fix one liner styling
Daviancold Sep 28, 2024
daaba81
Merge pull request #72 from CS3219-AY2425S1/71-fe-add-form-validation…
shishirbychapur Sep 28, 2024
800ad5d
feat: add width property to datatable and add title column
yunruu Sep 28, 2024
1862d45
fix: format according to prettier
yunruu Sep 28, 2024
06c9f7b
Merge pull request #63 from CS3219-AY2425S1/feat-question
yunruu Sep 28, 2024
a64b71b
[#73] fix: resolve failing tests
glemenneo Sep 29, 2024
b897dcd
feat: add ui for sessions route
yunruu Sep 29, 2024
114cf1c
feat: add more session datatable columns and column property
yunruu Sep 29, 2024
b0cab26
feat: add sorting to time column
yunruu Sep 29, 2024
a584a6c
Merge pull request #74 from CS3219-AY2425S1/73-be-add-additional-apis…
glemenneo Sep 29, 2024
1131b25
Merge pull request #76 from CS3219-AY2425S1/20-sessions-page
yunruu Sep 29, 2024
4202e33
feat: (incomplete) setup axios middleware and test create user
Daviancold Sep 28, 2024
dc60d18
feat: add create user with incomplete login
Daviancold Sep 28, 2024
89df269
feat: add code for axios middleware
Daviancold Sep 29, 2024
0e9087c
incomplete: add logic for auth routing
Daviancold Sep 29, 2024
f2496fc
add: new method to verify token
Daviancold Sep 29, 2024
78b9bdc
feat: make logo route to home page
shishirbychapur Sep 29, 2024
4d395de
fix: cherry pick commits
shishirbychapur Sep 29, 2024
07dd561
feat: add /auth/verify route
shishirbychapur Sep 29, 2024
2602007
feat: integrate new routes with ui
shishirbychapur Sep 29, 2024
fd95faa
fix: cherry pick commits
shishirbychapur Sep 29, 2024
48f16cd
feat: setup password update mechanism w/o authentication
shishirbychapur Sep 29, 2024
9691d3d
fix: update comment
shishirbychapur Sep 29, 2024
8a911c5
feat: add Protected Routing with session state
Daviancold Sep 29, 2024
7200ffe
feat: integrate all user service api except delete
Daviancold Sep 29, 2024
b56b507
feat: complete user-service api integration
Daviancold Sep 29, 2024
3f444e8
fix: CI issues
Daviancold Sep 29, 2024
a8436aa
feat: add custom confirmation dialog component
yunruu Sep 29, 2024
6712997
feat: prepare ui for api data fetching
yunruu Sep 29, 2024
d315cc4
feat: add method to refresh datatable
yunruu Sep 29, 2024
547dd82
feat: api handling for question service
Daviancold Sep 29, 2024
388541e
feat: complete question service api integration
Daviancold Sep 29, 2024
ebd9424
fix: bug fix for milestone 2
Daviancold Sep 30, 2024
b8fd2a4
fix: enable role based access control
shishirbychapur Oct 1, 2024
66bf2e6
fix: allow questions to be edited
shishirbychapur Oct 1, 2024
4a41547
fix: add badge component to question table
shishirbychapur Oct 1, 2024
26b8e27
fix: render button only for admins
shishirbychapur Oct 1, 2024
cd35fb9
Merge pull request #81 from CS3219-AY2425S1/shishir/fix-question-serv…
shishirbychapur Oct 1, 2024
dbd2e32
feat: setup next auth
shishirbychapur Oct 1, 2024
b96fa60
feat: add protected routes
shishirbychapur Oct 1, 2024
f0a704d
fix: solve auth redirect bug
shishirbychapur Oct 2, 2024
1d476a7
fix: ensure /auth page cant be accessed when logged in
shishirbychapur Oct 2, 2024
b39448e
fix: add session expiry
shishirbychapur Oct 2, 2024
5d8c0d7
fix: render edit/delete icon only for admins
shishirbychapur Oct 2, 2024
1b0f0d3
fix: render login page instead of signup page
shishirbychapur Oct 2, 2024
bcc4ad4
fix: add loading page and fix question page bugs
shishirbychapur Oct 2, 2024
a0eadfc
fix: clean up axios middleware code
shishirbychapur Oct 2, 2024
7c165b1
fix: resolve ci
shishirbychapur Oct 4, 2024
ae45630
Merge pull request #82 from CS3219-AY2425S1/shishir/fix-fe-authentica…
shishirbychapur Oct 5, 2024
21208d7
fix: solve profile bug
shishirbychapur Oct 6, 2024
c9c7c8c
fix: docker compose network
Daviancold Oct 6, 2024
e961a75
Set up matching service
Oct 8, 2024
745cf90
Save file
Oct 8, 2024
e69831c
Resolve comments
Oct 8, 2024
fa5e1b6
fix tests
Oct 8, 2024
d2e3b90
Add mock file
Oct 8, 2024
0a0e38e
Update port
Oct 8, 2024
d409a28
Import configMock
Oct 8, 2024
538ccb4
fix: resolve ci
shishirbychapur Oct 8, 2024
0402314
fix: solve import order
shishirbychapur Oct 8, 2024
3624265
fix: revert dev dependency
shishirbychapur Oct 8, 2024
d4b20dc
Merge pull request #98 from CS3219-AY2425S1/lynn/set-up-matching-service
shishirbychapur Oct 8, 2024
c5575ad
fix: resolve spam bug
shishirbychapur Oct 8, 2024
28ca145
feat: add UserQueueDto for entry queue
Daviancold Oct 10, 2024
f168945
fix: rename websocketUrl to websocketId
Daviancold Oct 10, 2024
df8ca03
add: user queue dto for queue message
Daviancold Oct 10, 2024
91f454c
fix: rename IUserQueue to IUserQueueMessage for clarity
Daviancold Oct 10, 2024
64b76dc
feat: setup post request
shishirbychapur Oct 11, 2024
a945233
fix: rename difficulty to complexity
shishirbychapur Oct 11, 2024
124197f
refactor: change difficulty to complexity
shishirbychapur Oct 11, 2024
3fb9e6f
refactor: rename difficulty to complexity
shishirbychapur Oct 11, 2024
b49d20b
Merge pull request #101 from CS3219-AY2425S1/shishir/post-api
lynnlow175 Oct 11, 2024
c10ddd3
Add matching model
Oct 11, 2024
6e99e1f
feat: add rabbitMQ class with entry publisher and consumer
Daviancold Oct 11, 2024
64c4a48
Change some fields
Oct 11, 2024
4bd88b6
feat: setup post request
shishirbychapur Oct 11, 2024
c7abd49
fix: rename difficulty to complexity
shishirbychapur Oct 11, 2024
5e24494
refactor: change difficulty to complexity
shishirbychapur Oct 11, 2024
5420731
refactor: rename difficulty to complexity
shishirbychapur Oct 11, 2024
444f0e4
incomplete: add enqueue to post call (untested)
Daviancold Oct 11, 2024
cceadba
Merge branch 'main' into 92-entry-queue
Daviancold Oct 12, 2024
c002562
fix: comments from glemen
Daviancold Oct 12, 2024
d06a6e9
fix: change console.log to use logger util
Daviancold Oct 12, 2024
0f1d025
Merge pull request #103 from CS3219-AY2425S1/92-entry-queue
Daviancold Oct 12, 2024
43fc8c0
Add indexes
Oct 13, 2024
29bae12
[#86] feat: add props and logic to handle conditional rendering of bo…
glemenneo Oct 13, 2024
2db2bb2
Merge pull request #102 from CS3219-AY2425S1/lynn/create-matching-schema
shishirbychapur Oct 14, 2024
c3707af
[#73] feat: remove margin from loading to improve reusability
glemenneo Oct 14, 2024
26a1958
[#73] feat: add matchmaking modal
glemenneo Oct 14, 2024
b2c81e2
[#73] fix: simplify time state logic
glemenneo Oct 14, 2024
325e106
[#73] fix: modal reopens after matchmaking is cancelled
glemenneo Oct 14, 2024
7b0d7b5
[#73] fix: centre contents of modal
glemenneo Oct 14, 2024
9231f79
incomplete: add skeleton for waiting queue
Daviancold Oct 12, 2024
71dfe4e
chore: add comment framework
Daviancold Oct 12, 2024
c7bd22c
feat: add logic for matching
Daviancold Oct 13, 2024
c58448f
fix: change header exchange to use direct exchange instead
Daviancold Oct 13, 2024
3b00df0
refactor: tweak logger
Daviancold Oct 13, 2024
8b0aa0c
fix: issue with unreachable message once queried
Daviancold Oct 13, 2024
0fae019
refactor: main matching logic
Daviancold Oct 13, 2024
8d8146b
refactor: add try catch for all async logic
Daviancold Oct 13, 2024
5c7245f
fix: remove proficiency level and add delete queue check
Daviancold Oct 14, 2024
4ec184a
add: delete after match found and queue empty with clearer logging
Daviancold Oct 14, 2024
78d8a92
[#73] fix: refresh match found state
glemenneo Oct 14, 2024
df183a9
[#73] feat: add failed to find match toaster
glemenneo Oct 14, 2024
408dbac
[#73] feat: add failed matchmaking modal and redirect for successful …
glemenneo Oct 14, 2024
277a2f5
[#73] feat: add redirect for successful matchmaking
glemenneo Oct 14, 2024
0fee1d8
[#73] fix: center loading screen
glemenneo Oct 14, 2024
30a3342
[#86] feat: change button colours and add ws mock implementation
glemenneo Oct 15, 2024
b543967
Add schema for matched users
Oct 15, 2024
41be9cd
Merge pull request #110 from CS3219-AY2425S1/lynn/create-matched-object
lynnlow175 Oct 15, 2024
a81454e
Add query function
Oct 15, 2024
037527e
Create type to handle complexity logic
Oct 15, 2024
d926f36
Merge pull request #112 from CS3219-AY2425S1/lynn/create-question-query
lynnlow175 Oct 16, 2024
15c305d
Merge pull request #108 from CS3219-AY2425S1/86-fe-create-ui-for-matc…
shishirbychapur Oct 16, 2024
bf98387
feat: support cancellation of matchmaking
shishirbychapur Oct 16, 2024
2f59bde
Set up frontend ws
Oct 16, 2024
3335726
Add ws-types
Oct 17, 2024
e9328ff
Merge pull request #115 from CS3219-AY2425S1/shishir/cancel
lynnlow175 Oct 17, 2024
a660737
Fix ws-types
Oct 17, 2024
1359853
Merge pull request #116 from CS3219-AY2425S1/lynn/set-up-FE-WS
shishirbychapur Oct 17, 2024
0a780b0
Set up be ws
Oct 17, 2024
ab919aa
feat: add rabbitmq and matching service to docker compose
Daviancold Oct 16, 2024
3b57455
feat: increase interval to reduce service health message spam
Daviancold Oct 16, 2024
bd71e68
feat: link ws
shishirbychapur Oct 18, 2024
e84ab77
fix: cleanup code
shishirbychapur Oct 18, 2024
84774b4
[#118] feat: remove mongo log verbosity and healthchecks
glemenneo Oct 16, 2024
a7c6c2d
[#118] feat: add nginx config and update compose
glemenneo Oct 16, 2024
0f1fe56
[#118] feat: add additional config for proxy pass
glemenneo Oct 16, 2024
45d7c12
[#118] feat: add rate limiting
glemenneo Oct 17, 2024
028dfc2
[#118] feat: change nginx to return json responses for common errors
glemenneo Oct 17, 2024
aa8b472
[#118] refactor: move proxy headers to server context
glemenneo Oct 17, 2024
4d4c097
[#118] feat: add ssl termination
glemenneo Oct 17, 2024
5e0cf8d
[#118] feat: add matching service proxy pass
glemenneo Oct 17, 2024
c59b2d9
fix: resolve ci
shishirbychapur Oct 18, 2024
c5fc205
fix: resolve ci
Oct 18, 2024
a4dbb48
fix: resolve comments
Oct 18, 2024
078422d
fix: add import in ws.servce.ts
shishirbychapur Oct 18, 2024
61be554
fix: resolve pr comments
shishirbychapur Oct 18, 2024
9d67b49
feat: add dead letter exchange and queue
yunruu Oct 18, 2024
5079fff
feat: create and listen to dead letter queue
yunruu Oct 18, 2024
32ff69d
Add query function
Oct 15, 2024
7813436
Create type to handle complexity logic
Oct 15, 2024
83769d4
[#86] feat: add props and logic to handle conditional rendering of bo…
glemenneo Oct 13, 2024
9c1fa77
[#73] feat: remove margin from loading to improve reusability
glemenneo Oct 14, 2024
a4046da
[#73] feat: add matchmaking modal
glemenneo Oct 14, 2024
2875a07
[#73] fix: simplify time state logic
glemenneo Oct 14, 2024
4eed243
[#73] fix: modal reopens after matchmaking is cancelled
glemenneo Oct 14, 2024
cfa3453
[#73] fix: centre contents of modal
glemenneo Oct 14, 2024
d92eb50
[#73] fix: refresh match found state
glemenneo Oct 14, 2024
35b451d
[#73] feat: add failed to find match toaster
glemenneo Oct 14, 2024
c150b5e
[#73] feat: add failed matchmaking modal and redirect for successful …
glemenneo Oct 14, 2024
045c843
[#73] feat: add redirect for successful matchmaking
glemenneo Oct 14, 2024
9c0fe8a
[#73] fix: center loading screen
glemenneo Oct 14, 2024
a7b323e
[#86] feat: change button colours and add ws mock implementation
glemenneo Oct 15, 2024
54e54f5
feat: support cancellation of matchmaking
shishirbychapur Oct 16, 2024
b2efb96
Set up frontend ws
Oct 16, 2024
f14dd72
Add ws-types
Oct 17, 2024
68dd3fb
Fix ws-types
Oct 17, 2024
15d458b
feat: add rabbitmq and matching service to docker compose
Daviancold Oct 16, 2024
04082c6
feat: increase interval to reduce service health message spam
Daviancold Oct 16, 2024
16e4a0f
[#118] feat: remove mongo log verbosity and healthchecks
glemenneo Oct 16, 2024
73cafff
[#118] feat: add nginx config and update compose
glemenneo Oct 16, 2024
3d3ba6a
[#118] feat: add additional config for proxy pass
glemenneo Oct 16, 2024
6736906
[#118] feat: add rate limiting
glemenneo Oct 17, 2024
ccd141a
[#118] feat: change nginx to return json responses for common errors
glemenneo Oct 17, 2024
f6c5f7c
[#118] refactor: move proxy headers to server context
glemenneo Oct 17, 2024
96cc573
[#118] feat: add ssl termination
glemenneo Oct 17, 2024
6bd5acf
[#118] feat: add matching service proxy pass
glemenneo Oct 17, 2024
23846d0
feat: add dead letter exchange and queue
yunruu Oct 18, 2024
e3ad916
Merge branch 'main' into 105-be-dlq
yunruu Oct 18, 2024
f54743a
Merge pull request #120 from CS3219-AY2425S1/lynn/set-up-be-ws
shishirbychapur Oct 19, 2024
14e4cce
feat: add questions type to packages
yunruu Oct 19, 2024
858cee2
fix: add logical ordering to complexity and categories
yunruu Oct 19, 2024
de5ee48
feat: create interface for match info
yunruu Oct 19, 2024
d271522
feat: add question service url requirement in env
yunruu Oct 19, 2024
26ab6c6
feat: add question service to retrieve random question id
yunruu Oct 19, 2024
ba49821
fix: set timestamp as current time if field in req is empty
yunruu Oct 19, 2024
84362d5
feat: create match in match repo
yunruu Oct 19, 2024
8c3eec7
feat: create and save match data into db on match success
yunruu Oct 19, 2024
cc5f1dc
Merge branch 'main' into 109-update-db-on-match
yunruu Oct 19, 2024
f3016a1
refactor: move id extraction out
yunruu Oct 19, 2024
c580b7d
chore
yunruu Oct 19, 2024
f2c380a
feat: set and retrieve user id to check dead letter identity
yunruu Oct 19, 2024
55019ba
feat: remove durability of DL exchange and queue
yunruu Oct 19, 2024
479ee75
feat: increase TTL of dead letter to 3 minutes for buffer
yunruu Oct 19, 2024
ddc57a9
feat: create and save match data into db on match success
yunruu Oct 19, 2024
5b725a4
fix: rebase issue
yunruu Oct 19, 2024
9bb333a
fix: remove duplicate call
yunruu Oct 19, 2024
bebec2c
refactor: move matchedUser assignment before remove queue call
yunruu Oct 19, 2024
3db0ec8
refactor: create matchdto with more fields
yunruu Oct 19, 2024
a0ec897
feat: check if user already in match on match create
yunruu Oct 19, 2024
3244a69
Merge pull request #123 from CS3219-AY2425S1/105-be-dlq
yunruu Oct 19, 2024
98641b4
refactor: follow logical order of code
yunruu Oct 19, 2024
ba22b2b
Merge pull request #124 from CS3219-AY2425S1/109-update-db-on-match
yunruu Oct 19, 2024
9d85b94
feat: use websocket id as key to close ws connection on DLM
yunruu Oct 19, 2024
a8ac94d
feat: close connection on WS timeout
yunruu Oct 19, 2024
f59d3fd
refactor: maintain one source of dlx keys
yunruu Oct 19, 2024
61666df
Integrate successful matching with ws
Oct 20, 2024
4477e2f
fix cicd
Oct 20, 2024
9c4902f
Handle duplicate user
Oct 20, 2024
8921d60
fix: resolve bugs
shishirbychapur Oct 20, 2024
5ea022c
fix: solve cancel matchmaking ws
shishirbychapur Oct 20, 2024
c9c51a9
fix: improve code quality
shishirbychapur Oct 20, 2024
a9f93cf
Merge pull request #129 from CS3219-AY2425S1/lynn/126-successful-match
shishirbychapur Oct 20, 2024
4bb4531
feat: add auto timeout on server WS connection
yunruu Oct 20, 2024
e730587
Check user already finding match
Oct 20, 2024
14b3e6d
Update
Oct 20, 2024
5e475fc
feat: send clear WS close message to client
yunruu Oct 20, 2024
2d6f735
feat: remove ttl for expired messages
yunruu Oct 20, 2024
3e0e5ad
refactor: send failure message to client on matchmaking timeout
yunruu Oct 20, 2024
ccc5bbf
refactor: wrap closure message as type
yunruu Oct 20, 2024
d40ebb4
Merge pull request #127 from CS3219-AY2425S1/125-be-integrate-dlq-ws
shishirbychapur Oct 20, 2024
fc75f69
Add clearing of set
Oct 20, 2024
9e6a8fe
Add clear upon dlq
Oct 20, 2024
c1eaf62
Merge branch 'main' of https://github.com/CS3219-AY2425S1/cs3219-ay24…
shishirbychapur Oct 20, 2024
b17bc3b
fix: resolve ci
shishirbychapur Oct 20, 2024
03aa6cf
fix: solve bug in matchmaking
shishirbychapur Oct 20, 2024
c782953
fix: comment out routing
shishirbychapur Oct 20, 2024
797289c
feat: refine matchmaking
shishirbychapur Oct 20, 2024
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
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
**/node_modules
**/.next
**/dist
**/coverage
.git
.gitignore
.vscode
.github
.husky
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: ['@repo/eslint-config/eslint-base.js'],
}
Empty file added .github/.keep
Empty file.
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI

on:
push:
branches: ['main']
pull_request:
types: [opened, synchronize]

jobs:
build:
name: Build and Test
timeout-minutes: 15
runs-on: ubuntu-latest
# To use Remote Caching, uncomment the next lines and follow the steps below.
# env:
# TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
# TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# TURBO_REMOTE_ONLY: true

steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Build
run: npm run build

- name: Test
run: npm run test
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.git
.vscode

/node_modules
**/node_modules

**/.env
**/.env.*

**/dist
**/coverage

**/*.log

**/.turbo

**/*.tsbuildinfo

/nginx/ssl
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npm run lint-staged
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore artifacts:
**/coverage/*
**/dist/*
**/public/*
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true,
"printWidth": 120
}
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @shishirbychapur @glemenneo @Daviancold @lynnlow175 @yunruu
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
![build_test_workflow](https://github.com/CS3219-AY2425S1/cs3219-ay2425s1-project-g31/actions/workflows/ci.yml/badge.svg)

# CS3219 Project (PeerPrep) - AY2425S1
## Group: Gxx

### Note:
- You can choose to develop individual microservices within separate folders within this repository **OR** use individual repositories (all public) for each microservice.
- In the latter scenario, you should enable sub-modules on this GitHub classroom repository to manage the development/deployment **AND** add your mentor to the individual repositories as a collaborator.
- The teaching team should be given access to the repositories as we may require viewing the history of the repository in case of any disputes or disagreements.
## Group: G31

### Note:

- You can choose to develop individual microservices within separate folders within this repository **OR** use individual repositories (all public) for each microservice.
- In the latter scenario, you should enable sub-modules on this GitHub classroom repository to manage the development/deployment **AND** add your mentor to the individual repositories as a collaborator.
- The teaching team should be given access to the repositories as we may require viewing the history of the repository in case of any disputes or disagreements.

[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/bzPrOe11)
9 changes: 9 additions & 0 deletions backend/matching-service/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: ['@repo/eslint-config/eslint-service.js'],
parserOptions: {
root: true,
tsconfigRootDir: __dirname,
sourceType: 'module',
},
}
4 changes: 4 additions & 0 deletions backend/matching-service/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore artifacts:
**/coverage/*
**/dist/*
**/public/*
39 changes: 39 additions & 0 deletions backend/matching-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ---- Node 22 on Alpine Linux ----
FROM node:22-alpine AS base

FROM base AS builder
RUN apk update && apk add --no-cache libc6-compat

WORKDIR /app

COPY . .

# Generate a partial monorepo with a pruned lockfile for the app
RUN npx turbo prune --scope=matching-service --docker

FROM base AS installer
RUN apk update && apk add --no-cache libc6-compat
WORKDIR /app

#############################################
# ---- Dependencies ----
COPY --from=builder /app/out/json/ .
RUN npm install

#############################################
# ---- App ----
COPY --from=builder /app/out/full/ .
RUN npx turbo build --filter=matching-service

#############################################
# ---- Start ----
FROM base AS runner
WORKDIR /app

# Don't run production as root
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 matching-service
USER matching-service

COPY --from=installer /app .

CMD ["node", "backend/matching-service/dist/server"]
19 changes: 19 additions & 0 deletions backend/matching-service/__mocks__/config.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { generateKeyPairSync } from 'crypto'

// Generate RSA key pair for testing
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
})

export default {
NODE_ENV: 'test',
PORT: '8000',
ACCESS_TOKEN_PUBLIC_KEY: Buffer.from(publicKey).toString('base64'),
ACCESS_TOKEN_PRIVATE_KEY: Buffer.from(privateKey).toString('base64'),
RMQ_USER: 'test',
RMQ_PASSWORD: 'test',
RMQ_HOST: 'test',
DB_URL: 'test',
}
19 changes: 19 additions & 0 deletions backend/matching-service/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
// [...]
extensionsToTreatAsEsm: ['.ts'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
// '^.+\\.[tj]sx?$' to process ts,js,tsx,jsx with `ts-jest`
// '^.+\\.m?[tj]sx?$' to process ts,js,tsx,jsx,mts,mjs,mtsx,mjsx with `ts-jest`
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
},
],
},
collectCoverage: true,
}
58 changes: 58 additions & 0 deletions backend/matching-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "matching-service",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "tsc",
"test": "jest --passWithNoTests",
"lint": "eslint . --fix --no-error-on-unmatched-pattern && prettier --write --ignore-unknown .",
"start": "npm run build && node dist/server.js",
"dev": "nodemon src/server.ts",
"format": "prettier --write \"./**/*.{js,jsx,mjs,cjs,ts,tsx,json}\""
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"amqplib": "^0.10.4",
"axios": "^1.7.7",
"class-validator": "^0.14.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"express-async-errors": "^3.1.1",
"helmet": "^7.1.0",
"mongoose": "^8.6.3",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"winston": "^3.14.2",
"ws": "^8.18.0"
},
"devDependencies": {
"@repo/eslint-config": "*",
"@repo/request-types": "*",
"@repo/typescript-config": "*",
"@repo/user-types": "*",
"@repo/question-types": "*",
"@testcontainers/mongodb": "^10.13.1",
"@types/amqplib": "^0.10.5",
"@types/cors": "^2.8.17",
"@types/dotenv": "^6.1.1",
"@types/express": "^4.17.21",
"@types/helmet": "^0.0.48",
"@types/jest": "^29.5.13",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^22.5.5",
"@types/passport": "^1.0.16",
"@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.2",
"globals": "^15.9.0",
"jest": "^29.7.0",
"jsonwebtoken": "^9.0.2",
"nodemon": "^3.1.7",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
13 changes: 13 additions & 0 deletions backend/matching-service/src/common/config.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ValidationError } from 'class-validator'
import { Config } from '../types/Config'
import logger from './logger.util'

const config: Config = Config.fromEnv(process.env)
config.validateOrReject().catch((errors: ValidationError[]) => {
logger.error(
`[Config] Invalid or missing configuration: ${errors.map((error: ValidationError) => error.property).join(', ')}`
)
process.exit(1)
})

export default config
16 changes: 16 additions & 0 deletions backend/matching-service/src/common/logger.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Winston from 'winston'

export default Winston.createLogger({
level: 'info',
format: Winston.format.combine(
Winston.format.printf(({ level, message }) => {
return `[${level}]: ${message}`
})
),
defaultMeta: { service: 'matching-service' },
transports: [
new Winston.transports.Console(),
new Winston.transports.File({ filename: 'error.log', level: 'error' }),
new Winston.transports.File({ filename: 'combined.log' }),
],
})
16 changes: 16 additions & 0 deletions backend/matching-service/src/common/mongodb.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import config from './config.util'
import { connect } from 'mongoose'
import logger from './logger.util'

export default async (connectionString: string): Promise<void> => {
await connect(connectionString, {
autoCreate: config.NODE_ENV !== 'production',
autoIndex: config.NODE_ENV !== 'production',
})
.then(() => {
logger.info(`[Init] Connected to database`)
})
.catch((error: Error) => {
logger.error(`[Init] Failed to connect to database: ${error.message}`)
})
}
12 changes: 12 additions & 0 deletions backend/matching-service/src/common/rabbitmq.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import mqConnection from '../services/rabbitmq.service'
import logger from './logger.util'

export default async () => {
await mqConnection.connect()
await mqConnection.entryQueueConsumer().then(() => {
logger.info(`[Entry-Queue] Listening to Entry Queue...`)
})
await mqConnection.listenToDeadLetterQueue().then(() => {
logger.info(`[DeadLetter-Queue] Listening to DeadLetter Queue...`)
})
}
64 changes: 64 additions & 0 deletions backend/matching-service/src/controllers/matching.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ITypedBodyRequest } from '@repo/request-types'
import { Response } from 'express'
import { UserQueueRequest, UserQueueRequestDto } from '../types/UserQueueRequestDto'
import mqConnection from '../services/rabbitmq.service'
import { randomUUID } from 'crypto'
import { WebSocketMessageType } from '@repo/ws-types'
import wsConnection from '../services/ws.service'
import { IMatch } from '../types/IMatch'
import { MatchDto } from '../types/MatchDto'
import { createMatch, isUserInMatch } from '../models/matching.repository'

export async function generateWS(request: ITypedBodyRequest<void>, response: Response): Promise<void> {
const userHasMatch = await isUserInMatch(request.user.id)
if (userHasMatch) {
response.status(403).send('USER_ALREADY_IN_MATCH')
return
}

if (mqConnection.userCurrentlyConnected(request.user.id)) {
response.status(409).send('USER_ALREADY_IN_QUEUE')
return
}
mqConnection.addUserConnected(request.user.id)

const websocketID = randomUUID()
response.status(200).send({ websocketID: websocketID })
}

export async function addUserToMatchmaking(data: UserQueueRequest): Promise<void> {
const userHasMatch = await isUserInMatch(data.userId)
if (userHasMatch) {
wsConnection.sendMessageToUser(data.websocketId, JSON.stringify({ type: WebSocketMessageType.DUPLICATE }))
return
}
const createDto = UserQueueRequestDto.fromJSON(data)
const errors = await createDto.validate()
if (errors.length) {
return
}
await mqConnection.sendToEntryQueue(createDto)
}

export async function removeUserFromMatchingQueue(websocketId: string, userId: string): Promise<void> {
await mqConnection.cancelUser(websocketId, userId)
wsConnection.sendMessageToUser(websocketId, JSON.stringify({ type: WebSocketMessageType.CANCEL }))
}

export async function handleCreateMatch(data: IMatch, ws1: string, ws2: string): Promise<IMatch> {
const isAnyUserInMatch = (await isUserInMatch(data.user1Id)) || (await isUserInMatch(data.user2Id))
if (isAnyUserInMatch) {
wsConnection.sendMessageToUser(ws1, JSON.stringify({ type: WebSocketMessageType.DUPLICATE }))
wsConnection.sendMessageToUser(ws2, JSON.stringify({ type: WebSocketMessageType.DUPLICATE }))
}
data.questionId = randomUUID() // TODO: replace with actual question ID
const createDto = MatchDto.fromJSON(data)
const errors = await createDto.validate()
if (errors.length) {
throw new Error('Invalid match data')
}
const dto = await createMatch(createDto)
wsConnection.sendMessageToUser(ws1, JSON.stringify({ type: WebSocketMessageType.SUCCESS, matchId: dto.id }))
wsConnection.sendMessageToUser(ws2, JSON.stringify({ type: WebSocketMessageType.SUCCESS, matchId: dto.id }))
return dto
}
Loading