Skip to content

Commit

Permalink
Merge pull request #36 from CS3219-AY2425S1/merged-user-question
Browse files Browse the repository at this point in the history
Containerize question and user services
  • Loading branch information
iynixil authored Oct 5, 2024
2 parents b664495 + 400b094 commit 743855a
Show file tree
Hide file tree
Showing 55 changed files with 4,585 additions and 158 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
.env
.env
.vscode/
14 changes: 0 additions & 14 deletions backend/firebaseConfig.js

This file was deleted.

57 changes: 0 additions & 57 deletions backend/index.js

This file was deleted.

2 changes: 2 additions & 0 deletions backend/question-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
20 changes: 20 additions & 0 deletions backend/question-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use an official Node.js runtime as a parent image
FROM node:20-alpine

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install any dependencies
RUN npm install

# Bundle app source inside the Docker image
COPY . .

# Make port 5000 available to the world outside this container
EXPOSE 5000

# Define the command to run your app
CMD ["npm", "start"]
146 changes: 146 additions & 0 deletions backend/question-service/controller/questionController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Author(s): Calista, Xiu Jia, Xue Ling
const db = require("../db/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 questionCollection.where('title', '==', req.body.title.trim()).get();
if (!querySnap.empty) {
return res.status(409).json({ message: 'Duplicate entry found' });
}

const response = questionCollection.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 questionCollection.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 questionCollection.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 questionCollection.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
};
24 changes: 24 additions & 0 deletions backend/question-service/db/firebase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Author(s): Andrew, Xiu Jia
require("dotenv").config();
const admin = require("firebase-admin");

const firebaseConfig = {
type: "service_account",
project_id: "cs3219-d4ee1",
private_key_id: "d9899e20a23a397cdce523437f42d50696aede61",
private_key: process.env.PRIVATE_KEY,
client_email: "firebase-adminsdk-hba0d@cs3219-d4ee1.iam.gserviceaccount.com",
client_id: "106098472779235960036",
auth_uri: "https://accounts.google.com/o/oauth2/auth",
token_uri: "https://oauth2.googleapis.com/token",
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hba0d%40cs3219-d4ee1.iam.gserviceaccount.com",
universe_domain: "googleapis.com"
};

admin.initializeApp({
credential: admin.credential.cert(firebaseConfig)
});
const db = admin.firestore();

module.exports = db;
22 changes: 22 additions & 0 deletions backend/question-service/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Author(s): Andrew, Calista, Xinyi, Xiu Jia, Xue Ling
require("dotenv").config();

const express = require("express");
const cors = require("cors");
const app = express();
const port = process.env.PORT;

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

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

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.use("/question", questionRoute);

app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
"start": "nodemon index.js"
},
"author": "",
"license": "ISC",
Expand Down
19 changes: 19 additions & 0 deletions backend/question-service/routes/questionRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Author(s): Calista, Xiu Jia, Xue Ling
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;
2 changes: 2 additions & 0 deletions backend/user-service/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
20 changes: 20 additions & 0 deletions backend/user-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Use an official Node.js runtime as a parent image
FROM node:20-alpine

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install any dependencies
RUN npm install

# Bundle app source inside the Docker image
COPY . .

# Make port 5001 available to the world outside this container
EXPOSE 5001

# Define the command to run your app
CMD ["npm", "start"]
Loading

0 comments on commit 743855a

Please sign in to comment.