added complete api functionality

This commit is contained in:
JBB0807 2025-04-29 12:01:10 -07:00
parent 956ede5619
commit 24bd570795
13 changed files with 205 additions and 107 deletions

View file

@ -20,7 +20,7 @@ COPY package*.json ./
RUN npm install && npx prisma generate RUN npm install && npx prisma generate
# Rebuild bcrypt specifically (optional if clean install is guaranteed) # Rebuild bcrypt specifically (optional if clean install is guaranteed)
RUN npm rebuild bcrypt --build-from-source # RUN npm rebuild bcrypt --build-from-source
# Expose the application port # Expose the application port
EXPOSE 3200 EXPOSE 3200

View file

@ -1,6 +1,6 @@
const express = require('express'); const express = require("express");
const { PrismaClient } = require('@prisma/client'); const { PrismaClient } = require("@prisma/client");
const bcrypt = require('bcrypt'); const bcrypt = require("bcrypt");
const app = express(); const app = express();
const prisma = new PrismaClient(); const prisma = new PrismaClient();
@ -10,117 +10,150 @@ const port = process.env.NODE_PORT || 3000;
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded({ extended: true })); app.use(express.urlencoded({ extended: true }));
// Create Assignment //function to conver req.body to assignment
app.post('/assignments', async (req, res) => { function convertToAssignment(req) {
try {
const { const {
CampID, campid,
ProgramID, programid,
StudentName, studentname,
SnakeGameId, snakegameid,
OriginalFile, originalfile,
EditableFile, editablefile,
AssignmentUrl, assignmenturl,
Password, password,
InstructorID, instructorid
} = req.body; } = req.body;
const hashedPassword = await bcrypt.hash(Password, 10); // const hashedPassword = await bcrypt.hash(Password, 10);
return {
campid: campid,
programid: programid,
studentname: studentname,
snakegameid: snakegameid,
originalfile: originalfile,
editablefile: editablefile,
assignmenturl: assignmenturl,
// passwordhash: hashedpassword,
passwordhash: password,
instructorid: instructorid,
};
}
const newAssignment = await prisma.assignment.create({ // Create Assignment
app.post("/assignments", async (req, res) => {
try {
console.log("Request body:", req.body);
// const {
// campid,
// programid,
// studentname,
// snakegameid,
// originalfile,
// editablefile,
// assignmenturl,
// password,
// instructorid
// } = req.body;
// const hashedPassword = await bcrypt.hash(Password, 10);
const newAssignment = await prisma.assignments.create({
data: { data: {
CampID, ...convertToAssignment(req)
ProgramID,
StudentName,
SnakeGameId,
OriginalFile,
EditableFile,
AssignmentUrl,
PasswordHash: hashedPassword,
InstructorID,
}, },
}); });
res.json({ message: 'Assignment created successfully', assignment: newAssignment }); console.log("Assignment created successfully:", newAssignment);
res.json({
message: "Assignment created successfully",
assignment: newAssignment,
});
} catch (err) { } catch (err) {
console.error('Error creating assignment:', err.message); console.error("Error creating assignment:", err.message);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
} }
}); });
// Get Assignments by InstructorID // Get Assignments by InstructorID
app.get('/assignments/instructor/:instructorId', async (req, res) => { app.get("/assignments/instructor/:instructorId", async (req, res) => {
try { try {
const { instructorId } = req.params; const { instructorId } = req.params;
console.log("InstructorID:", instructorId);
const assignments = await prisma.assignment.findMany({ const assignments = await prisma.assignments.findMany({
where: { InstructorID: parseInt(instructorId) }, where: { instructorid: parseInt(instructorId) },
}); });
if (assignments.length === 0) { if (assignments.length === 0) {
return res.status(404).json({ message: 'No assignments found for this instructor' }); return res
.status(404)
.json({ message: "No assignments found for this instructor" });
} }
res.json(assignments); res.json(assignments);
} catch (err) { } catch (err) {
console.error('Error fetching assignments:', err.message); console.error("Error fetching assignments:", err.message);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
} }
}); });
// Read Assignment // Read Assignment
app.get('/assignments/:id', async (req, res) => { app.get("/assignments/:id", async (req, res) => {
try { try {
const assignment = await prisma.assignment.findUnique({ const assignment = await prisma.assignments.findUnique({
where: { AssignmentID: parseInt(req.params.id) }, where: { assignmentid: parseInt(req.params.id) },
}); });
if (!assignment) { if (!assignment) {
return res.status(404).json({ message: 'Assignment not found' }); return res.status(404).json({ message: "Assignment not found" });
} }
res.json(assignment); res.json(assignment);
} catch (err) { } catch (err) {
console.error('Error fetching assignment:', err.message); console.error("Error fetching assignment:", err.message);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
} }
}); });
// Update Assignment // Update Assignment
app.put('/assignments/:id', async (req, res) => { app.put("/assignments/:id", async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
const data = req.body; const data = req.body;
if (data.Password) { if (data.password) {
data.PasswordHash = await bcrypt.hash(data.Password, 10); // data.passwordhash = await bcrypt.hash(data.Password, 10);
delete data.Password; data.passwordhash = data.password;
delete data.password;
} }
const updatedAssignment = await prisma.assignment.update({ const updatedAssignment = await prisma.assignments.update({
where: { AssignmentID: parseInt(id) }, where: { assignmentid: parseInt(id) },
data, data,
}); });
res.json({ message: 'Assignment updated successfully', assignment: updatedAssignment }); res.json({
message: "Assignment updated successfully",
assignment: updatedAssignment,
});
} catch (err) { } catch (err) {
console.error('Error updating assignment:', err.message); console.error("Error updating assignment:", err.message);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
} }
}); });
// Delete Assignment // Delete Assignment
app.delete('/assignments/:id', async (req, res) => { app.delete("/assignments/:id", async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
await prisma.assignment.delete({ await prisma.assignments.delete({
where: { AssignmentID: parseInt(id) }, where: { assignmentid: parseInt(id) },
}); });
res.json({ message: 'Assignment deleted successfully' }); res.json({ message: "Assignment deleted successfully" });
} catch (err) { } catch (err) {
console.error('Error deleting assignment:', err.message); console.error("Error deleting assignment:", err.message);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
} }
}); });

