Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract question routes to reduce clutter #27

Merged
merged 9 commits into from
Sep 30, 2024
145 changes: 145 additions & 0 deletions backend/controller/questionController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
const db = require("../firebase");
const questionCollection = db.collection("questions");

/**
* POST /add
*
* Creates questions from form data and store in firebase
*
* Responses:
* - 500: Server error if something goes wrong while fetching data.
*/
const createQuestion = async (req, res) => {
try {
console.log(req.body);
const questionJson = {
title: req.body.title.trim(),
category: req.body.category,
complexity: req.body.complexity,
description: req.body.description,
};

const querySnap = await db.collection("questions").where('title', '==', req.body.title.trim()).get();
if (!querySnap.empty) {
return res.status(409).json({ message: 'Duplicate entry found' });
}

const response = db.collection("questions").doc().set(questionJson); // Added 'await'
res.send({ message: "Question created successfully", response });
} catch (error) {
res.status(500).send({ error: error.message });
}
}

/**
* GET /question/
*
* Retrieves data from firebase from questions collection.
*
* Responses:
* - 200: Returns an array of data matching the query parameters.
* - 500: Server error if something goes wrong while fetching data.
*/
const getAllQuestions = async (req, res) => {
try {
const questions = await questionCollection.get();

const questionArray = [];

if (questions.empty) {
res.status(400).send("No questions found.");
}

questions.forEach((doc) => {
questionArray.push({ id: doc.id, ...doc.data() });
});

res.status(200).json(questionArray);
} catch (error) {
console.error("Error fetching data from Firebase:", error);
res.status(500).json({ message: "Error fetching data from Firebase" });
}
};

/**
* GET /question/<questionId>
*
* Retrieves specified question from questions collection in firebase.
*
* Responses:
* - 200: Returns data matching the questionId.
* - 500: Server error if something goes wrong while fetching data.
*/
const getQuestionById = async (req, res) => {
try {
const id = req.params.questionId;
const question = questionCollection.doc(id);
const data = await question.get();

if (!data.exists) {
return res.status(404).send({ message: "Question not found" });
}

res.status(200).send(data.data());
} catch (error) {
res.status(500).send({ error: error.message });
}
}

/**
* PUT /question/update/<questionId>
*
* Updates specified question from questions collection in firebase.
*/
const updateQuestion = async (req, res) => {
try {
const questionId = req.params.questionId;
console.log("Updating question ID:", questionId);

const updatedQuestion = {
title: req.body.title.trim(),
category: req.body.category,
complexity: req.body.complexity,
description: req.body.description,
};
const querySnap = await db.collection("questions").where('title', '==', req.body.title.trim()).get();
if (!querySnap.empty) {
for (const doc of querySnap.docs) {
if (doc.id != questionId) {
return res.status(409).json({ message: 'Duplicate entry found' });
}
}
}
const response = await db.collection("questions").doc(questionId).set(updatedQuestion, { merge: true });

res.send({ message: "Question updated successfully", response });
} catch (error) {
console.log(error.message)
res.status(500).send({ error: error.message });
}
}

/**
* DELETE /question/delete/<questionId>
*
* Deletes specified question from questions collection in firebase.
*/
const deleteQuestion = async (req, res) => {
try {
const questionId = req.params.questionId;
console.log("Deleting question ID:", questionId);

await db.collection("questions").doc(questionId).delete();

res.send({ message: "Question deleted successfully" });
} catch (error) {
res.status(500).send({ error: error.message });
}
}

module.exports = { createQuestion,
getAllQuestions,
getQuestionById,
updateQuestion,
deleteQuestion
};
126 changes: 4 additions & 122 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const db = require("./firebase");
const app = express();
const port = 5000;

const questionRoute = require("./routes/questionRoute");

app.use(cors());
app.use(express.json());

Expand Down Expand Up @@ -48,128 +50,8 @@ app.post("/submit/text", (req, res) => {
createText(inputText);
});

/**
* GET /api/data/questions
*
* Retrieves data from firebase from questions collection.
*
* Responses:
* - 200: Returns an array of data matching the query parameters.
* - 500: Server error if something goes wrong while fetching data.
*/
app.get("/questions/get", async (req, res) => {
try {
const snapshot = await db.collection("questions").get();
const data = [];

if (snapshot.empty) {
console.log("No matching documents.");
return;
}

snapshot.forEach((doc) => {
// console.log(doc.id, "=>", doc.data());
data.push({ id: doc.id, ...doc.data() });
});
res.status(200).json(data);
} catch (error) {
console.error("Error fetching data from Firebase:", error);
res.status(500).json({ message: "Error fetching data from Firebase" });
}
});

/**
* GET /question/<questionId>
*
* Retrieves specified question from questions collection in firebase.
*
* Responses:
* - 200: Returns data matching the questionId.
* - 500: Server error if something goes wrong while fetching data.
*/
app.get("/question/:questionId", async (req, res) => {
try {
const questionId = req.params.questionId;
const questionSnap = await db.collection("questions").doc(questionId).get();

if (!questionSnap.exists) {
return res.status(404).send({ message: "Question not found" });
}

res.status(200).send(questionSnap.data());
} catch (error) {
res.status(500).send({ error: error.message });
}
})

