Skip to content

Commit

Permalink
Merge branch 'master' of github.com:CS3219-AY2324S1/ay2324s1-course-a…
Browse files Browse the repository at this point in the history
…ssessment-g53
  • Loading branch information
zzthian committed Nov 4, 2023
2 parents 7626296 + 0016269 commit 7040ccf
Show file tree
Hide file tree
Showing 27 changed files with 2,738 additions and 200 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/question-backend.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: question-backend CI

on:
push:
branches: ['master']
pull_request:
branches: ['master']

defaults:
run:
working-directory: backend/question-backend

jobs:
question-backend_test_and_coverage:
runs-on: ubuntu-latest

steps:
- name: Checkout Backend
uses: actions/checkout@v3

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '20.x'
- name: Install Dependencies
run: npm install mocha chai sinon --save-dev
npm install --save-dev c8
working-directory: backend/question-backend

- name: Run Tests with Coverage
run: npm run test-with-coverage
5 changes: 2 additions & 3 deletions .github/workflows/user_profile_backend.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defaults:
working-directory: backend/user_profile_backend

jobs:
backend:
user_profile_backend_test_and_coverage:
runs-on: ubuntu-latest

steps:
Expand All @@ -31,7 +31,6 @@ jobs:
run: npm install mocha chai sinon --save-dev
npm install --save-dev nyc
working-directory: backend/user_profile_backend

- name: Run Tests with Coverage
run: npm run test-with-coverage

148 changes: 107 additions & 41 deletions backend/collab-backend/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const express = require("express")
const cors = require("cors")
const mongoose = require("mongoose")
const dotenv = require("dotenv")
const Document = require("./Document")
const { Mutex } = require('async-mutex')

const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const Document = require("./Document");
const roomSchema = require("./roomSchema");
const { Mutex } = require("async-mutex");
const axios = require("axios");

const collabRouter = require('./routes/collabRouter')
dotenv.config({
Expand All @@ -12,6 +15,8 @@ dotenv.config({
const DEFAULT_DOCUMENT_DATA = ""
const PORT = process.env.PORT ? process.env.PORT : 9000
const FRONTEND_HOST = process.env.FRONTEND_HOST ? process.env.FRONTEND_HOST : "http://localhost:3000"
const QUESTION_HOST = process.env.QUESTION_HOST ? process.env.QUESTION_HOST : "http://localhost:8000/api/questions";


mongoose.connect(process.env.MONGODB_URI)

Expand Down Expand Up @@ -41,33 +46,92 @@ io.on("connection", socket => {
socket.join(documentID)
socket.emit("load-document", document.data)

// Proprogate changes from users to other users in the same channel
socket.on("send-changes", delta => {
socket.broadcast.to(documentID).emit("recieve-changes", delta)
})

// Save document into MongoDB
socket.on("save-document", async data => {
await Document.findByIdAndUpdate(documentID, {data})
findOrCreateDocument(documentID)
})
})
//socket for the video calling
socket.on('join-room', (roomId, userId) => {
socket.join(roomId)
// console.log("user has joined the room")
socket.on("video-ready", () => {
// console.log("server sees that user's video is ready")
socket.to(roomId).emit('user-connected', userId)
})


socket.on('disconnect', () => {
socket.to(roomId).emit('user-disconnected', userId)
})
})
// Proprogate changes from users to other users in the same channel
socket.on("send-changes", (delta) => {
socket.broadcast.to(documentID).emit("recieve-changes", delta);
});

// Save document into MongoDB
socket.on("save-document", async (data) => {
await Document.findByIdAndUpdate(documentID, { data });
findOrCreateDocument(documentID);
});
});
//socket for the video calling
socket.on("join-room", (roomId, userId) => {
socket.join(roomId);
// console.log("user has joined the room")
socket.on("video-ready", () => {
// console.log("server sees that user's video is ready")
socket.to(roomId).emit("user-connected", userId);
});

socket.on("disconnect", () => {
socket.to(roomId).emit("user-disconnected", userId);
});
});

// Join the question room
socket.on("join-question-room", (roomId) => {
console.log("join-question-room")
const questionRoomId = `question_${roomId}`;
socket.join(questionRoomId);
});

// Request questions for the room

socket.on("request-questions", async (data) => {
const {roomId, complexity} = data
const questionRoomId = `question_${roomId}`;
const newQuestion = await findOrFetchNewQuestion(questionRoomId, complexity);
io.to(questionRoomId).emit("receive-questions", newQuestion);
});

socket.on("request-new-questions", async (data) => {
const {roomId, complexity} = data
const questionRoomId = `question_${roomId}`;

})
const newQuestion = await fetchQuestionByComplexity(complexity)
console.log("getnewqsn time")
console.log(newQuestion)
const foo = await roomSchema.findByIdAndUpdate(questionRoomId, {question : newQuestion});
console.log(foo)
io.to(questionRoomId).emit("receive-questions", newQuestion);
});
});

async function fetchQuestionByComplexity(complexity) {
try {
const response = await axios.get(`${QUESTION_HOST}/${complexity}`, {});
return response.data;
} catch (error) {
console.error("Error fetching question:", error);
return null;
}
}
const question_mutex = new Mutex();

async function findOrFetchNewQuestion(id, complexity) {
if (id == null) return;

const release = await question_mutex.acquire();
var question = null;
try {
question = await roomSchema.findById(id);

// if document is null, aka isn't in the DB
if (!question) {
quesiton = await fetchQuestionByComplexity(complexity)
question = await roomSchema.create({
_id: id,
question: await fetchQuestionByComplexity(complexity),
});
}
} finally {
release();
}
return question;
}

const add_to_db_mutex = new Mutex()

Expand All @@ -79,13 +143,15 @@ async function findOrCreateDocument(id) {
try {
document = await Document.findById(id)

// if document is null, aka isn't in the DB
if (!document) {
document = await Document.create({_id: id, data: DEFAULT_DOCUMENT_DATA})
}

} finally {
release()
// Handle document is not in the DB
if (!document) {
document = await Document.create({
_id: id,
data: DEFAULT_DOCUMENT_DATA,
});
}
return document
}
} finally {
release();
}
return document;
}
72 changes: 72 additions & 0 deletions backend/collab-backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/collab-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"license": "ISC",
"dependencies": {
"async-mutex": "^0.4.0",
"axios": "^1.6.0",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"mongoose": "^7.6.0",
Expand Down
7 changes: 7 additions & 0 deletions backend/collab-backend/roomSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { Schema, model } = require("mongoose")
const roomSchema = new Schema({
_id: String,
question: Object
})

module.exports = model("roomSchema", roomSchema)
33 changes: 33 additions & 0 deletions backend/question-backend/controller/getQuestionsByComplexity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Question from "../model/Question.js";

export async function getQuestionsByComplexity(req, res) {
try {
// Extract complexity from the request (e.g., from query parameters)
const { complexity } = req.params;
console.log(complexity, req.params)

// If no complexity is provided, return an error response
if (!complexity) {
return res.status(400).send("Complexity parameter is required");
}

// Find one question with the specified complexity
const question = await Question.aggregate([
{ $match: { complexity: complexity } }, // Filter by the specified complexity
{ $sample: { size: 1 } } // Get one random document
]).exec();

// Since aggregate returns an array, extract the first element
const randomQuestion = question[0];

// If no question is found, return a not found response
if (!randomQuestion) {
return res.status(404).send("No question found for the specified complexity");
}

res.send(randomQuestion);
} catch (error) {
console.log(error);
res.status(500).send("ERROR");
}
}
Loading

0 comments on commit 7040ccf

Please sign in to comment.