View file

@ -5,8 +5,8 @@
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
#use this when testing local, remmber to run the proxy command #use this when testing local, remmber to run the proxy command
DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost:15432/postgres?schema=public" DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@host.docker.internal:15432/postgres?schema=public"
# DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable" # DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable"
# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable # DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
NODE_PORT=3000 NODE_PORT=3200

View file

@ -8,15 +8,15 @@ datasource db {
url = env("DATABASE_URL") url = env("DATABASE_URL")
} }
model Assignment { model assignments {
AssignmentID Int @id @default(autoincrement()) assignmentid Int @id @default(autoincrement())
CampID Int? campid Int?
ProgramID Int? programid Int?
StudentName String studentname String?
SnakeGameId String? snakegameid String?
OriginalFile String? originalfile String?
EditableFile String? editablefile String?
AssignmentUrl String? assignmenturl String?
PasswordHash String // store bcrypt hash passwordhash String? // store bcrypt hash
InstructorID Int? instructorid Int?
} }

View file

@ -1,2 +1,2 @@
#DB_ASSIGNMENT_SERVICE_URL = "http://localhost:3000/" #DB_ASSIGNMENT_SERVICE_URL = "http://localhost:3000"
DB_ASSIGNMENT_SERVICE_URL = "http://db-assignment-service.internal:3000/" DB_ASSIGNMENT_SERVICE_URL = "http://db-assignment-service.internal:3000"

View file

@ -1,3 +1,5 @@
DB_ASSIGNMENT_SERVICE_URL="http://localhost:3000/" #DB_ASSIGNMENT_SERVICE_URL="http://localhost:3000"
# DB_ASSIGNMENT_SERVICE_URL="http://db-assignment-service.internal:3000/" DB_ASSIGNMENT_SERVICE_URL="http://js-assignment-db-service:3200"
AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173
PORT=8082 PORT=8082

View file