/**
* POST /add
*
* Creates questions from form data and store in firebase
*
* Responses:
* - 500: Server error if something goes wrong while fetching data.
*/
app.post("/questions/add", async (req, res) => {
try {
console.log(req.body);
const questionJson = {
title: req.body.title.trim(),
category: req.body.category,
complexity: req.body.complexity,
description: req.body.description,
};
const querySnap = await db.collection("questions").where('title', '==', req.body.title.trim()).get();
if (!querySnap.empty) {
return res.status(409).json({ message: 'Duplicate entry found' });
}
const response = db.collection("questions").doc().set(questionJson); // Added 'await'
res.send({ message: "Question created successfully", response });
} catch (error) {
res.status(500).send({ error: error.message });
}
});

app.put("/questions/update/:id", async (req, res) => {
try {
const questionId = req.params.id;
console.log("Updating question ID:", questionId);

const updatedQuestion = {
title: req.body.title.trim(),
category: req.body.category,
complexity: req.body.complexity,
description: req.body.description,
};
const querySnap = await db.collection("questions").where('title', '==', req.body.title.trim()).get();
if (!querySnap.empty) {
for (const doc of querySnap.docs) {
if (doc.id != questionId) {
return res.status(409).json({ message: 'Duplicate entry found' });
}
}
}
const response = await db.collection("questions").doc(questionId).set(updatedQuestion, { merge: true });

res.send({ message: "Question updated successfully", response });
} catch (error) {
console.log(error.message)
res.status(500).send({ error: error.message });
}
});

app.delete("/questions/delete/:id", async (req, res) => {
try {
const questionId = req.params.id;
console.log("Deleting question ID:", questionId);

await db.collection("questions").doc(questionId).delete();

res.send({ message: "Question deleted successfully" });
} catch (error) {
res.status(500).send({ error: error.message });
}
});
// Routes
app.use("/question", questionRoute);

app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
Expand Down
18 changes: 18 additions & 0 deletions backend/routes/questionRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const express = require("express");
const router = express.Router();

const {
createQuestion,
getAllQuestions,
getQuestionById,
updateQuestion,
deleteQuestion
} = require("../controller/questionController");

router.get("/", getAllQuestions);
router.get("/:questionId", getQuestionById);
router.post("/add", createQuestion);
router.put("/update/:questionId", updateQuestion);
router.delete("/delete/:questionId", deleteQuestion);

module.exports = router;
28 changes: 19 additions & 9 deletions my-app/src/pages/Question.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ function Question() {
useEffect(() => {
// Set loading to true before calling API
setLoading(true);

fetch("http://localhost:5000/questions/get")
fetch("http://localhost:5000/question/")
.then((response) => response.json())
.then((data) => {
setData(data)
Expand All @@ -38,7 +37,7 @@ function Question() {

if (loading) {
return (
<div class="lds-ring"><div></div><div></div><div></div><div></div></div>
<div className="lds-ring"><div></div><div></div><div></div><div></div></div>
);
}

Expand Down Expand Up @@ -70,24 +69,30 @@ function Question() {
e.preventDefault();
console.log("Input text before sending:", formData);
try {
// Set loading to true before calling API
setLoading(true);

if (selectedQuestionId) {
const response = await axios.put(
`http://localhost:5000/questions/update/${selectedQuestionId}`,
`http://localhost:5000/question/update/${selectedQuestionId}`,
formData
);
console.log("Form updated successfully:", response.data);
} else {
const response = await axios.post(
"http://localhost:5000/questions/add",
"http://localhost:5000/question/add",
formData
);
console.log("Form submitted successfully:", response.data);
}

window.location.reload();
setLoading(false);
} catch (error) {
if (error.response && error.response.status === 409) {
setError('A question with the same title already exists. Please enter a new question.');
}
setLoading(false);
}
console.error("Error submitting form:", error);
}
};
Expand All @@ -102,15 +107,20 @@ function Question() {
});
window.scrollTo({
top: 0,
behavior: 'smooth',
behavior: 'smooth',
});
};

const handleDelete = async (id) => {
try {
await axios.delete(`http://localhost:5000/questions/delete/${id}`);
// Set loading to true before calling API
setLoading(true);

await axios.delete(`http://localhost:5000/question/delete/${id}`);
console.log("Question deleted successfully");

window.location.reload();
setLoading(false);
} catch (error) {
console.error("Error deleting question:", error);
}
Expand Down Expand Up @@ -210,7 +220,7 @@ function Question() {
<td>
<div className="action-button-container">
<button className="edit-question" onClick={() => handleEdit(item)}>Edit</button>
<button className="delete-question" onClick={() => handleDelete(item.id)}>Delete</button>
<button className="delete-question" onClick={() => handleDelete(item.id)}>Delete</button>
</div>
</td>
</tr>
Expand Down
Loading