diff --git a/assignment-db-service/.env.development b/assignment-db-service/.env.development new file mode 100644 index 0000000..d370b34 --- /dev/null +++ b/assignment-db-service/.env.development @@ -0,0 +1,14 @@ +NODE_ENV=development + +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# 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 +DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost:15432/postgres?schema=public" + +# DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable" +# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable +NODE_PORT=3200 diff --git a/assignment-db-service/dev.env b/assignment-db-service/.env.test similarity index 97% rename from assignment-db-service/dev.env rename to assignment-db-service/.env.test index 1e00c54..b464239 100644 --- a/assignment-db-service/dev.env +++ b/assignment-db-service/.env.test @@ -1,3 +1,5 @@ +NODE_ENV=development + # Environment variables declared in this file are automatically made available to Prisma. # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema diff --git a/assignment-db-service/app.js b/assignment-db-service/app.js index 115c256..91d19be 100644 --- a/assignment-db-service/app.js +++ b/assignment-db-service/app.js @@ -10,33 +10,71 @@ const port = process.env.NODE_PORT || 3000; app.use(express.json()); app.use(express.urlencoded({ extended: true })); +async function encryptPassword(password) { + if (!password) { + return null; + } + + return new Promise((resolve, reject) => { + bcrypt.hash(password, 10, (err, hash) => { + if (err) { + reject(err); + } else { + resolve(hash); + } + }); + }); +} + //function to conver req.body to assignment -function convertToAssignment(req) { +async function convertToAssignment(req) { + console.log("Converting request body to assignment object..."); const { campid, programid, studentname, snakegameid, - originalfile, - editablefile, + appname, + qrcodenumber, + description, assignmenturl, password, instructorid } = req.body; - // 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, - }; + console.log("Request body fields:", { + campid, + programid, + studentname, + snakegameid, + appname, + qrcodenumber, + description, + assignmenturl, + password, + instructorid + }); + + const hashPassword = await encryptPassword(req.body.password); + + console.log("Password hash generated:", hashPassword); + + const assignment = { + campid: campid ? parseInt(campid) : null, + programid: programid ? parseInt(programid) : null, + studentname: studentname || null, + snakegameid: snakegameid || null, + appname: appname || null, + qrcodenumber: qrcodenumber ? parseInt(qrcodenumber) : null, + description: description || null, + assignmenturl: assignmenturl || null, + passwordhash: hashPassword || null, + instructorid: instructorid ? parseInt(instructorid) : null, + }; + + console.log("Converted assignment object:", assignment); + + return assignment; } // Create Assignment @@ -44,25 +82,11 @@ 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 assignment = await convertToAssignment(req); const newAssignment = await prisma.assignments.create({ - data: { - ...convertToAssignment(req) - }, + data: assignment, }); - + console.log("Assignment created successfully:", newAssignment); res.json({ @@ -82,6 +106,7 @@ app.get("/assignments/instructor/:instructorId", async (req, res) => { console.log("InstructorID:", instructorId); const assignments = await prisma.assignments.findMany({ where: { instructorid: parseInt(instructorId) }, + orderBy: { assignmentid: 'asc' }, }); if (assignments.length === 0) { @@ -97,17 +122,65 @@ app.get("/assignments/instructor/:instructorId", async (req, res) => { } }); -// Read Assignment +//Get assignment by assignmentid app.get("/assignments/:id", async (req, res) => { try { + const { id } = req.params; + console.log("Fetching assignment with ID:", id); + const assignment = await prisma.assignments.findUnique({ - where: { assignmentid: parseInt(req.params.id) }, + where: { assignmentid: parseInt(id) }, }); if (!assignment) { + console.log("No assignment found for ID:", id); return res.status(404).json({ message: "Assignment not found" }); } + console.log("Assignment found:", assignment); + res.json(assignment); + } catch (err) { + console.error("Error fetching assignment:", err.message); + res.status(500).json({ error: err.message }); + } +}); + +// Get Assignment by QR Code Number +app.get("/assignments/qr/:qrNumber", async (req, res) => { + try { + console.log("Fetching assignment with QR Code Number:", req.params.qrNumber); + + const assignment = await prisma.assignments.findUnique({ + where: { qrcodenumber: parseInt(req.params.qrNumber) }, + }); + + if (!assignment) { + console.log("No assignment found for QR Code Number:", req.params.qrNumber); + return res.status(404).json({ message: "Assignment not found" }); + } + + console.log("Assignment found:", assignment); + res.json(assignment); + } catch (err) { + console.error("Error fetching assignment:", err.message); + res.status(500).json({ error: err.message }); + } +}); + +//get assignment by appname +app.get("/assignments/appname/:appName", async (req, res) => { + try { + const { appName } = req.params; + const assignment = await prisma.assignments.findUnique({ + where: { appname: appName }, + }); + + if (!assignment) { + console.log("No assignment found for app name:", req.params.qrNumber); + return res.status(404).json({ message: "Assignment not found" }); + } + + console.log("Assignment found:", assignment); res.json(assignment); } catch (err) { console.error("Error fetching assignment:", err.message); @@ -119,17 +192,28 @@ app.get("/assignments/:id", async (req, res) => { app.put("/assignments/:id", async (req, res) => { try { const { id } = req.params; - const data = req.body; + const assignment = await convertToAssignment(req); - if (data.password) { - // data.passwordhash = await bcrypt.hash(data.Password, 10); - data.passwordhash = data.password; - delete data.password; + const existingAssignment = await prisma.assignments.findUnique({ + where: { assignmentid: parseInt(id) }, + }); + + if (!existingAssignment) { + return res.status(404).json({ message: "Assignment not found" }); } + // Update only the fields that are provided in the request body + Object.keys(assignment).forEach((key) => { + if (assignment[key]) { + existingAssignment[key] = assignment[key]; + } + }); + + console.log("Existing Assignment before update:", existingAssignment); + const updatedAssignment = await prisma.assignments.update({ where: { assignmentid: parseInt(id) }, - data, + data: existingAssignment, }); res.json({ @@ -161,3 +245,4 @@ app.delete("/assignments/:id", async (req, res) => { app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); + diff --git a/assignment-db-service/fly.toml b/assignment-db-service/fly.toml index 18fc89d..4f08c1f 100644 --- a/assignment-db-service/fly.toml +++ b/assignment-db-service/fly.toml @@ -7,26 +7,39 @@ app = 'db-assignment-service' primary_region = 'sea' [build] +# Only needed if you're using a Dockerfile — can be empty if using buildpacks or Node preset -[http_service] - internal_port = 3000 - force_https = true - auto_stop_machines = 'stop' - auto_start_machines = true - min_machines_running = 0 - processes = ['app'] +# Removed the [http_service] section to disable public HTTP/HTTPS access +# [http_service] +# internal_port = 3000 +# force_https = true +# auto_stop_machines = true +# auto_start_machines = true +# min_machines_running = 0 +# processes = ["app"] [[services]] - protocol = 'tcp' + protocol = "tcp" internal_port = 3000 - ports = [] + internal_only = true # Makes this service only accessible internally + auto_start_machines = true + auto_stop_machines = true + + # Removed public port exposure + # [[services.ports]] + # port = 80 + # handlers = ["http"] + + # [[services.ports]] + # port = 443 + # handlers = ["tls", "http"] [services.concurrency] - type = 'requests' + type = "requests" hard_limit = 1000 soft_limit = 500 [[vm]] memory = '1gb' - cpu_kind = 'shared' + cpu_kind = "shared" cpus = 1 diff --git a/assignment-db-service/package-lock.json b/assignment-db-service/package-lock.json index 1f1e538..c8e5c33 100644 --- a/assignment-db-service/package-lock.json +++ b/assignment-db-service/package-lock.json @@ -9,7 +9,410 @@ "bcrypt": "^5.1.1", "express": "^5.1.0", "nodemon": "^3.1.9", - "prisma": "^6.1.0" + "prisma": "^6.7.0" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, "node_modules/@mapbox/node-pre-gyp": { @@ -54,49 +457,59 @@ } } }, + "node_modules/@prisma/config": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.7.0.tgz", + "integrity": "sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==", + "license": "Apache-2.0", + "dependencies": { + "esbuild": ">=0.12 <1", + "esbuild-register": "3.6.0" + } + }, "node_modules/@prisma/debug": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.1.0.tgz", - "integrity": "sha512-0himsvcM4DGBTtvXkd2Tggv6sl2JyUYLzEGXXleFY+7Kp6rZeSS3hiTW9mwtUlXrwYbJP6pwlVNB7jYElrjWUg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.7.0.tgz", + "integrity": "sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==", "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.1.0.tgz", - "integrity": "sha512-GnYJbCiep3Vyr1P/415ReYrgJUjP79fBNc1wCo7NP6Eia0CzL2Ot9vK7Infczv3oK7JLrCcawOSAxFxNFsAERQ==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.7.0.tgz", + "integrity": "sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.1.0", - "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "@prisma/fetch-engine": "6.1.0", - "@prisma/get-platform": "6.1.0" + "@prisma/debug": "6.7.0", + "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", + "@prisma/fetch-engine": "6.7.0", + "@prisma/get-platform": "6.7.0" } }, "node_modules/@prisma/engines-version": { - "version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959.tgz", - "integrity": "sha512-PdJqmYM2Fd8K0weOOtQThWylwjsDlTig+8Pcg47/jszMuLL9iLIaygC3cjWJLda69siRW4STlCTMSgOjZzvKPQ==", + "version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed.tgz", + "integrity": "sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==", "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.1.0.tgz", - "integrity": "sha512-asdFi7TvPlEZ8CzSZ/+Du5wZ27q6OJbRSXh+S8ISZguu+S9KtS/gP7NeXceZyb1Jv1SM1S5YfiCv+STDsG6rrg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.7.0.tgz", + "integrity": "sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.1.0", - "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "@prisma/get-platform": "6.1.0" + "@prisma/debug": "6.7.0", + "@prisma/engines-version": "6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed", + "@prisma/get-platform": "6.7.0" } }, "node_modules/@prisma/get-platform": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.1.0.tgz", - "integrity": "sha512-ia8bNjboBoHkmKGGaWtqtlgQOhCi7+f85aOkPJKgNwWvYrT6l78KgojLekE8zMhVk0R9lWcifV0Pf8l3/15V0Q==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.7.0.tgz", + "integrity": "sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.1.0" + "@prisma/debug": "6.7.0" } }, "node_modules/abbrev": { @@ -377,6 +790,21 @@ "node": ">=6.6.0" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -418,6 +846,45 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-cli": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-8.0.0.tgz", + "integrity": "sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -483,6 +950,58 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" + } + }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -912,6 +1431,13 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -999,6 +1525,16 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -1211,6 +1747,16 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -1233,13 +1779,14 @@ } }, "node_modules/prisma": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.1.0.tgz", - "integrity": "sha512-aFI3Yi+ApUxkwCJJwyQSwpyzUX7YX3ihzuHNHOyv4GJg3X5tQsmRaJEnZ+ZyfHpMtnyahhmXVfbTZ+lS8ZtfKw==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.7.0.tgz", + "integrity": "sha512-vArg+4UqnQ13CVhc2WUosemwh6hr6cr6FY2uzDvCIFwH8pu8BXVv38PktoMLVjtX7sbYThxbnZF5YiR8sN2clw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "6.1.0" + "@prisma/config": "6.7.0", + "@prisma/engines": "6.7.0" }, "bin": { "prisma": "build/index.js" @@ -1249,6 +1796,14 @@ }, "optionalDependencies": { "fsevents": "2.3.3" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/proxy-addr": { @@ -1454,6 +2009,29 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -1713,6 +2291,22 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", diff --git a/assignment-db-service/package.json b/assignment-db-service/package.json index ca9db41..f78b946 100644 --- a/assignment-db-service/package.json +++ b/assignment-db-service/package.json @@ -4,10 +4,13 @@ "bcrypt": "^5.1.1", "express": "^5.1.0", "nodemon": "^3.1.9", - "prisma": "^6.1.0" + "prisma": "^6.7.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "nodemon app.js" + "dev": "dotenv -e .env.development nodemon app.js" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" } } diff --git a/assignment-db-service/prisma/schema.prisma b/assignment-db-service/prisma/schema.prisma index 0a18c40..4d1a053 100644 --- a/assignment-db-service/prisma/schema.prisma +++ b/assignment-db-service/prisma/schema.prisma @@ -14,9 +14,10 @@ model assignments { programid Int? studentname String? snakegameid String? - originalfile String? - editablefile String? - assignmenturl String? + qrcodenumber Int? @unique + appname String? @unique + description String? passwordhash String? // store bcrypt hash + assignmenturl String? instructorid Int? } diff --git a/assignment-service/.env b/assignment-service/.env index b948690..f5f5b51 100644 --- a/assignment-service/.env +++ b/assignment-service/.env @@ -1,2 +1,3 @@ -#DB_ASSIGNMENT_SERVICE_URL = "http://localhost:3000" DB_ASSIGNMENT_SERVICE_URL = "http://db-assignment-service.internal:3000" +DEPLOY_API_URL="http://localhost:3006" +NODE_PORT = 8080 \ No newline at end of file diff --git a/assignment-service/.env.development b/assignment-service/.env.development new file mode 100644 index 0000000..b683362 --- /dev/null +++ b/assignment-service/.env.development @@ -0,0 +1,11 @@ +NODE_ENV=development +DB_ASSIGNMENT_SERVICE_URL="http://localhost:3200" +DEPLOY_API_URL="http://127.0.0.1:3006" + +AWS_ACCESS_KEY_ID='tid__NSmOVaGknqitaCySppZjqVTgJSdDFnFbWcQllkC_juHwkbQZO' +AWS_ENDPOINT_URL_S3='https://fly.storage.tigris.dev' +AWS_REGION='auto' +AWS_SECRET_ACCESS_KEY='tsec_6Bz1aMbfYQftuq5WfIVEDZkHwskU4MMjVywdtxSP6uxetEBvkSC2VHI9HfTeDgHr4D6kiz' +COMMON_BUCKET='snakeapi-deployment-test-bucket' + +NODE_PORT=8082 \ No newline at end of file diff --git a/assignment-service/.env.test b/assignment-service/.env.test new file mode 100644 index 0000000..fd1e4e1 --- /dev/null +++ b/assignment-service/.env.test @@ -0,0 +1,4 @@ +NODE_ENV=test +DB_ASSIGNMENT_SERVICE_URL="http://js-assignment-db-service:3200" +DEPLOY_API_URL="http://localhost:3006/deploy" +NODE_PORT=8082 \ No newline at end of file diff --git a/assignment-service/dev.env b/assignment-service/dev.env deleted file mode 100644 index c457dfa..0000000 --- a/assignment-service/dev.env +++ /dev/null @@ -1,5 +0,0 @@ -#DB_ASSIGNMENT_SERVICE_URL="http://localhost: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 \ No newline at end of file diff --git a/assignment-service/package-lock.json b/assignment-service/package-lock.json index a86b84f..d8dba1c 100644 --- a/assignment-service/package-lock.json +++ b/assignment-service/package-lock.json @@ -11,14 +11,45 @@ "dependencies": { "aws-sdk": "^2.1692.0", "axios": "^1.9.0", + "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", "express-session": "^1.18.1", + "multer": "^1.4.5-lts.2", "nodemon": "^3.1.9", "passport": "^0.7.0" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -32,6 +63,44 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -45,6 +114,46 @@ "node": ">= 8" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -125,6 +234,20 @@ ], "license": "MIT" }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -207,6 +330,23 @@ "isarray": "^1.0.0" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -287,6 +427,24 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -305,6 +463,27 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" + }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -344,6 +523,12 @@ "node": ">=6.6.0" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -357,6 +542,21 @@ "node": ">= 0.10" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -398,6 +598,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -407,6 +613,15 @@ "node": ">= 0.8" } }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/dotenv": { "version": "16.5.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", @@ -419,6 +634,32 @@ "url": "https://dotenvx.com" } }, + "node_modules/dotenv-cli": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-8.0.0.tgz", + "integrity": "sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -439,6 +680,12 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -736,20 +983,36 @@ "node": ">= 0.8" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 8" } }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -759,6 +1022,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -796,6 +1080,27 @@ "node": ">= 0.4" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -868,6 +1173,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -896,6 +1207,36 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -920,6 +1261,17 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "license": "ISC" }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -984,6 +1336,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -1068,6 +1429,13 @@ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/jmespath": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", @@ -1077,6 +1445,24 @@ "node": ">= 0.6.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1140,12 +1526,140 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multer": { + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -1155,6 +1669,32 @@ "node": ">= 0.6" } }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/nodemon": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", @@ -1200,6 +1740,21 @@ } } }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1209,6 +1764,19 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1295,6 +1863,25 @@ "node": ">= 0.4.0" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -1330,6 +1917,12 @@ "node": ">= 0.4" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1418,6 +2011,36 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1430,6 +2053,22 @@ "node": ">=8.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -1578,6 +2217,12 @@ "node": ">= 18" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -1601,6 +2246,29 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -1673,6 +2341,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1694,6 +2368,49 @@ "node": ">= 0.8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1706,6 +2423,23 @@ "node": ">=4" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1736,6 +2470,12 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -1750,6 +2490,12 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -1800,6 +2546,12 @@ "which-typed-array": "^1.1.2" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1827,6 +2579,38 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/which-typed-array": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", @@ -1848,6 +2632,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1875,6 +2668,21 @@ "engines": { "node": ">=4.0" } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" } } } diff --git a/assignment-service/package.json b/assignment-service/package.json index 91ad99e..c4df28e 100644 --- a/assignment-service/package.json +++ b/assignment-service/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "server.js", "scripts": { - "dev": "nodemon server.js" + "dev": "dotenv -e .env.development nodemon server.js" }, "keywords": [], "author": "", @@ -12,11 +12,16 @@ "dependencies": { "aws-sdk": "^2.1692.0", "axios": "^1.9.0", + "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", "express-session": "^1.18.1", + "multer": "^1.4.5-lts.2", "nodemon": "^3.1.9", "passport": "^0.7.0" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" } } diff --git a/assignment-service/routes/InstructorRouter.js b/assignment-service/routes/InstructorRouter.js index c3a6d01..22777ca 100644 --- a/assignment-service/routes/InstructorRouter.js +++ b/assignment-service/routes/InstructorRouter.js @@ -1,31 +1,75 @@ const intructorRouter = require("express").Router(); const passport = require("passport"); const axios = require("axios"); +const multer = require("multer"); +const FormData = require("form-data"); + +const DB_ASSIGNMENT_SERVICE_URL = + process.env.DB_ASSIGNMENT_SERVICE_URL || "http://localhost:3000"; + +const DEPLOY_API_URL = process.env.DEPLOY_API_URL || "http://localhost:3600"; -const DB_ASSIGNMENT_SERVICE_URL = process.env.DB_ASSIGNMENT_SERVICE_URL || "http://localhost:3000"; console.log("DB_ASSIGNMENT_SERVICE_URL:", DB_ASSIGNMENT_SERVICE_URL); +console.log("DEPLOY_API_URL:", DEPLOY_API_URL); + +// Use memory storage to keep file in RAM +const upload = multer({ storage: multer.memoryStorage() }); // This endpoint is for instructors to create a new assignment -intructorRouter.post("/create", - // passport.authenticate("jwt", { session: false }), +intructorRouter.post( + "/create", + upload.single("file"), + // passport.authenticate("jwt", { session: false }), async (req, res) => { - try { - console.log("Creating a new assignment with data:", 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); - } catch (error) { - console.error("Error creating assignment:", error.message); - res.status(error.response?.status || 500).json({ error: error.message }); + try { + const file = req.file; + const assignmentData = req.body; + + if (!file) { + return res.status(400).send("No file uploaded."); + } + + console.log("Creating a new assignment with data:", req.body); + const response = await axios.post( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments`, + req.body + ); + console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data); + + // call upload api to upload the file to S3 + console.log("Uploading file to:", `${DEPLOY_API_URL}/${assignmentData.appname}/upload`); + const uploadResponse = await axios.post(`${DEPLOY_API_URL}/${assignmentData.appname}/upload`, { + "appName": assignmentData.appname, + "notebookName": file.originalname, + "fileContentBase64": file.buffer.toString('base64'), + }); + console.log('Response from DEPLOY_API_URL:', uploadResponse.data); + + // Deploy a new Battlesnake API + console.log('Deploying a new Battlesnake API'); + console.log("DEPLOY_API_URL:", DEPLOY_API_URL, assignmentData.appname); + const deployResponse = await axios.post(`${DEPLOY_API_URL}/deploy`, { + "appName": assignmentData.appname + }); + console.log('Response from DEPLOY_API_URL:', deployResponse.data); + + res.status(response.status).json(response.data); + } 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}`); + 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) { @@ -35,48 +79,134 @@ intructorRouter.get("/details/:id", async (req, res) => { }); // This endpoint is for instructors to get a list of assignments they have created -intructorRouter.get("/list/:id", async (req, res) => { - // if (req.isAuthenticated()) { +intructorRouter.get( + "/list/:id", + // passport.authenticate("jwt", { session: false }), + async (req, res) => { + // if (req.isAuthenticated()) { try { 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}`); - console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data); + // console.log("Fetching assignments for instructorId:", 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); } catch (error) { res.status(error.response?.status || 500).json({ error: error.message }); } - // } else { - // return res.status(401).json({ error: "Not authenticated" }); - // } - -}); + // } else { + // return res.status(401).json({ error: "Not authenticated" }); + // } + } +); // This endpoint is for instructors to update an assignment -intructorRouter.put("/update/:id", - // passport.authenticate("jwt", { session: false }), +intructorRouter.put( + "/update/:id", + upload.none(), // No file upload for this endpoint + // passport.authenticate("jwt", { session: false }), async (req, res) => { - try { - const assignmentId = req.params.id; - const response = await axios.put(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`, req.body); - res.status(response.status).json(response.data); - } catch (error) { - res.status(error.response?.status || 500).json({ error: error.message }); + try { + const assignmentId = req.params.id; + console.log("Updating assignment with ID:", assignmentId); + console.log("Request body:", req.body); + + const response = await axios.put( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`, + req.body + ); + + console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data); + res.status(response.status).json(response.data); + } catch (error) { + console.error("Error updating assignment:", error.message); + res.status(error.response?.status || 500).json({ error: error.message }); + } } -}); +); // This endpoint is for instructors to delete an assignment -intructorRouter.delete("/delete/:id", - // passport.authenticate("jwt", { session: false }), +intructorRouter.delete( + "/delete/:id", + // passport.authenticate("jwt", { session: false }), async (req, res) => { - try { - const assignmentId = req.params.id; - const response = await axios.delete(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`); - res.status(response.status).json(response.data); - } catch (error) { - res.status(error.response?.status || 500).json({ error: error.message }); - } -}); + try { -module.exports = intructorRouter; \ No newline at end of file + const assignmentId = req.params.id; + + //get the assignment data from the database + console.log("Fetching assignment data for ID:", assignmentId); + const assignmentResponse = await axios.get( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}` + ); + const assignmentData = assignmentResponse.data; + console.log("Assignment data:", assignmentData); + + if (!assignmentData) { + return res.status(404).json({ error: "Assignment not found" }); + } + + // Delete the Battlesnake API + console.log('Deploying a new Battlesnake API'); + console.log("DEPLOY_API_URL:", DEPLOY_API_URL, assignmentData.appname); + const deployResponse = await axios.post(`${DEPLOY_API_URL}/${assignmentData.appname}/delete`, { + "appName": assignmentData.appname + }); + //throw error if the response is not 200 + if (deployResponse.status !== 200) { + throw new Error(`Failed to delete Battlesnake API: ${deployResponse.statusText}`); + } + console.log('Response from DEPLOY_API_URL:', deployResponse.data); + + const response = await axios.delete( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}` + ); + res.status(response.status).json(response.data); + } catch (error) { + res.status(error.response?.status || 500).json({ error: error.message }); + } + } +); + +//get assignment by appname +intructorRouter.get( + "/checkAssignmentByAppName/:appName", + // passport.authenticate("jwt", { session: false }), + async (req, res) => { + try { + const appName = req.params.appName; + console.log("Fetching assignment for appName:", appName); + const response = await axios.get( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/appname/${appName}` + ); + console.log("Response data:", response.data); + res.status(response.status).json({"exists": (response.data !== null && response.data !== undefined)}); + } catch (error) { + console.error("Error fetching assignment by app name:", error.message); + res.status(error.response?.status || 500).json({ error: error.message }); + } + } +); + +//get assignment by qrcode number +intructorRouter.get( + "/checkAssignmentByQRCode/:qrcode", + // passport.authenticate("jwt", { session: false }), + async (req, res) => { + try { + const qrcode = req.params.qrcode; + console.log("Fetching assignment for qrcode:", qrcode); + const response = await axios.get( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/${qrcode}` + ); + console.log("Response data:", response.data); + res.status(response.status).json({"exists": (response.data !== null && response.data !== undefined)}); + } catch (error) { + console.error("Error fetching assignment by QR code:", error.message); + res.status(error.response?.status || 500).json({ error: error.message }); + } + } +); + +module.exports = intructorRouter; diff --git a/assignment-service/routes/StudentRouter.js b/assignment-service/routes/StudentRouter.js index 63f07a2..947820c 100644 --- a/assignment-service/routes/StudentRouter.js +++ b/assignment-service/routes/StudentRouter.js @@ -1,13 +1,71 @@ const studentRouter = require("express").Router(); const passport = require("passport"); const axios = require("axios"); +const bcrypt = require("bcrypt"); +require("dotenv").config(); +const DB_ASSIGNMENT_SERVICE_URL = process.env.DB_ASSIGNMENT_SERVICE_URL; -studentRouter.post("/save", (req, res) => { - + +studentRouter.post("/save", (req, res) => {}); + +studentRouter.post("/deploy", (req, res) => {}); + +studentRouter.get("/assignment/:qrnum", (req, res) => { + const qrnum = req.params.qrnum; + console.log("Fetching details for qr number:", qrnum); + axios + .get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/qr/${qrnum}`) + .then((response) => { + 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 }); + }); }); -studentRouter.post("/deploy", (req, res) => { - +studentRouter.post("/verify", async (req, res) => { + try { + const qrNumber = req.body.qrNumber; + const password = req.body.password; + console.log("Received request to verify assignment."); + console.log("Request body:", req.body); + console.log( + "Accessing assignment with QR Number:", + qrNumber, + "and password:", + password + ); + + console.log(`Fetching from URL: ${DB_ASSIGNMENT_SERVICE_URL}/assignments/${qrNumber}`); + const response = await axios.get( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments/qr/${qrNumber}` + ); + + console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data); + console.log("Password provided:", password); + console.log("Password hash from database:", response.data.passwordhash); + + const isPasswordValid = await bcrypt.compare( + password, + response.data.passwordhash + ); + + console.log("Password validation result:", isPasswordValid); + + if (!isPasswordValid || !response.data) { + console.log("Invalid id or password."); + return res.status(401).json({ error: "Invalid id and password" }); + } + + console.log("Verification successful. Sending response."); + res.status(response.status).json(response.data); + } catch (error) { + console.error("Error fetching assignment details:", error.message); + console.error("Error details:", error); + res.status(error.response?.status || 500).json({ error: error.message }); + } }); -module.exports = studentRouter; \ No newline at end of file +module.exports = studentRouter; diff --git a/assignment-service/server.js b/assignment-service/server.js index 2731cfc..b20c3eb 100644 --- a/assignment-service/server.js +++ b/assignment-service/server.js @@ -70,5 +70,5 @@ app.get("/notebook/:appName", async (req, res) => { } }); -const port = process.env.PORT || 8080; -app.listen(port, "0.0.0.0", () => console.log(`Listening on 0.0.0.0:${port}...`)); +const port = process.env.NODE_PORT || 8080; +app.listen({ port: port, host: '::', ipv6Only: false }, () => console.log(`Listening on ${port}...`)); diff --git a/auth-service/.env b/auth-service/.env index 4fe65d0..75d4e76 100644 --- a/auth-service/.env +++ b/auth-service/.env @@ -2,10 +2,11 @@ GOOGLE_CLIENT_ID = "485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleuse GOOGLE_CLIENT_SECRET = "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" GOOGLE_CALLBACK_URL = "https://byte-camp-auth-service.fly.dev/auth/google/callback" LOGIN_REDIRECT_URL = "https://bytecamp-web.fly.dev/" -ACCEPTED_ORIGINS ="https://bytecamp-web.fly.dev,https://byte-camp-auth-service.fly.dev" +ACCEPTED_ORIGINS ="https://bytecamp-web.fly.dev,https://byte-camp-auth-service.fly.dev,http://localhost:5173" #DB_USER_SERVICE_URL = "http://localhost:3000/" DB_USER_SERVICE_URL = "http://db-user-service.internal:3000/" AUTH_SESSION_KEY = "f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42" +ASSIGNMENT_SERVICE_URL="http://assignment-service.internal:8080" # fly secrets set GOOGLE_CALLBACK_URL=https://byte-camp-auth-service.fly.dev/auth/google/callback #fly secrets set GOOGLE_CLIENT_ID=485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=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 LOGIN_REDIRECT_URL=https://bytecamp-web.fly.dev/ DB_USER_SERVICE_URL=https://db-user-service.fly.dev:3000/ AUTH_SESSION_KEY=f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42 \ No newline at end of file diff --git a/auth-service/dev.env b/auth-service/.env.development similarity index 80% rename from auth-service/dev.env rename to auth-service/.env.development index 794749f..5fd061d 100644 --- a/auth-service/dev.env +++ b/auth-service/.env.development @@ -1,8 +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 -DB_USER_SERVICE_URL="http://js-user-db-service:3100/" +ASSIGNMENT_SERVICE_URL="http://localhost:8082" +DB_USER_SERVICE_URL="http://localhost:3100/" AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42" PORT=8080 \ No newline at end of file diff --git a/auth-service/package-lock.json b/auth-service/package-lock.json index 495b39d..26d2726 100644 --- a/auth-service/package-lock.json +++ b/auth-service/package-lock.json @@ -16,7 +16,11 @@ "express-session": "^1.18.1", "nodemon": "^3.1.9", "passport": "^0.7.0", + "passport-custom": "^1.1.1", "passport-google-oauth20": "^2.0.0" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" } }, "node_modules/accepts": { @@ -280,6 +284,21 @@ "node": ">= 0.10" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -325,6 +344,32 @@ "url": "https://dotenvx.com" } }, + "node_modules/dotenv-cli": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-8.0.0.tgz", + "integrity": "sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -847,6 +892,13 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -910,6 +962,16 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1063,6 +1125,18 @@ "url": "https://github.com/sponsors/jaredhanson" } }, + "node_modules/passport-custom": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/passport-custom/-/passport-custom-1.1.1.tgz", + "integrity": "sha512-/2m7jUGxmCYvoqenLB9UrmkCgPt64h8ZtV+UtuQklZ/Tn1NpKBeOorCYkB/8lMRoiZ5hUrCoMmDtxCS/d38mlg==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/passport-google-oauth20": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", @@ -1103,6 +1177,16 @@ "node": ">= 0.4.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -1345,6 +1429,29 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -1545,6 +1652,22 @@ "node": ">= 0.8" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/auth-service/package.json b/auth-service/package.json index 14d0810..2d95f65 100644 --- a/auth-service/package.json +++ b/auth-service/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "server.js", "scripts": { - "dev": "nodemon server.js" + "dev": "dotenv -e .env.development nodemon server.js" }, "keywords": [], "author": "", @@ -17,6 +17,10 @@ "express-session": "^1.18.1", "nodemon": "^3.1.9", "passport": "^0.7.0", + "passport-custom": "^1.1.1", "passport-google-oauth20": "^2.0.0" + }, + "devDependencies": { + "dotenv-cli": "^8.0.0" } } diff --git a/auth-service/passport.js b/auth-service/passport.js index e65e7c8..e04adb9 100644 --- a/auth-service/passport.js +++ b/auth-service/passport.js @@ -1,36 +1,78 @@ -require('dotenv').config(); +require("dotenv").config(); const GoogleStrategy = require("passport-google-oauth20").Strategy; const passport = require("passport"); +const CustomStrategy = require("passport-custom").Strategy; +const axios = require("axios"); passport.use( - new GoogleStrategy( + new GoogleStrategy( + { + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: process.env.GOOGLE_CALLBACK_URL, + scope: ["profile", "email"], + }, + function (accessToken, refreshToken, profile, callback) { + callback(null, {...profile, role: "instructor"}); + } + ) +); + +passport.use( + "student-auth", + new CustomStrategy(async (req, done) => { + const { qrNumber, password } = req.body; + + console.log("Custom strategy invoked"); + console.log("Received qrNumber:", qrNumber); + console.log("Received password:", password); + + try { + console.log("Sending request to external auth service..."); + const response = await axios.post( + `${process.env.ASSIGNMENT_SERVICE_URL}/student/verify`, { - clientID: process.env.GOOGLE_CLIENT_ID, - clientSecret: process.env.GOOGLE_CLIENT_SECRET, - callbackURL: process.env.GOOGLE_CALLBACK_URL, - scope: ["profile", "email"], - }, - function (accessToken, refreshToken, profile, callback) { - - // Save the user info to your DB here if still not yet saved - // Example of what profile might contain: - // { - // "id": "112233445566778899", - // "displayName": "John Doe", - // "emails": [{ "value": "john.doe@gmail.com" }], - // "photos": [{ "value": "https://.../photo.jpg" }] - // } - - callback(null, profile); + qrNumber, + password, } - ) + ); + + if (response.status === 200 && response.data) { + user = { + ...response.data, + role: "student", + }; + console.log("Authentication successful, user:", user); + return done(null, user); // success + } else { + console.log("Authentication failed: Invalid credentials"); + return done(null, false, { message: "Invalid credentials" }); + } + } catch (err) { + console.error("Error during authentication:", err); + return done(err); + } + }) ); passport.serializeUser((user, done) => { - done(null, user); + // done(null, user); + console.log("Serializing user:", user); + done(null, { + userId: user.qrcodenumber || user.id, + displayName: user.studentname || user.displayName, + role: user.role, + emails: user.emails || "none", + }); }); -passport.deserializeUser((user, done) => { - done(null,user); -}); \ No newline at end of file +passport.deserializeUser(async (user, done) => { + try { + console.log("Deserializing user:", user); + done(null, user); + } catch (err) { + console.error("Error during deserialization:", err); + done(err); + } +}); diff --git a/auth-service/routes/auth.js b/auth-service/routes/auth.js index 782d09c..05d5f63 100644 --- a/auth-service/routes/auth.js +++ b/auth-service/routes/auth.js @@ -11,6 +11,8 @@ router.get( ); router.get("/current_user", (req, res) => { + console.log("Current user endpoint hit"); + console.log("Request user:", req.user); if (req.isAuthenticated()) { console.log("Authenticated user:", req.user); res.json(req.user); @@ -52,9 +54,47 @@ router.get("/login/failed", (req, res) => { router.get("/google", passport.authenticate("google", ["profile", "email"])); +router.post( + "/student/login", + passport.authenticate("student-auth"), + (req, res) => { + console.log("Student login endpoint hit"); + + if (req.user) { + console.log("Authenticated user:", req.user); + console.log("Processing student login..."); + + // Optional: augment user object (doesn't affect session unless you reserialize) + req.user.userId = req.user.assignmentid; + req.user.role = "student"; + + req.logIn(req.user, function(err) { + if (err) return next(err); + + console.log('is authenticated?: ' + req.isAuthenticated()); + + return res.status(200).json({ + success: true, + message: 'Successful Login', + user: req.user + }); + }); + + } else { + console.log("Authentication failed"); + res.status(401).json({ error: true, message: "Authentication failed" }); + } + } +); + router.get("/logout", (req, res) => { - req.logOut(); - res.redirect(process.env.LOGIN_REDIRECT_URL); + + req.logout((err) => { + if (err) { + return next(err); + } + res.redirect(process.env.LOGIN_REDIRECT_URL); + }); }); module.exports = router; diff --git a/auth-service/server.js b/auth-service/server.js index 8e92dce..924dfac 100644 --- a/auth-service/server.js +++ b/auth-service/server.js @@ -6,10 +6,14 @@ const passport = require("passport"); const passportSetup = require("./passport"); const authRoute = require("./routes/auth"); const session = require("express-session"); +const bodyParser = require("body-parser"); const app = express(); +app.use(bodyParser.json()); // or express.json() +app.use(bodyParser.urlencoded({ extended: true })); app.use( + session({ secret: process.env.AUTH_SESSION_KEY, resave: false, @@ -31,6 +35,8 @@ app.use( }) ) +app.use(express.json()); + app.use("/auth", authRoute); const port = process.env.PORT || 8080; diff --git a/compose.yaml b/compose.yaml index 99c6a2d..41c59e6 100644 --- a/compose.yaml +++ b/compose.yaml @@ -11,7 +11,7 @@ services: ports: - "3200:3200" # Expose port to the same host env_file: - - ./assignment-db-service/dev.env + - ./assignment-db-service/.env.development networks: - backend @@ -25,7 +25,7 @@ services: ports: - "8082:8082" # Expose port to the same host env_file: - - ./assignment-service/dev.env + - ./assignment-service/.env.development depends_on: - js-assignment-db-service networks: @@ -41,7 +41,7 @@ services: ports: - "8080:8080" # Expose port to the same host env_file: - - ./auth-service/dev.env + - ./auth-service/.env.development networks: - backend @@ -55,7 +55,7 @@ services: ports: - "3100:3100" # Expose port to the same host env_file: - - ./user-db-service/dev.env + - ./user-db-service/.env.development networks: - backend diff --git a/deployment-service/src/index.js b/deployment-service/src/index.js index 433392a..1467d13 100644 --- a/deployment-service/src/index.js +++ b/deployment-service/src/index.js @@ -1,8 +1,9 @@ -const express = require('express'); -const fs = require('fs'); -const path = require('path'); -const AWS = require('aws-sdk'); -const axios = require('axios'); +const express = require("express"); +const fs = require("fs"); +const path = require("path"); +const AWS = require("aws-sdk"); +const axios = require("axios"); +require("dotenv").config(); const { FLY_ORG, @@ -12,47 +13,56 @@ const { AWS_ENDPOINT_URL_S3, AWS_REGION, FLY_ACCESS_TOKEN, - IMAGE_REF + IMAGE_REF, } = process.env; // Log environment variables for debugging -console.log('--- ENV START ---'); -console.log('FLY_ORG: ', FLY_ORG); -console.log('COMMON_BUCKET: ', COMMON_BUCKET); -console.log('AWS_ACCESS_KEY_ID: ', AWS_ACCESS_KEY_ID ? '(found)' : '(NOT SET)'); -console.log('AWS_SECRET_ACCESS_KEY:', AWS_SECRET_ACCESS_KEY ? '(found)' : '(NOT SET)'); -console.log('AWS_ENDPOINT_URL_S3: ', AWS_ENDPOINT_URL_S3); -console.log('AWS_REGION: ', AWS_REGION); -console.log('FLY_ACCESS_TOKEN: ', FLY_ACCESS_TOKEN ? '(found)' : '(NOT SET)'); -console.log('IMAGE_REF: ', IMAGE_REF); -console.log('--- ENV END ---'); +console.log("--- ENV START ---"); +console.log("FLY_ORG: ", FLY_ORG); +console.log("COMMON_BUCKET: ", COMMON_BUCKET); +console.log( + "AWS_ACCESS_KEY_ID: ", + AWS_ACCESS_KEY_ID ? "(found)" : "(NOT SET)" +); +console.log( + "AWS_SECRET_ACCESS_KEY:", + AWS_SECRET_ACCESS_KEY ? "(found)" : "(NOT SET)" +); +console.log("AWS_ENDPOINT_URL_S3: ", AWS_ENDPOINT_URL_S3); +console.log("AWS_REGION: ", AWS_REGION); +console.log( + "FLY_ACCESS_TOKEN: ", + FLY_ACCESS_TOKEN ? "(found)" : "(NOT SET)" +); +console.log("IMAGE_REF: ", IMAGE_REF); +console.log("--- ENV END ---"); // Initialize S3 client const s3 = new AWS.S3({ endpoint: AWS_ENDPOINT_URL_S3, region: AWS_REGION, credentials: new AWS.Credentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), - s3ForcePathStyle: true + s3ForcePathStyle: true, }); // Create Fly Machines API client function createFlyClient() { return axios.create({ - baseURL: 'https://api.machines.dev/v1', + baseURL: "https://api.machines.dev/v1", headers: { Authorization: `Bearer ${FLY_ACCESS_TOKEN}`, - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }); } // Create Fly GraphQL client (for IP allocation) const gqlClient = axios.create({ - baseURL: 'https://api.fly.io/graphql', + baseURL: "https://api.fly.io/graphql", headers: { Authorization: `Bearer ${FLY_ACCESS_TOKEN}`, - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }); // Define GraphQL mutation for IP allocation @@ -68,164 +78,175 @@ mutation AllocateIp($input: AllocateIPAddressInput!) { `; const app = express(); -app.use(express.json({ limit: '10mb' })); +app.use(express.json({ limit: "10mb" })); -app.post('/deploy', async (req, res) => { - console.log('Received /deploy:', req.body); - const { appName, region, notebookName } = req.body; - if (!appName || !notebookName) { - return res.status(400).json({ error: 'appName and notebookName required' }); +app.post("/deploy", async (req, res) => { + console.log("Received /deploy:", req.body); + const { + appName, + // , region + // , notebookName + } = req.body; + if (!appName) { + return res.status(400).json({ error: "appName required" }); } - const notebookPath = path.join(__dirname, '../snakeapi_service/notebooks', notebookName); - console.log('Resolved notebookPath:', notebookPath); - if (!fs.existsSync(notebookPath)) { - console.error('Notebook not found at:', notebookPath); - return res.status(500).json({ error: `Notebook not found: ${notebookPath}` }); - } + // const notebookPath = path.join(__dirname, '../snakeapi_service/notebooks', notebookName); + // console.log('Resolved notebookPath:', notebookPath); + // if (!fs.existsSync(notebookPath)) { + // console.error('Notebook not found at:', notebookPath); + // return res.status(500).json({ error: `Notebook not found: ${notebookPath}` }); + // } try { const fly = createFlyClient(); - console.log('Creating Fly app:', appName); - await fly.post('/apps', { + console.log("Creating Fly app:", appName); + await fly.post("/apps", { app_name: appName, org_slug: FLY_ORG, - primary_region: region + primary_region: "sea", }); - console.log('Uploading notebook to S3'); - const data = fs.readFileSync(notebookPath); - const key = `${appName}/notebooks/${Date.now()}-notebook.ipynb`; - console.log('S3 key:', key); - await s3.putObject({ - Bucket: COMMON_BUCKET, - Key: key, - Body: data, - ContentType: 'application/json' - }).promise(); + // console.log('Uploading notebook to S3'); + // const data = fs.readFileSync(notebookPath); + // const key = `${appName}/notebooks/${Date.now()}-notebook.ipynb`; + // console.log('S3 key:', key); + // await s3.putObject({ + // Bucket: COMMON_BUCKET, + // Key: key, + // Body: data, + // ContentType: 'application/json' + // }).promise(); - console.log('Creating machine'); + console.log("Creating machine"); const machineConfig = { name: `${appName}-machine`, - region: 'sea', + region: "sea", count: 1, - vm_size: 'shared-cpu-1x', + vm_size: "shared-cpu-1x", autostart: true, config: { image: IMAGE_REF, env: { INSTANCE_PREFIX: appName, - NOTEBOOK_KEY: key, + // NOTEBOOK_KEY: key, COMMON_BUCKET: COMMON_BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ENDPOINT_URL_S3, - AWS_REGION + AWS_REGION, }, http_service: { internal_port: 8000, force_https: true, - auto_stop_machines: 'stop', + auto_stop_machines: "stop", auto_start_machines: true, min_machines_running: 0, - processes: ['app'] + processes: ["app"], }, services: [ { - protocol: 'tcp', + protocol: "tcp", internal_port: 8000, ports: [ - { port: 443, handlers: ['tls', 'http'] }, - { port: 80, handlers: ['http'] } - ] - } + { port: 443, handlers: ["tls", "http"] }, + { port: 80, handlers: ["http"] }, + ], + }, ], guest: { memory_mb: 512, - cpu_kind: 'shared', - cpus: 1 - } - } + cpu_kind: "shared", + cpus: 1, + }, + }, }; - 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); - console.log('Allocating IPv4 via GraphQL API'); - const v4resp = await gqlClient.post('', { + console.log("Allocating IPv4 via GraphQL API"); + const v4resp = await gqlClient.post("", { query: ALLOCATE_IP_MUTATION, - variables: { input: { appId: appName, type: 'v4' } } + variables: { input: { appId: appName, type: "v4" } }, }); const ipv4 = v4resp.data.data.allocateIpAddress.ipAddress.address; - console.log('Allocated IPv4:', ipv4); + console.log("Allocated IPv4:", ipv4); - console.log('Allocating IPv6 via GraphQL API'); - const v6resp = await gqlClient.post('', { + console.log("Allocating IPv6 via GraphQL API"); + const v6resp = await gqlClient.post("", { query: ALLOCATE_IP_MUTATION, - variables: { input: { appId: appName, type: 'v6' } } + variables: { input: { appId: appName, type: "v6" } }, }); const ipv6 = v6resp.data.data.allocateIpAddress.ipAddress.address; - console.log('Allocated IPv6:', ipv6); + console.log("Allocated IPv6:", ipv6); return res.json({ - status: 'created', + status: "created", app: appName, ipv4, ipv6, url_v4: `http://${ipv4}`, - url_v6: `http://[${ipv6}]` + url_v6: `http://[${ipv6}]`, }); } catch (err) { - console.error('Deployment error:', err.response?.data || err.stack || err.message); + console.error( + "Deployment error:", + err.response?.data || err.stack || err.message + ); return res.status(500).json({ error: err.response?.data || err.message }); } }); // Upload notebook to S3 for an existing app -app.post('/:appName/upload', async (req, res) => { +app.post("/:appName/upload", async (req, res) => { const { appName } = req.params; const { notebookName, fileContentBase64 } = req.body; if (!notebookName || !fileContentBase64) { - return res.status(400).json({ error: 'notebookName and fileContentBase64 are required' }); + return res + .status(400) + .json({ error: "notebookName and fileContentBase64 are required" }); } try { - const buffer = Buffer.from(fileContentBase64, 'base64'); + const buffer = Buffer.from(fileContentBase64, "base64"); const key = `${appName}/notebooks/${notebookName}`; console.log(`Uploading notebook to: s3://${COMMON_BUCKET}/${key}`); - await s3.putObject({ - Bucket: COMMON_BUCKET, - Key: key, - Body: buffer, - ContentType: 'application/json' - }).promise(); + await s3 + .putObject({ + Bucket: COMMON_BUCKET, + Key: key, + Body: buffer, + ContentType: "application/json", + }) + .promise(); - return res.json({ status: 'uploaded', app: appName, key }); + return res.json({ status: "uploaded", app: appName, key }); } catch (err) { - console.error('Notebook upload error:', err); + console.error("Notebook upload error:", err); return res.status(500).json({ error: err.message }); } }); // Delete a Fly app -app.post('/:appName/delete', async (req, res) => { +app.post("/:appName/delete", async (req, res) => { const { appName } = req.params; try { const fly = createFlyClient(); - console.log('Destroying Fly app:', appName); + console.log("Destroying Fly app:", appName); await fly.delete(`/apps/${appName}`); - return res.json({ status: 'deleted', app: appName }); + return res.json({ status: "deleted", app: appName }); } catch (err) { - console.error('App deletion error:', err.response?.data || err.message); + console.error("App deletion error:", err.response?.data || err.message); return res.status(500).json({ error: err.response?.data || err.message }); } }); const LISTEN_PORT = process.env.PORT || 3006; -app.listen(LISTEN_PORT, '0.0.0.0', () => { +app.listen(LISTEN_PORT, "0.0.0.0", () => { console.log(`Deployment service listening on port ${LISTEN_PORT}`); }); diff --git a/uploader-service/app.js b/uploader-service/app.js index 6d71209..453324c 100644 --- a/uploader-service/app.js +++ b/uploader-service/app.js @@ -102,7 +102,7 @@ app.post('/machines/get', async (req, res) => { // Endpoint to upload files to Google Drive app.post('/drive/upload', upload.fields([{ name: 'pythonFile' }, { name: 'jsonFile', maxCount: 1 }]), async (req, res) => { const { folderLink } = req.body; - const { pythonFile, jsonFile } = req.files; + const { pythonFile, jsonFile } = req.files; if (!folderLink || !pythonFile) { return res.status(400).json({ error: 'Folder link and Python file are required' }); diff --git a/user-db-service/.env b/user-db-service/.env index 3aaa685..52a3ca1 100644 --- a/user-db-service/.env +++ b/user-db-service/.env @@ -5,8 +5,8 @@ # 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 -# DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost:15432/postgres?schema=public" +DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost: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 -NODE_PORT=3000 +NODE_PORT=3100 diff --git a/user-db-service/dev.env b/user-db-service/.env.development similarity index 100% rename from user-db-service/dev.env rename to user-db-service/.env.development diff --git a/user-db-service/fly.toml b/user-db-service/fly.toml index 07d92c2..30dbd0d 100644 --- a/user-db-service/fly.toml +++ b/user-db-service/fly.toml @@ -6,11 +6,6 @@ primary_region = "sea" [build] # Only needed if you're using a Dockerfile — can be empty if using buildpacks or Node preset -#[env] - #NODE_ENV = "production" - #DATABASE_URL = "postgresql://user:password@hostname:port/dbname" - # you can also leave DATABASE_URL unset here and use secrets instead - # Removed the [http_service] section to disable public HTTP/HTTPS access # [http_service] # internal_port = 3000 @@ -24,6 +19,8 @@ primary_region = "sea" protocol = "tcp" internal_port = 3000 internal_only = true # Makes this service only accessible internally + auto_start_machines = true + auto_stop_machines = true # Removed public port exposure # [[services.ports]]