@ -2,31 +2,61 @@ const intructorRouter = require("express").Router();
const passport = require("passport"); const passport = require("passport");
const axios = require("axios"); const axios = require("axios");
const { DB_ASSIGNMENT_SERVICE_URL } = process.env.DB_ASSIGNMENT_SERVICE_URL || "http://localhost:3000"; const DB_ASSIGNMENT_SERVICE_URL = process.env.DB_ASSIGNMENT_SERVICE_URL || "http://localhost:3000";
console.log("DB_ASSIGNMENT_SERVICE_URL:", DB_ASSIGNMENT_SERVICE_URL);
// This endpoint is for instructors to create a new assignment // This endpoint is for instructors to create a new assignment
intructorRouter.post("/create", passport.authenticate("jwt", { session: false }), async (req, res) => { intructorRouter.post("/create",
// passport.authenticate("jwt", { session: false }),
async (req, res) => {
try { try {
console.log("Creating a new assignment with data:", req.body);
const response = await axios.post(`${DB_ASSIGNMENT_SERVICE_URL}/assignments`, req.body); const response = await axios.post(`${DB_ASSIGNMENT_SERVICE_URL}/assignments`, req.body);
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
res.status(response.status).json(response.data); res.status(response.status).json(response.data);
} catch (error) { } catch (error) {
console.error("Error creating assignment:", error.message);
res.status(error.response?.status || 500).json({ error: error.message });
}
});
// This endpoint is for instructors to get details of a specific assignment
intructorRouter.get("/details/:id", async (req, res) => {
try {
const assignmentId = req.params.id;
console.log("Fetching details for assignmentId:", assignmentId);
const response = await axios.get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`);
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
res.status(response.status).json(response.data);
} catch (error) {
console.error("Error fetching assignment details:", error.message);
res.status(error.response?.status || 500).json({ error: error.message }); res.status(error.response?.status || 500).json({ error: error.message });
} }
}); });
// This endpoint is for instructors to get a list of assignments they have created // This endpoint is for instructors to get a list of assignments they have created
intructorRouter.get("/list", passport.authenticate("jwt", { session: false }), async (req, res) => { intructorRouter.get("/list/:id", async (req, res) => {
// if (req.isAuthenticated()) {
try { try {
const instructorId = req.user.id; // Assuming req.user contains the authenticated user const instructorId = req.params.id;
console.log("Fetching assignments for instructorId:", instructorId);
// const instructorId = req.user.userid; // Assuming req.user contains the authenticated user
const response = await axios.get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/instructor/${instructorId}`); const response = await axios.get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/instructor/${instructorId}`);
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
res.status(response.status).json(response.data); res.status(response.status).json(response.data);
} catch (error) { } catch (error) {
res.status(error.response?.status || 500).json({ error: error.message }); res.status(error.response?.status || 500).json({ error: error.message });
} }
// } else {
// return res.status(401).json({ error: "Not authenticated" });
// }
}); });
// This endpoint is for instructors to update an assignment // This endpoint is for instructors to update an assignment
intructorRouter.put("/update/:id", passport.authenticate("jwt", { session: false }), async (req, res) => { intructorRouter.put("/update/:id",
// passport.authenticate("jwt", { session: false }),
async (req, res) => {
try { try {
const assignmentId = req.params.id; const assignmentId = req.params.id;
const response = await axios.put(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`, req.body); const response = await axios.put(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`, req.body);
@ -37,7 +67,9 @@ intructorRouter.put("/update/:id", passport.authenticate("jwt", { session: false
}); });
// This endpoint is for instructors to delete an assignment // This endpoint is for instructors to delete an assignment
intructorRouter.delete("/delete/:id", passport.authenticate("jwt", { session: false }), async (req, res) => { intructorRouter.delete("/delete/:id",
// passport.authenticate("jwt", { session: false }),
async (req, res) => {
try { try {
const assignmentId = req.params.id; const assignmentId = req.params.id;
const response = await axios.delete(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`); const response = await axios.delete(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`);

View file

@ -1,10 +1,38 @@
require('dotenv').config(); require('dotenv').config();
const cors = require("cors");
const passport = require("passport");
const session = require("express-session");
const express = require("express"); const express = require("express");
const instructorRouter = require("./routes/InstructorRouter"); const instructorRouter = require("./routes/InstructorRouter");
const studentRouter = require("./routes/StudentRouter"); const studentRouter = require("./routes/StudentRouter");
const app = express(); const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// app.use(
// session({
// secret: process.env.AUTH_SESSION_KEY,
// resave: false,
// saveUninitialized: false,
// cookie: {
// maxAge: 24 * 60 * 60 * 1000, // 1 day
// },
// })
// );
// app.use(passport.initialize());
// app.use(passport.session());
// app.use(
// cors({
// origin: process.env.ACCEPTED_ORIGINS.split(","),
// methods: ["GET", "POST"],
// credentials: true,
// })
// )
app.use("/instructor", instructorRouter); app.use("/instructor", instructorRouter);
app.use("/student", studentRouter); app.use("/student", studentRouter);

View file

@ -2,7 +2,7 @@ GOOGLE_CLIENT_ID="485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleuserc
GOOGLE_CLIENT_SECRET="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" GOOGLE_CLIENT_SECRET="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"
GOOGLE_CALLBACK_URL="http://localhost:8080/auth/google/callback" GOOGLE_CALLBACK_URL="http://localhost:8080/auth/google/callback"
LOGIN_REDIRECT_URL="http://localhost:5173/" LOGIN_REDIRECT_URL="http://localhost:5173/"
ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5137 ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173
DB_USER_SERVICE_URL="http://js-user-db-service:3100/" DB_USER_SERVICE_URL="http://js-user-db-service:3100/"
AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42" AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
PORT=8080 PORT=8080

View file

@ -5,35 +5,39 @@ const axios = require("axios");
router.get( router.get(
"/google/callback", "/google/callback",
passport.authenticate("google", { passport.authenticate("google", {
successRedirect: "/auth/login", successRedirect: "/auth/google/login",
failureRedirect: "/auth/login/failed", failureRedirect: "/auth/login/failed",
}) })
); );
router.get('/current_user', (req, res) => { router.get("/current_user", (req, res) => {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
console.log("Authenticated user:", req.user);
res.json(req.user); res.json(req.user);
} else { } else {
res.status(401).json({ error: 'Not authenticated' }); console.log("User not authenticated");
res.status(401).json({ error: "Not authenticated" });
} }
}); });
router.get("/login", (req, res) => { router.get("/google/login", (req, res) => {
if (req.user) { if (req.user) {
console.log(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`);
console.log(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`) axios
axios.post(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`, { .post(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`, {
user: req.user, user: req.user,
}) })
.then(response => { .then((response) => {
req.user.userId = response.data.user.userid;
console.log("User ID:", response.data.user.userid);
req.user.role = "instructor";
console.log("User registration response:", response.data); console.log("User registration response:", response.data);
res.redirect(process.env.LOGIN_REDIRECT_URL); res.redirect(process.env.LOGIN_REDIRECT_URL);
}) })
.catch(error => { .catch((error) => {
console.error("Error registering user:", error.message); console.error("Error registering user:", error.message);
res.status(500).json({ error: true, message: "User login failed" }); res.status(500).json({ error: true, message: "User login failed" });
}); });
} else { } else {
res.status(403).json({ error: true, message: "Not Authorized" }); res.status(403).json({ error: true, message: "Not Authorized" });
} }

View file

@ -26,7 +26,7 @@ app.use(passport.session());
app.use( app.use(
cors({ cors({
origin: process.env.ACCEPTED_ORIGINS.split(","), origin: process.env.ACCEPTED_ORIGINS.split(","),
methods: "GET", methods: ["GET", "POST"],
credentials: true, credentials: true,
}) })
) )

View file

@ -9,7 +9,7 @@ services:
restart: unless-stopped restart: unless-stopped
init: true init: true
ports: ports:
- "3000:3000" # Expose port to the same host - "3200:3200" # Expose port to the same host
env_file: env_file:
- ./assignment-db-service/dev.env - ./assignment-db-service/dev.env
networks: networks:

View file

@ -38,7 +38,6 @@ instructorRouter.post("/register-user", async (req, res) => {
}, },
}); });
console.log("New user created:", newUser); console.log("New user created:", newUser);
res.json({ message: "User added successfully", user: newUser }); res.json({ message: "User added successfully", user: newUser });
} else { } else {
console.log("User already exists:", user); console.log("User already exists:", user);