minor changes
This commit is contained in:
parent
909b29dfb5
commit
af2e220116
30 changed files with 598 additions and 350 deletions
|
|
@ -75,7 +75,7 @@ async function convertToAssignment(req) {
|
||||||
console.log("Converted assignment object:", assignment);
|
console.log("Converted assignment object:", assignment);
|
||||||
|
|
||||||
return assignment;
|
return assignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Assignment
|
// Create Assignment
|
||||||
app.post("/assignments", async (req, res) => {
|
app.post("/assignments", async (req, res) => {
|
||||||
|
|
@ -86,7 +86,7 @@ app.post("/assignments", async (req, res) => {
|
||||||
const newAssignment = await prisma.assignments.create({
|
const newAssignment = await prisma.assignments.create({
|
||||||
data: assignment,
|
data: assignment,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Assignment created successfully:", newAssignment);
|
console.log("Assignment created successfully:", newAssignment);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
|
@ -104,14 +104,20 @@ app.get("/assignments/instructor/:instructorId", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { instructorId } = req.params;
|
const { instructorId } = req.params;
|
||||||
console.log("InstructorID:", instructorId);
|
console.log("InstructorID:", instructorId);
|
||||||
|
// changes below
|
||||||
|
// const whereClause = { instructorid: parseInt(instructorId) };
|
||||||
|
const whereClause = {}
|
||||||
|
// changes above
|
||||||
|
|
||||||
const assignments = await prisma.assignments.findMany({
|
const assignments = await prisma.assignments.findMany({
|
||||||
where: { instructorid: parseInt(instructorId) },
|
// where: { instructorid: parseInt(instructorId) },
|
||||||
orderBy: { assignmentid: 'asc' },
|
where: whereClause,
|
||||||
|
// orderBy: { assignmentid: 'asc' }, // commnented out to return in the chronological order
|
||||||
});
|
});
|
||||||
|
|
||||||
if (assignments.length === 0) {
|
if (assignments.length === 0) {
|
||||||
return res
|
return res
|
||||||
.status(404)
|
.status(204)
|
||||||
.json({ message: "No assignments found for this instructor" });
|
.json({ message: "No assignments found for this instructor" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +128,43 @@ app.get("/assignments/instructor/:instructorId", async (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// // Get Assignments by optional InstructorID (if not provided, return all assignments)
|
||||||
|
// app.get("/assignments/instructor/:instructorId?", async (req, res) => {
|
||||||
|
// try {
|
||||||
|
|
||||||
|
// // force all queries to return all assignments even if instructorId is provided
|
||||||
|
|
||||||
|
// // const { instructorId } = req.params;
|
||||||
|
|
||||||
|
// const instructorId = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const whereClause = instructorId
|
||||||
|
// ? { instructorid: parseInt(instructorId) }
|
||||||
|
// : {};
|
||||||
|
|
||||||
|
// const assignments = await prisma.assignments.findMany({
|
||||||
|
// where: whereClause,
|
||||||
|
// orderBy: { assignmentid: 'asc' },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (assignments.length === 0) {
|
||||||
|
// return res.status(204).json({
|
||||||
|
// message: instructorId
|
||||||
|
// ? "No assignments found for this instructor"
|
||||||
|
// : "No assignments found",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// res.json(assignments);
|
||||||
|
// } catch (err) {
|
||||||
|
// console.error("Error fetching assignments:", err.message);
|
||||||
|
// res.status(500).json({ error: err.message });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
//Get assignment by assignmentid
|
//Get assignment by assignmentid
|
||||||
app.get("/assignments/:id", async (req, res) => {
|
app.get("/assignments/:id", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,18 @@ primary_region = 'sea'
|
||||||
# processes = ['app']
|
# processes = ['app']
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = 'tcp'
|
protocol = 'tcp'
|
||||||
internal_port = 3000
|
internal_port = 3000
|
||||||
auto_stop_machines = 'stop'
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
ports = []
|
ports = []
|
||||||
|
|
||||||
[services.concurrency]
|
[services.concurrency]
|
||||||
type = 'requests'
|
type = 'requests'
|
||||||
hard_limit = 1000
|
hard_limit = 1000
|
||||||
soft_limit = 500
|
soft_limit = 500
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = 'shared'
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,18 @@ primary_region = 'sea'
|
||||||
[build]
|
[build]
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = 'tcp'
|
protocol = 'tcp'
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
auto_stop_machines = 'stop'
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
ports = [] # ✅ No public ports = no public IP
|
ports = [] # ✅ No public ports = no public IP
|
||||||
|
|
||||||
[services.concurrency]
|
[services.concurrency]
|
||||||
type = 'requests'
|
type = 'requests'
|
||||||
hard_limit = 1000
|
hard_limit = 1000
|
||||||
soft_limit = 500
|
soft_limit = 500
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = 'shared'
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
107
assignment-service/package-lock.json
generated
107
assignment-service/package-lock.json
generated
|
|
@ -16,6 +16,7 @@
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
|
"http-proxy-middleware": "^3.0.5",
|
||||||
"multer": "^1.4.5-lts.2",
|
"multer": "^1.4.5-lts.2",
|
||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"passport": "^0.7.0"
|
"passport": "^0.7.0"
|
||||||
|
|
@ -44,6 +45,24 @@
|
||||||
"node-pre-gyp": "bin/node-pre-gyp"
|
"node-pre-gyp": "bin/node-pre-gyp"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/http-proxy": {
|
||||||
|
"version": "1.17.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
|
||||||
|
"integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.15.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
|
||||||
|
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.21.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
|
@ -755,6 +774,12 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/events": {
|
"node_modules/events": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||||
|
|
@ -1207,6 +1232,54 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/http-proxy": {
|
||||||
|
"version": "1.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||||
|
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": "^4.0.0",
|
||||||
|
"follow-redirects": "^1.0.0",
|
||||||
|
"requires-port": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/http-proxy": "^1.17.15",
|
||||||
|
"debug": "^4.3.6",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"micromatch": "^4.0.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware/node_modules/debug": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/https-proxy-agent": {
|
"node_modules/https-proxy-agent": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||||
|
|
@ -1384,6 +1457,15 @@
|
||||||
"node": ">=0.12.0"
|
"node": ">=0.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-plain-object": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-promise": {
|
"node_modules/is-promise": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||||
|
|
@ -1493,6 +1575,19 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.3",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.54.0",
|
"version": "1.54.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
|
|
@ -2053,6 +2148,12 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/requires-port": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/rimraf": {
|
"node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
|
@ -2514,6 +2615,12 @@
|
||||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
|
"http-proxy-middleware": "^3.0.5",
|
||||||
"multer": "^1.4.5-lts.2",
|
"multer": "^1.4.5-lts.2",
|
||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"passport": "^0.7.0"
|
"passport": "^0.7.0"
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ intructorRouter.get("/details/:id", async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
||||||
|
console.log("Response status:", response.status);
|
||||||
res.status(response.status).json(response.data);
|
res.status(response.status).json(response.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching assignment details:", error.message);
|
console.error("Error fetching assignment details:", error.message);
|
||||||
|
|
@ -129,16 +130,20 @@ intructorRouter.get(
|
||||||
"/list/:id",
|
"/list/:id",
|
||||||
// passport.authenticate("jwt", { session: false }),
|
// passport.authenticate("jwt", { session: false }),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
|
console.log("/list/:id endpoint hit");
|
||||||
// if (req.isAuthenticated()) {
|
// if (req.isAuthenticated()) {
|
||||||
try {
|
try {
|
||||||
const instructorId = req.params.id;
|
const instructorId = req.params.id;
|
||||||
// console.log("Fetching assignments for instructorId:", instructorId);
|
console.log("Fetching assignments for instructorId:", instructorId);
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/instructor/${instructorId}`
|
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/instructor/${instructorId}`
|
||||||
);
|
);
|
||||||
// console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
||||||
|
console.log("Response status:", response.status);
|
||||||
res.status(response.status).json(response.data);
|
res.status(response.status).json(response.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log("Error fetching assignments:", error.response);
|
||||||
|
console.error("Error fetching assignments:", error.message);
|
||||||
res.status(error.response?.status || 500).json({ error: error.message });
|
res.status(error.response?.status || 500).json({ error: error.message });
|
||||||
}
|
}
|
||||||
// } else {
|
// } else {
|
||||||
|
|
@ -191,10 +196,10 @@ intructorRouter.delete(
|
||||||
|
|
||||||
if (!assignmentData) {
|
if (!assignmentData) {
|
||||||
return res.status(404).json({ error: "Assignment not found" });
|
return res.status(404).json({ error: "Assignment not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the Battlesnake API
|
// Delete the Battlesnake API
|
||||||
if(assignmentData.appname){
|
if (assignmentData.appname) {
|
||||||
console.log(`Deleting Battlesnake API: ${assignmentData.appname}`);
|
console.log(`Deleting Battlesnake API: ${assignmentData.appname}`);
|
||||||
const deployResponse = await axios.post(`${DEPLOY_API_URL}/${assignmentData.appname}/delete`, {
|
const deployResponse = await axios.post(`${DEPLOY_API_URL}/${assignmentData.appname}/delete`, {
|
||||||
"appName": assignmentData.appname
|
"appName": assignmentData.appname
|
||||||
|
|
@ -206,7 +211,7 @@ intructorRouter.delete(
|
||||||
}
|
}
|
||||||
console.log('Response from DEPLOY_API_URL:', deployResponse.data);
|
console.log('Response from DEPLOY_API_URL:', deployResponse.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Deleting assignment from database:", assignmentId);
|
console.log("Deleting assignment from database:", assignmentId);
|
||||||
const response = await axios.delete(
|
const response = await axios.delete(
|
||||||
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`
|
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`
|
||||||
|
|
@ -231,7 +236,7 @@ intructorRouter.get(
|
||||||
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/appname/${appName}`
|
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/appname/${appName}`
|
||||||
);
|
);
|
||||||
console.log("Response data:", response.data);
|
console.log("Response data:", response.data);
|
||||||
res.status(response.status).json({"exists": (response.data !== null && response.data !== undefined)});
|
res.status(response.status).json({ "exists": (response.data !== null && response.data !== undefined) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching assignment by app name:", error.message);
|
console.error("Error fetching assignment by app name:", error.message);
|
||||||
res.status(error.response?.status || 500).json({ error: error.message });
|
res.status(error.response?.status || 500).json({ error: error.message });
|
||||||
|
|
@ -251,7 +256,7 @@ intructorRouter.get(
|
||||||
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${qrcode}`
|
`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${qrcode}`
|
||||||
);
|
);
|
||||||
console.log("Response data:", response.data);
|
console.log("Response data:", response.data);
|
||||||
res.status(response.status).json({"exists": (response.data !== null && response.data !== undefined)});
|
res.status(response.status).json({ "exists": (response.data !== null && response.data !== undefined) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching assignment by QR code:", error.message);
|
console.error("Error fetching assignment by QR code:", error.message);
|
||||||
res.status(error.response?.status || 500).json({ error: error.message });
|
res.status(error.response?.status || 500).json({ error: error.message });
|
||||||
|
|
|
||||||
|
|
@ -7,24 +7,24 @@ const DB_ASSIGNMENT_SERVICE_URL = process.env.DB_ASSIGNMENT_SERVICE_URL;
|
||||||
const DEPLOY_API_URL = process.env.DEPLOY_API_URL || "http://localhost:3600";
|
const DEPLOY_API_URL = process.env.DEPLOY_API_URL || "http://localhost:3600";
|
||||||
|
|
||||||
studentRouter.post("/save", async (req, res) => {
|
studentRouter.post("/save", async (req, res) => {
|
||||||
//get the app name and code and save the latest jupyter file in s3 bucket
|
//get the app name and code and save the latest jupyter file in s3 bucket
|
||||||
const { appName, code } = req.body;
|
const { appName, code } = req.body;
|
||||||
|
|
||||||
console.log("Received save request for app:", appName);
|
console.log("Received save request for app:", appName);
|
||||||
|
|
||||||
const notebook = {
|
const notebook = {
|
||||||
cells: [
|
cells: [
|
||||||
{
|
{
|
||||||
cell_type: "code",
|
cell_type: "code",
|
||||||
execution_count: null,
|
execution_count: null,
|
||||||
metadata: {
|
metadata: {
|
||||||
language: "python"
|
language: "python"
|
||||||
},
|
},
|
||||||
outputs: [],
|
outputs: [],
|
||||||
source: code.split('\n').map(line => line + '\n')
|
source: code.split('\n').map(line => line + '\n')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
metadata: {
|
metadata: {
|
||||||
kernelspec: {
|
kernelspec: {
|
||||||
display_name: "Python 3",
|
display_name: "Python 3",
|
||||||
language: "python",
|
language: "python",
|
||||||
|
|
@ -34,36 +34,36 @@ studentRouter.post("/save", async (req, res) => {
|
||||||
name: "python",
|
name: "python",
|
||||||
version: "3.x"
|
version: "3.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nbformat: 4,
|
nbformat: 4,
|
||||||
nbformat_minor: 5
|
nbformat_minor: 5
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert the notebook object to a JSON string and then to base64
|
// Convert the notebook object to a JSON string and then to base64
|
||||||
const jsonString = JSON.stringify(notebook, null, 2);
|
const jsonString = JSON.stringify(notebook, null, 2);
|
||||||
const base64 = Buffer.from(jsonString, 'utf-8').toString('base64');
|
const base64 = Buffer.from(jsonString, 'utf-8').toString('base64');
|
||||||
|
|
||||||
const notebookName = `${Date.now()}-notebook.ipynb`;
|
const notebookName = `${Date.now()}-notebook.ipynb`;
|
||||||
console.log("DEPLOY_API_URL:", DEPLOY_API_URL);
|
console.log("DEPLOY_API_URL:", DEPLOY_API_URL);
|
||||||
console.log("Uploading notebook:", notebookName, "to app:", appName);
|
console.log("Uploading notebook:", notebookName, "to app:", appName);
|
||||||
|
|
||||||
await fetch(`${DEPLOY_API_URL}/${appName}/upload`, {
|
await fetch(`${DEPLOY_API_URL}/${appName}/upload`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ notebookName: notebookName, fileContentBase64: base64 })
|
body: JSON.stringify({ notebookName: notebookName, fileContentBase64: base64 })
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) throw new Error("Failed to save notebook");
|
||||||
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((data) => {
|
||||||
if (!response.ok) throw new Error("Failed to save notebook");
|
console.log("Notebook saved successfully:", data);
|
||||||
return response.json();
|
res.status(200).json(data);
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.catch((error) => {
|
||||||
console.log("Notebook saved successfully:", data);
|
console.error("Error saving notebook:", error.message);
|
||||||
res.status(200).json(data);
|
res.status(500).json({ error: error.message });
|
||||||
})
|
});
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error saving notebook:", error.message);
|
|
||||||
res.status(500).json({ error: error.message });
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
studentRouter.get("/assignment/:qrnum", (req, res) => {
|
studentRouter.get("/assignment/:qrnum", (req, res) => {
|
||||||
|
|
@ -105,7 +105,7 @@ studentRouter.post("/verify", async (req, res) => {
|
||||||
|
|
||||||
const isPasswordValid = await bcrypt.compare(
|
const isPasswordValid = await bcrypt.compare(
|
||||||
password,
|
password,
|
||||||
response.data.passwordhash
|
response.data.passwordhash
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("Password validation result:", isPasswordValid);
|
console.log("Password validation result:", isPasswordValid);
|
||||||
|
|
|
||||||
|
|
@ -9,34 +9,34 @@ primary_region = 'sea'
|
||||||
[build]
|
[build]
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
PORT = '8080'
|
PORT = '8080'
|
||||||
|
|
||||||
[http_service]
|
[http_service]
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
force_https = true
|
force_https = true
|
||||||
auto_stop_machines = 'stop'
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
min_machines_running = 0
|
min_machines_running = 0
|
||||||
processes = ['app']
|
processes = ['app']
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = 'tcp'
|
protocol = 'tcp'
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
|
|
||||||
[[services.ports]]
|
[[services.ports]]
|
||||||
port = 80
|
port = 80
|
||||||
handlers = ['http']
|
handlers = ['http']
|
||||||
|
|
||||||
[[services.ports]]
|
[[services.ports]]
|
||||||
port = 443
|
port = 443
|
||||||
handlers = ['tls', 'http']
|
handlers = ['tls', 'http']
|
||||||
|
|
||||||
[[services.tcp_checks]]
|
# [[services.tcp_checks]]
|
||||||
interval = '10s'
|
# interval = '10s'
|
||||||
timeout = '2s'
|
# timeout = '2s'
|
||||||
grace_period = '5s'
|
# grace_period = '5s'
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = 'shared'
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
11
auth-service/old.env.development
Normal file
11
auth-service/old.env.development
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID="485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleusercontent.com"
|
||||||
|
GOOGLE_CLIENT_SECRET="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"
|
||||||
|
GOOGLE_CALLBACK_URL="http://localhost:8080/auth/google/callback"
|
||||||
|
LOGIN_REDIRECT_URL="http://localhost:5173/"
|
||||||
|
ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173
|
||||||
|
ASSIGNMENT_SERVICE_URL="http://localhost:8082"
|
||||||
|
DB_USER_SERVICE_URL="http://localhost:3100/"
|
||||||
|
AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
|
||||||
|
PORT=8080
|
||||||
|
|
@ -36,8 +36,11 @@ passport.use(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("Sending request to external auth service...");
|
console.log("Sending request to external auth service...");
|
||||||
|
console.log(
|
||||||
|
`Request URL: ${process.env.ASSIGNMENT_SERVICE_URL}student/verify`
|
||||||
|
);
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${process.env.ASSIGNMENT_SERVICE_URL}/student/verify`,
|
`${process.env.ASSIGNMENT_SERVICE_URL}student/verify`,
|
||||||
{
|
{
|
||||||
qrNumber,
|
qrNumber,
|
||||||
password,
|
password,
|
||||||
|
|
@ -64,6 +67,7 @@ passport.use(
|
||||||
|
|
||||||
passport.serializeUser((user, done) => {
|
passport.serializeUser((user, done) => {
|
||||||
console.log("Serializing user:", user);
|
console.log("Serializing user:", user);
|
||||||
|
console.log(process.env.NODE_ENV)
|
||||||
// done(null, user);
|
// done(null, user);
|
||||||
done(null, {
|
done(null, {
|
||||||
userId: user.qrcodenumber || user.userId,
|
userId: user.qrcodenumber || user.userId,
|
||||||
|
|
|
||||||
32
auth-service/routes/assignment.js
Normal file
32
auth-service/routes/assignment.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// routes/assignment.js
|
||||||
|
const express = require("express");
|
||||||
|
const { createProxyMiddleware } = require("http-proxy-middleware");
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// Middleware to check authentication
|
||||||
|
function isAuthenticated(req, res, next) {
|
||||||
|
if (req.isAuthenticated && req.isAuthenticated()) {
|
||||||
|
return next();
|
||||||
|
} else {
|
||||||
|
return res.status(401).json({ error: "Not authenticated, visit /login" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy configuration
|
||||||
|
const proxy = createProxyMiddleware({
|
||||||
|
target: "http://assignment-service.internal:8080",
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
"^/assignment": "", // remove `/assignment` prefix when forwarding
|
||||||
|
},
|
||||||
|
onProxyReq(proxyReq, req, res) {
|
||||||
|
// Optional: log or modify headers
|
||||||
|
console.log(`Proxying ${req.method} request to ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply both middleware
|
||||||
|
router.use(isAuthenticated, proxy);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
@ -6,6 +6,7 @@ const express = require("express");
|
||||||
|
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require("body-parser");
|
||||||
|
|
||||||
|
|
||||||
auth.use(express.json());
|
auth.use(express.json());
|
||||||
auth.use(bodyParser.urlencoded({ extended: true }));
|
auth.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
|
@ -20,7 +21,7 @@ auth.get(
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
console.log("Google callback endpoint hit");
|
console.log("Google callback endpoint hit");
|
||||||
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,
|
||||||
|
|
@ -35,8 +36,25 @@ auth.get(
|
||||||
console.error("Login error:", err);
|
console.error("Login error:", err);
|
||||||
return res.status(500).send("Login failed");
|
return res.status(500).send("Login failed");
|
||||||
}
|
}
|
||||||
return res.redirect(process.env.LOGIN_REDIRECT_URL);
|
// Force session save before redirect
|
||||||
|
req.session.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Session save error:", err);
|
||||||
|
return res.status(500).send("Session save failed");
|
||||||
|
}
|
||||||
|
console.log("Session saved successfully");
|
||||||
|
return res.redirect(process.env.LOGIN_REDIRECT_URL);
|
||||||
|
});
|
||||||
|
console.log("User logged in successfully:", req.session);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// req.login(req.user, (err) => {
|
||||||
|
// if (err) {
|
||||||
|
// console.error("Login error:", err);
|
||||||
|
// return res.status(500).send("Login failed");
|
||||||
|
// }
|
||||||
|
// return 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);
|
||||||
|
|
@ -67,6 +85,19 @@ auth.get("/login/failed", (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Set a test cookie
|
||||||
|
auth.get("/test-cookie", (req, res) => {
|
||||||
|
res.cookie("test-session", "123", {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "none",
|
||||||
|
domain: "snake-byte.org", // Set the domain to allow cross-origin requests
|
||||||
|
});
|
||||||
|
res.send("Cookie set");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
auth.get("/google", passport.authenticate("google", ["profile", "email"]));
|
auth.get("/google", passport.authenticate("google", ["profile", "email"]));
|
||||||
|
|
||||||
auth.post(
|
auth.post(
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,86 @@ const passport = require("passport");
|
||||||
const passportSetup = require("./passport");
|
const passportSetup = require("./passport");
|
||||||
const authRoute = require("./routes/auth");
|
const authRoute = require("./routes/auth");
|
||||||
const apiRoute = require("./routes/api");
|
const apiRoute = require("./routes/api");
|
||||||
|
const assignmentRoute = require("./routes/assignment");
|
||||||
|
|
||||||
const session = require("express-session");
|
const session = require("express-session");
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// console.log("AUTH_URL:", process.env.AUTH_URL);
|
app.use((req, res, next) => {
|
||||||
|
console.log('Protocol before proxy:', req.protocol, 'Secure:', req.secure);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
console.log('req.secure:', req.secure);
|
||||||
|
console.log('x-forwarded-proto:', req.headers['x-forwarded-proto']);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.set('trust proxy', true); // proxy magic that needs to happen
|
||||||
|
|
||||||
|
|
||||||
|
// app.use((req, res, next) => {
|
||||||
|
// console.log('Protocol after proxy:', req.protocol, 'Secure:', req.secure);
|
||||||
|
// next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
const allowedOrigins = process.env.ACCEPTED_ORIGINS.split(",");
|
||||||
|
|
||||||
|
const corsOptions = {
|
||||||
|
// origin: function (origin, callback) {
|
||||||
|
// if (!origin || allowedOrigins.includes(origin)) {
|
||||||
|
// callback(null, origin); // allow the request
|
||||||
|
// } else {
|
||||||
|
// callback(new Error("Not allowed by CORS"));
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
origin: "https://snake-byte.org", // Replace with your frontend URL
|
||||||
|
// methods: ["GET", "POST", "OPTIONS"],
|
||||||
|
// allowedHeaders: ["Content-Type", "Authorization"],
|
||||||
|
credentials: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
app.use(cors(corsOptions));
|
||||||
|
|
||||||
|
|
||||||
|
// app.use((req, res, next) => {
|
||||||
|
// console.log("Session:", req.session);
|
||||||
|
// console.log("User:", req.user);
|
||||||
|
// next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// app.use((req, res, next) => {
|
||||||
|
// res.cookie(
|
||||||
|
// 'myTestCookie', 'helloWorld',
|
||||||
|
// {
|
||||||
|
// httpOnly: true,
|
||||||
|
// secure: true, // Set to true if using HTTPS
|
||||||
|
// sameSite: 'none', // Use 'none' for cross-origin requests
|
||||||
|
// domain: 'jank-frontend.fly.dev', // Set the domain to allow cross-origin requests
|
||||||
|
// maxAge: 24 * 60 * 60 * 1000, // 1 day
|
||||||
|
// path: '/', // Set the path for the cookie
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
console.log("AUTH_URL:", process.env.AUTH_URL);
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: process.env.AUTH_SESSION_KEY,
|
secret: process.env.AUTH_SESSION_KEY,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false, // true in development, false in production
|
||||||
cookie: {
|
cookie: {
|
||||||
|
httpOnly: true, // true in production for sec
|
||||||
maxAge: 24 * 60 * 60 * 1000, // 1 day
|
maxAge: 24 * 60 * 60 * 1000, // 1 day
|
||||||
|
secure: true, //true // only true in production over HTTPS
|
||||||
|
sameSite: 'none', // or 'none' if using cross-origin
|
||||||
|
// domain: '', // Set the domain to allow cross-origin requests, or not?
|
||||||
//keep production security settings below disable for the mean-time because we need to integrate redis session for cross-origin to work properly
|
//keep production security settings below disable for the mean-time because we need to integrate redis session for cross-origin to work properly
|
||||||
//sameSite: isProduction ? "none" : "lax", // or 'none' if using cross-origin
|
//sameSite: isProduction ? "none" : "lax", // or 'none' if using cross-origin
|
||||||
//secure: isProduction, // only true in production over HTTPS
|
//secure: isProduction, // only true in production over HTTPS
|
||||||
|
|
@ -26,28 +93,36 @@ app.use(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// console.log("this is the session", session);
|
||||||
|
// console.log("this is the cookie", session.cookie);
|
||||||
|
|
||||||
app.use(passport.initialize());
|
app.use(passport.initialize());
|
||||||
app.use(passport.session());
|
app.use(passport.session());
|
||||||
|
|
||||||
const allowedOrigins = process.env.ACCEPTED_ORIGINS.split(",");
|
|
||||||
|
|
||||||
const corsOptions = {
|
|
||||||
origin: function (origin, callback) {
|
|
||||||
if (!origin || allowedOrigins.includes(origin)) {
|
|
||||||
callback(null, origin); // allow the request
|
|
||||||
} else {
|
|
||||||
callback(new Error("Not allowed by CORS"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: ["GET", "POST", "OPTIONS"],
|
|
||||||
allowedHeaders: ["Content-Type", "Authorization"],
|
|
||||||
credentials: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
app.use(cors(corsOptions));
|
// app.use((req, res, next) => {
|
||||||
|
// res.on("finish", () => {
|
||||||
|
// console.log(`Response Status: ${res.statusCode}`);
|
||||||
|
// console.log(`Response Headers:`, res.getHeaders());
|
||||||
|
// });
|
||||||
|
// next();
|
||||||
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
// app.use((req, res, next) => {
|
||||||
|
// res.on("finish", () => {
|
||||||
|
// const headers = res.getHeaders();
|
||||||
|
// console.log("Set-Cookie header:", headers["set-cookie"]);
|
||||||
|
// });
|
||||||
|
// next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
app.use("/assignment", assignmentRoute);
|
||||||
app.use("/api", apiRoute);
|
app.use("/api", apiRoute);
|
||||||
app.use("/auth", authRoute);
|
app.use("/auth", authRoute);
|
||||||
|
|
||||||
const port = process.env.PORT || 8080;
|
const port = 8080;
|
||||||
app.listen(port, () => console.log(`Listening on port ${port}...`));
|
console.log(`Listening on port ${port}...`);
|
||||||
|
app.listen(port, '0.0.0.0');
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,21 @@ app = 'deployment-service'
|
||||||
primary_region = 'sea'
|
primary_region = 'sea'
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
dockerfile = 'Dockerfile'
|
dockerfile = 'Dockerfile'
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = 'tcp'
|
protocol = 'tcp'
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
auto_stop_machines = 'stop'
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
ports = []
|
ports = []
|
||||||
|
|
||||||
[services.concurrency]
|
[services.concurrency]
|
||||||
type = 'requests'
|
type = 'requests'
|
||||||
hard_limit = 1000
|
hard_limit = 1000
|
||||||
soft_limit = 500
|
soft_limit = 500
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = 'shared'
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ app.post("/deploy", async (req, res) => {
|
||||||
http_service: {
|
http_service: {
|
||||||
internal_port: 8000,
|
internal_port: 8000,
|
||||||
force_https: true,
|
force_https: true,
|
||||||
auto_stop_machines: "stop",
|
auto_stop_machines: "suspend",
|
||||||
auto_start_machines: true,
|
auto_start_machines: true,
|
||||||
min_machines_running: 0,
|
min_machines_running: 0,
|
||||||
processes: ["app"],
|
processes: ["app"],
|
||||||
|
|
@ -147,14 +147,14 @@ app.post("/deploy", async (req, res) => {
|
||||||
console.log("Machine config:", JSON.stringify(machineConfig, null, 2));
|
console.log("Machine config:", JSON.stringify(machineConfig, null, 2));
|
||||||
await fly.post(`/apps/${appName}/machines`, machineConfig);
|
await fly.post(`/apps/${appName}/machines`, machineConfig);
|
||||||
|
|
||||||
console.log("Allocating IPv4 via GraphQL API");
|
// console.log("Allocating IPv4 via GraphQL API");
|
||||||
const v4resp = await gqlClient.post("", {
|
// const v4resp = await gqlClient.post("", {
|
||||||
query: ALLOCATE_IP_MUTATION,
|
// query: ALLOCATE_IP_MUTATION,
|
||||||
variables: { input: { appId: appName, type: "v4" } },
|
// variables: { input: { appId: appName, type: "v4" } },
|
||||||
});
|
// });
|
||||||
const ipv4 = v4resp.data.data.allocateIpAddress.ipAddress.address;
|
// const ipv4 = v4resp.data.data.allocateIpAddress.ipAddress.address;
|
||||||
console.log("Allocated IPv4:", ipv4);
|
// console.log("Allocated IPv4:", ipv4);
|
||||||
|
const ipv4 = "snake-byte.org"; // Placeholder for IPv4 allocation, if needed
|
||||||
console.log("Allocating IPv6 via GraphQL API");
|
console.log("Allocating IPv6 via GraphQL API");
|
||||||
const v6resp = await gqlClient.post("", {
|
const v6resp = await gqlClient.post("", {
|
||||||
query: ALLOCATE_IP_MUTATION,
|
query: ALLOCATE_IP_MUTATION,
|
||||||
|
|
@ -175,7 +175,7 @@ app.post("/deploy", async (req, res) => {
|
||||||
status: "created",
|
status: "created",
|
||||||
app: appName,
|
app: appName,
|
||||||
ipv4,
|
ipv4,
|
||||||
ipv6 : firstPrivateIp,
|
ipv6: firstPrivateIp,
|
||||||
url_v4: `http://${ipv4}`,
|
url_v4: `http://${ipv4}`,
|
||||||
url_v6: `http://[${firstPrivateIp}]`,
|
url_v6: `http://[${firstPrivateIp}]`,
|
||||||
});
|
});
|
||||||
|
|
@ -255,7 +255,7 @@ app.post("/:appName/delete", async (req, res) => {
|
||||||
|
|
||||||
const appCheck = await fly.get(`/apps/${appName}`);
|
const appCheck = await fly.get(`/apps/${appName}`);
|
||||||
console.log("App check response:", appCheck.status);
|
console.log("App check response:", appCheck.status);
|
||||||
|
|
||||||
await fly.delete(`/apps/${appName}`);
|
await fly.delete(`/apps/${appName}`);
|
||||||
|
|
||||||
return res.json({ status: "deleted", app: appName });
|
return res.json({ status: "deleted", app: appName });
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,24 @@
|
||||||
|
# flyctl launch added from .gitignore
|
||||||
# General
|
# General
|
||||||
.DS_Store
|
**/.DS_Store
|
||||||
.vscode
|
**/.vscode
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
node_modules
|
**/node_modules
|
||||||
|
|
||||||
# SvelteKit
|
# SvelteKit
|
||||||
.output
|
**/.output
|
||||||
.svelte-kit
|
**/.svelte-kit
|
||||||
/build
|
build
|
||||||
/package
|
package
|
||||||
|
|
||||||
.env
|
**/.env
|
||||||
.env.*
|
**/.env.*
|
||||||
!.env.example
|
!**/.env.example
|
||||||
|
|
||||||
vite.config.js.timestamp-*
|
**/vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
**/vite.config.ts.timestamp-*
|
||||||
|
|
||||||
# Netlify
|
# Netlify
|
||||||
.netlify
|
**/.netlify
|
||||||
|
fly.toml
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
|
|
||||||
|
|
||||||
name: Fly Deploy
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
name: Deploy app
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
concurrency: deploy-group # optional: ensure only one action runs at a time
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
|
||||||
- run: flyctl deploy --remote-only
|
|
||||||
env:
|
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
|
||||||
29
gameboard-service/.github/workflows/release.yaml
vendored
29
gameboard-service/.github/workflows/release.yaml
vendored
|
|
@ -1,29 +0,0 @@
|
||||||
name: Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tests:
|
|
||||||
name: Tests
|
|
||||||
uses: ./.github/workflows/tests.yaml
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
name: netlify deploy
|
|
||||||
needs: [tests]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: echo ${{ github.event.release.tag_name }} > ./static/version
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm install -g netlify-cli
|
|
||||||
- run: netlify build
|
|
||||||
env:
|
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
|
||||||
- run: netlify deploy --prod --message ${{ github.event.release.tag_name }}
|
|
||||||
env:
|
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
|
||||||
43
gameboard-service/.github/workflows/tests.yaml
vendored
43
gameboard-service/.github/workflows/tests.yaml
vendored
|
|
@ -1,43 +0,0 @@
|
||||||
name: Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push: # Branch pushes only, not tags
|
|
||||||
branches:
|
|
||||||
- "**"
|
|
||||||
workflow_call: # Allow other workflows to call this one
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
name: npm run lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run lint
|
|
||||||
|
|
||||||
check:
|
|
||||||
name: npm run check
|
|
||||||
needs: [lint]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run check
|
|
||||||
|
|
||||||
unit:
|
|
||||||
name: npm run test:unit
|
|
||||||
needs: [check]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run test:unit
|
|
||||||
|
|
||||||
build:
|
|
||||||
name: npm run build
|
|
||||||
needs: [check]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run build
|
|
||||||
|
|
@ -1,47 +1,27 @@
|
||||||
# syntax = docker/dockerfile:1
|
# Build Stage
|
||||||
|
FROM node:18 AS build
|
||||||
|
|
||||||
# Adjust NODE_VERSION as desired
|
|
||||||
ARG NODE_VERSION=22.13.0
|
|
||||||
FROM node:${NODE_VERSION}-slim AS base
|
|
||||||
|
|
||||||
LABEL fly_launch_runtime="SvelteKit"
|
|
||||||
|
|
||||||
# SvelteKit app lives here
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Set production environment
|
COPY package*.json ./
|
||||||
ENV NODE_ENV="production"
|
RUN npm install
|
||||||
ENV PORT="3005"
|
|
||||||
|
|
||||||
# Throw-away build stage to reduce size of final image
|
|
||||||
FROM base AS build
|
|
||||||
|
|
||||||
# Install packages needed to build node modules
|
|
||||||
RUN apt-get update -qq && \
|
|
||||||
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3
|
|
||||||
|
|
||||||
# Install node modules
|
|
||||||
COPY .npmrc package-lock.json package.json ./
|
|
||||||
RUN npm ci --include=dev
|
|
||||||
|
|
||||||
# Copy application code
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build application
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Remove development dependencies
|
# Serve Stage
|
||||||
RUN npm prune --omit=dev
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
# Copy built frontend into nginx public folder
|
||||||
|
COPY --from=build /app/build /usr/share/nginx/html
|
||||||
|
|
||||||
# Final stage for app image
|
# Remove default Nginx config
|
||||||
FROM base
|
RUN rm /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
# Copy built application
|
# Add custom Nginx config
|
||||||
COPY --from=build /app/build /app/build
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY --from=build /app/node_modules /app/node_modules
|
|
||||||
COPY --from=build /app/package.json /app
|
|
||||||
|
|
||||||
# Start the server by default, this can be overwritten at runtime
|
# Expose port 80 (not 8080 inside container)
|
||||||
EXPOSE 3005
|
EXPOSE 3000
|
||||||
CMD [ "node", "./build/index.js" ]
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
app = "gameboard-service-aged-glitter-8141"
|
# fly.toml app configuration file generated for gameboard-service on 2025-06-01T21:09:25-07:00
|
||||||
primary_region = "sea"
|
#
|
||||||
|
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||||
|
#
|
||||||
|
|
||||||
[env]
|
app = 'gameboard-service'
|
||||||
PORT = "3005"
|
primary_region = 'sea'
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
|
||||||
|
|
||||||
[http_service]
|
[http_service]
|
||||||
internal_port = 3005
|
internal_port = 3000
|
||||||
force_https = true
|
force_https = true
|
||||||
auto_stop_machines = "stop"
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
min_machines_running = 0
|
min_machines_running = 0
|
||||||
processes = ["app"]
|
processes = ['app']
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = "1gb"
|
memory = '512mb'
|
||||||
cpu_kind = "shared"
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
25
gameboard-service/nginx.conf
Normal file
25
gameboard-service/nginx.conf
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 3000;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Enable compression
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
expires 1h;
|
||||||
|
add_header Cache-Control "public, no-transform";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serve pre-compressed files if they exist
|
||||||
|
location ~ \.(?:js|css|html)$ {
|
||||||
|
gzip_static on;
|
||||||
|
expires 1h;
|
||||||
|
add_header Cache-Control "public, no-transform";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,4 +49,4 @@
|
||||||
"vitest": "^0.32.2"
|
"vitest": "^0.32.2"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|
@ -88,8 +88,8 @@ export function engineEventToFrame(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
turn: engineGameEvent.Turn,
|
turn: engineGameEvent.Turn,
|
||||||
width: engineGameInfo.Game.Width,
|
width: 11,
|
||||||
height: engineGameInfo.Game.Height,
|
height: 11,
|
||||||
snakes: engineGameEvent.Snakes.map(engineSnakeToSnake),
|
snakes: engineGameEvent.Snakes.map(engineSnakeToSnake),
|
||||||
food: engineGameEvent.Food.map(engineCoordsToPoint),
|
food: engineGameEvent.Food.map(engineCoordsToPoint),
|
||||||
hazards: engineGameEvent.Hazards.map(engineCoordsToPoint),
|
hazards: engineGameEvent.Hazards.map(engineCoordsToPoint),
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,8 @@ export type Settings = {
|
||||||
export function getDefaultSettings(): Settings {
|
export function getDefaultSettings(): Settings {
|
||||||
return {
|
return {
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
engine: "https://engine.battlesnake.com",
|
// engine: "https://engine.battlesnake.com",
|
||||||
|
engine: "https://snake-server.fly.dev",
|
||||||
fps: 6,
|
fps: 6,
|
||||||
game: "",
|
game: "",
|
||||||
loop: false,
|
loop: false,
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,40 @@
|
||||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
// // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
// // If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
// // See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
|
// // import adapter from '@sveltejs/adapter-node';
|
||||||
// import adapter from '@sveltejs/adapter-node';
|
// import adapter from '@sveltejs/adapter-node';
|
||||||
import adapter from '@sveltejs/adapter-node';
|
// // import adapter from "@sveltejs/adapter-static";
|
||||||
// import adapter from "@sveltejs/adapter-static";
|
|
||||||
|
|
||||||
|
// import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||||
|
|
||||||
|
// /** @type {import('@sveltejs/kit').Config} */
|
||||||
|
// const config = {
|
||||||
|
// // Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||||
|
// // for more information about preprocessors
|
||||||
|
// preprocess: vitePreprocess(),
|
||||||
|
// kit: {
|
||||||
|
// adapter: adapter({
|
||||||
|
// // This option specifies the output directory for the build
|
||||||
|
// out: 'build'
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export default config;
|
||||||
|
import adapter from '@sveltejs/adapter-static'; // Change this line
|
||||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
|
||||||
// for more information about preprocessors
|
|
||||||
preprocess: vitePreprocess(),
|
preprocess: vitePreprocess(),
|
||||||
kit: {
|
kit: {
|
||||||
adapter: adapter({
|
adapter: adapter({
|
||||||
// This option specifies the output directory for the build
|
pages: 'build',
|
||||||
out: 'build'
|
assets: 'build',
|
||||||
|
fallback: 'index.html',
|
||||||
|
precompress: true // Enable Brotli & Gzip precompression
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
@ -10,6 +10,6 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 3005
|
port: 3000
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,34 +9,34 @@ primary_region = 'sea'
|
||||||
[build]
|
[build]
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
PORT = '8080'
|
PORT = '8080'
|
||||||
|
|
||||||
[http_service]
|
[http_service]
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
force_https = true
|
force_https = true
|
||||||
auto_stop_machines = 'stop'
|
auto_stop_machines = 'off'
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
min_machines_running = 0
|
min_machines_running = 0
|
||||||
processes = ['app']
|
processes = ['app']
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = 'tcp'
|
protocol = 'tcp'
|
||||||
internal_port = 8080
|
internal_port = 8080
|
||||||
|
|
||||||
[[services.ports]]
|
[[services.ports]]
|
||||||
port = 80
|
port = 80
|
||||||
handlers = ['http']
|
handlers = ['http']
|
||||||
|
|
||||||
[[services.ports]]
|
[[services.ports]]
|
||||||
port = 443
|
port = 443
|
||||||
handlers = ['tls', 'http']
|
handlers = ['tls', 'http']
|
||||||
|
|
||||||
[[services.tcp_checks]]
|
[[services.tcp_checks]]
|
||||||
interval = '10s'
|
interval = '10s'
|
||||||
timeout = '2s'
|
timeout = '2s'
|
||||||
grace_period = '5s'
|
grace_period = '5s'
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = 'shared'
|
cpu_kind = 'shared'
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const instructorRouter = require("./routes/InstructorRouter");
|
||||||
const studentRouter = require("./routes/StudentRouter");
|
const studentRouter = require("./routes/StudentRouter");
|
||||||
|
|
||||||
// require('dotenv').config(); // prisma client already loads .env apparently, double check before deploying
|
// require('dotenv').config(); // prisma client already loads .env apparently, double check before deploying
|
||||||
const port = process.env.NODE_PORT; // Use env for port
|
const port = process.env.NODE_PORT || 3000; // Use env for port
|
||||||
console.log('NODE_PORT:', port);
|
console.log('NODE_PORT:', port);
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
@ -19,6 +19,7 @@ app.use("/student", studentRouter);
|
||||||
app.use("/admin", adminRouter);
|
app.use("/admin", adminRouter);
|
||||||
app.use("/instructor", instructorRouter);
|
app.use("/instructor", instructorRouter);
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Server running at http://localhost:${port}`);
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
});
|
// app.listen(port, '0.0.0.0');
|
||||||
|
app.listen(3000, '::'); // im terrible i know - Bhav
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,27 @@ primary_region = "sea"
|
||||||
# processes = ["app"]
|
# processes = ["app"]
|
||||||
|
|
||||||
[[services]]
|
[[services]]
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
internal_port = 3000
|
internal_port = 3000
|
||||||
internal_only = true # Makes this service only accessible internally
|
internal_only = true # Makes this service only accessible internally
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
auto_stop_machines = true
|
auto_stop_machines = "off"
|
||||||
|
|
||||||
# Removed public port exposure
|
# Removed public port exposure
|
||||||
# [[services.ports]]
|
# [[services.ports]]
|
||||||
# port = 80
|
# port = 80
|
||||||
# handlers = ["http"]
|
# handlers = ["http"]
|
||||||
|
|
||||||
# [[services.ports]]
|
# [[services.ports]]
|
||||||
# port = 443
|
# port = 443
|
||||||
# handlers = ["tls", "http"]
|
# handlers = ["tls", "http"]
|
||||||
|
|
||||||
[services.concurrency]
|
[services.concurrency]
|
||||||
type = "requests"
|
type = "requests"
|
||||||
hard_limit = 1000
|
hard_limit = 1000
|
||||||
soft_limit = 500
|
soft_limit = 500
|
||||||
|
|
||||||
[[vm]]
|
[[vm]]
|
||||||
memory = '1gb'
|
memory = '1gb'
|
||||||
cpu_kind = "shared"
|
cpu_kind = "shared"
|
||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue