From 5ce01158ade45323e6e5836767092d6f3a51f434 Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 14:50:05 -0700 Subject: [PATCH 1/2] submit assignment now creates an fly machine --- assignment-db-service/app.js | 6 +- assignment-service/.env | 2 +- assignment-service/.env.development | 11 +- assignment-service/.env.test | 6 +- assignment-service/dev.env | 5 - assignment-service/routes/InstructorRouter.js | 93 ++++++-- assignment-service/routes/StudentRouter.js | 15 ++ deployment-service/src/index.js | 205 ++++++++++-------- 8 files changed, 215 insertions(+), 128 deletions(-) delete mode 100644 assignment-service/dev.env diff --git a/assignment-db-service/app.js b/assignment-db-service/app.js index 09f0055..659a31f 100644 --- a/assignment-db-service/app.js +++ b/assignment-db-service/app.js @@ -43,15 +43,15 @@ async function convertToAssignment(req) { const hashPassword = await encryptPassword(req.body.password); return { - campid: campid, - programid: programid, + campid: parseInt(campid), + programid: parseInt(programid), studentname: studentname, snakegameid: snakegameid, originalfile: originalfile, editablefile: editablefile, assignmenturl: assignmenturl, passwordhash: hashPassword, - instructorid: instructorid, + instructorid: parseInt(instructorid), }; } diff --git a/assignment-service/.env b/assignment-service/.env index 9cf3674..f5f5b51 100644 --- a/assignment-service/.env +++ b/assignment-service/.env @@ -1,3 +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 index b0a3aab..b683362 100644 --- a/assignment-service/.env.development +++ b/assignment-service/.env.development @@ -1,6 +1,11 @@ NODE_ENV=development -#DB_ASSIGNMENT_SERVICE_URL="http://localhost:3000" DB_ASSIGNMENT_SERVICE_URL="http://localhost:3200" -AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42" -ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173 +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 index 8323fe9..fd1e4e1 100644 --- a/assignment-service/.env.test +++ b/assignment-service/.env.test @@ -1,6 +1,4 @@ -NODE_ENV=development -#DB_ASSIGNMENT_SERVICE_URL="http://localhost:3000" +NODE_ENV=test 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 +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/routes/InstructorRouter.js b/assignment-service/routes/InstructorRouter.js index 8fa3cff..9cd23d6 100644 --- a/assignment-service/routes/InstructorRouter.js +++ b/assignment-service/routes/InstructorRouter.js @@ -1,45 +1,98 @@ const intructorRouter = require("express").Router(); const passport = require("passport"); const axios = require("axios"); -const multer = require('multer'); -const FormData = require('form-data'); +const multer = require("multer"); +const FormData = require("form-data"); +const fs = require('fs'); +const path = require('path'); +const AWS = require('aws-sdk'); + +// const { +// COMMON_BUCKET, +// AWS_ACCESS_KEY_ID, +// AWS_SECRET_ACCESS_KEY, +// AWS_ENDPOINT_URL_S3, +// AWS_REGION, +// } = process.env; + +// Log environment variables for debugging +// console.log('--- ENV START ---'); +// 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('--- ENV END ---'); 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"; + console.log("DB_ASSIGNMENT_SERVICE_URL:", DB_ASSIGNMENT_SERVICE_URL); +console.log("DEPLOY_API_URL:", DEPLOY_API_URL); + + +// 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 +// }); // 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", - upload.single('file'), - // passport.authenticate("jwt", { session: false }), +intructorRouter.post( + "/create", + upload.single("file"), + // passport.authenticate("jwt", { session: false }), async (req, res) => { try { - const file = req.file; const assignmentData = req.body; if (!file) { - return res.status(400).send('No file uploaded.'); + return res.status(400).send("No file uploaded."); } - await axios.post('https://target-api.com/endpoint', { - filename: file.originalname, - mimetype: file.mimetype, - content: file.buffer.toString('base64') - }, { - headers: { - 'Content-Type': 'application/json' - } - }); - console.log("Creating a new assignment with data:", req.body); - const response = await axios.post(`${DB_ASSIGNMENT_SERVICE_URL}/assignments`, req.body); + const response = await axios.post( + `${DB_ASSIGNMENT_SERVICE_URL}/assignments`, + req.body + ); console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data); + + // Upload the file to the S3 bucket + // console.log('Uploading notebook to S3'); + // const key = `${assignmentData.appname}/notebooks/${Date.now()}-notebook.ipynb`; + // console.log('S3 key:', key); + // await s3.putObject({ + // Bucket: COMMON_BUCKET, + // Key: key, + // Body: file.buffer, + // ContentType: 'application/json' + // }).promise(); + + // 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); @@ -56,7 +109,7 @@ intructorRouter.get("/details/:id", async (req, res) => { 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) { diff --git a/assignment-service/routes/StudentRouter.js b/assignment-service/routes/StudentRouter.js index 6dcf37b..d57339a 100644 --- a/assignment-service/routes/StudentRouter.js +++ b/assignment-service/routes/StudentRouter.js @@ -10,6 +10,21 @@ studentRouter.post("/save", (req, res) => {}); studentRouter.post("/deploy", (req, res) => {}); +studentRouter.get("/assignment/:id", (req, res) => { + const assignmentId = req.params.id; + console.log("Fetching details for assignmentId:", assignmentId); + axios + .get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`) + .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("/verify", async (req, res) => { try { const assignmentId = req.body.assignmentId; 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}`); }); From b2a6b3689bac2c46f723ef33fce7dbd336a6895e Mon Sep 17 00:00:00 2001 From: JBB0807 <104856796+JBB0807@users.noreply.github.com> Date: Mon, 5 May 2025 15:07:15 -0700 Subject: [PATCH 2/2] inserts appname and qrcodenumber in the DB --- assignment-db-service/app.js | 12 +- assignment-db-service/package-lock.json | 527 +++++++++++++++++++-- assignment-db-service/package.json | 2 +- assignment-db-service/prisma/schema.prisma | 7 +- 4 files changed, 512 insertions(+), 36 deletions(-) diff --git a/assignment-db-service/app.js b/assignment-db-service/app.js index 659a31f..9f43b2f 100644 --- a/assignment-db-service/app.js +++ b/assignment-db-service/app.js @@ -33,8 +33,9 @@ async function convertToAssignment(req) { programid, studentname, snakegameid, - originalfile, - editablefile, + appname, + qrcodenumber, + description, assignmenturl, password, instructorid @@ -47,8 +48,11 @@ async function convertToAssignment(req) { programid: parseInt(programid), studentname: studentname, snakegameid: snakegameid, - originalfile: originalfile, - editablefile: editablefile, + appname: appname, + qrcodenumber: parseInt(qrcodenumber), + description: description, + // originalfile: originalfile, + // editablefile: editablefile, assignmenturl: assignmenturl, passwordhash: hashPassword, instructorid: parseInt(instructorid), diff --git a/assignment-db-service/package-lock.json b/assignment-db-service/package-lock.json index d88c403..c8e5c33 100644 --- a/assignment-db-service/package-lock.json +++ b/assignment-db-service/package-lock.json @@ -9,12 +9,412 @@ "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": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -57,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": { @@ -540,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", @@ -1317,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" @@ -1333,6 +1796,14 @@ }, "optionalDependencies": { "fsevents": "2.3.3" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/proxy-addr": { diff --git a/assignment-db-service/package.json b/assignment-db-service/package.json index 6724b9c..f78b946 100644 --- a/assignment-db-service/package.json +++ b/assignment-db-service/package.json @@ -4,7 +4,7 @@ "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", diff --git a/assignment-db-service/prisma/schema.prisma b/assignment-db-service/prisma/schema.prisma index 0a18c40..5cf5df5 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? }