Skip to content

Commit 896bedd

Browse files
authored
Merge pull request #17 from CS3219-AY2425S1/D2-TEMPLATE
Add Question Service to Main Repository
2 parents 06d9807 + 8df25d8 commit 896bedd

33 files changed

+25915
-1
lines changed

Backend/.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
QuestionService/.env
2+
QuestionService/insert_questions_script.py
3+
4+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
5+
6+
# dependencies
7+
QuestionService/node_modules
8+
/.pnp
9+
.pnp.js
10+
11+
# testing
12+
/coverage
13+
14+
# production
15+
/build
16+
17+
# misc
18+
.DS_Store
19+
.env.local
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
24+
npm-debug.log*
25+
yarn-debug.log*
26+
yarn-error.log*

Backend/QuestionService/app.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const express = require('express')
2+
const mongoose = require('mongoose')
3+
const cors = require('cors')
4+
const dotenv = require("dotenv")
5+
const questionRouter = require("./controllers/questions")
6+
7+
dotenv.config()
8+
9+
const app = express()
10+
app.use(cors())
11+
app.use(express.json())
12+
13+
const mongoURI = `mongodb+srv://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@cs3219.rrxz3.mongodb.net/Question-User-DB?retryWrites=true&w=majority&appName=CS3219`
14+
mongoose.connect(mongoURI)
15+
.then(() => console.log('MongoDB connected'))
16+
.catch(err => console.error('MongoDB connection error:', err));
17+
18+
app.use('/api/questions', questionRouter)
19+
20+
module.exports = app
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const questionsRouter = require('express').Router()
2+
const QuestionModel = require('../models/Questions')
3+
4+
// Read all questions
5+
questionsRouter.get("/", async (req, res) => {
6+
try {
7+
const questions = await QuestionModel.find();
8+
res.status(200).json(questions);
9+
} catch (error) {
10+
res.status(500).json({error: error.message});
11+
}
12+
})
13+
14+
// Create a new question
15+
questionsRouter.post("/", async (req, res) => {
16+
console.log('Incoming Data:', req.body)
17+
try {
18+
const maxQuestion = await QuestionModel.findOne().sort({ id: -1 }).exec()
19+
const maxId = maxQuestion ? maxQuestion.id : 0
20+
21+
const newQuestion = new QuestionModel({
22+
category: req.body.category,
23+
complexity: req.body.complexity,
24+
description: req.body.description,
25+
id: maxId + 1,
26+
title: req.body.title
27+
})
28+
29+
// Save the new question
30+
await newQuestion.save()
31+
res.status(201).json(newQuestion)
32+
} catch (error) {
33+
if (error.code === 11000) {
34+
// Check for duplicate key in MongoDB
35+
return res.status(400).json({ error: "This title is already in use." })
36+
} else if (error.name === "ValidationError" || error.name === "CastError") {
37+
const errors = Object.values(error.errors).map(err => err.message)
38+
return res.status(400).json({ error: errors })
39+
}
40+
res.status(500).json({ error: error.message })
41+
}
42+
})
43+
44+
// Read a specific question
45+
questionsRouter.get("/:id", async (req, res) => {
46+
47+
const id = req.params.id;
48+
49+
console.log("Fetching Question with ID:", id);
50+
51+
try {
52+
const question = await QuestionModel.findById(id);
53+
54+
if (!question) {
55+
return res.status(404).json({error: 'Question not found'});
56+
}
57+
console.log("Data found: ", question);
58+
res.status(200).json(question);
59+
} catch (error) {
60+
res.status(500).json({error: error.message});
61+
}
62+
})
63+
64+
questionsRouter.put("/:id", async (req, res) => {
65+
try {
66+
const question = await QuestionModel.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
67+
if (!question) return res.status(404).json({ error: "Question not found" });
68+
res.status(200).json(question);
69+
} catch (error) {
70+
71+
if (error.code === 11000) {
72+
// Check for duplicate key in MongoDB
73+
return res.status(400).json({ error: "This title is already in use. " });
74+
} else if (error.name === "ValidationError" || error.name === "CastError" ) {
75+
const errors = Object.values(error.errors).map(err => err.message);
76+
return res.status(400).json({ error: errors });
77+
}
78+
res.status(500).json({ error: error.message });
79+
}
80+
});
81+
82+
83+
// Delete a question
84+
questionsRouter.delete("/:id", async (req, res) => {
85+
const id = req.params.id;
86+
87+
try {
88+
const question = await QuestionModel.findByIdAndDelete({_id: id});
89+
if (!question) {
90+
return res.status(404).json({error: 'Question not found '});
91+
}
92+
res.status(200).json({message: 'Question deleted'});
93+
} catch (error) {
94+
res.status(500).json({ error: error.message });
95+
}
96+
})
97+
98+
module.exports = questionsRouter
99+
100+
101+
102+
103+

Backend/QuestionService/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const app = require('./app')
2+
3+
// Change the port number to listen to a different port but remember to change the port number in frontend too!
4+
app.listen(3001, () => {
5+
console.log("Server is Running")
6+
})
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Create Question Model Here
2+
const mongoose = require('mongoose');
3+
4+
const QuestionSchema = new mongoose.Schema({
5+
category: {
6+
type: [String],
7+
required: [true, "Category is required. "],
8+
validate: {
9+
validator: function (v) {
10+
return v.length > 0;
11+
},
12+
message: "Category cannot be empty. "
13+
},
14+
},
15+
complexity: {
16+
type: String,
17+
required: [true, "Please indicate the level of complexity. "]
18+
},
19+
description: {
20+
type: String,
21+
required: [true, "Description is required. "],
22+
validate: {
23+
validator: function (v) {
24+
return v && v.trim().length > 0;
25+
},
26+
message: "Description cannot be empty. "
27+
}
28+
},
29+
id: Number,
30+
title: {
31+
type: String,
32+
required: [true, "Title is required. "],
33+
unique: true,
34+
validate: {
35+
validator: function (v) {
36+
return v && v.trim().length > 0;
37+
},
38+
message: "Title cannot be empty. "
39+
}
40+
}
41+
});
42+
43+
44+
// We create a model with the name 'Question', a schema 'QuestionSchema', and specifically looking at 'Questions' cluster in
45+
// the 'Question-User-DB' database
46+
const QuestionModel = mongoose.model('Question', QuestionSchema, 'Questions');
47+
module.exports = QuestionModel;

0 commit comments

Comments
 (0)