From eafe02f402a4b8c369fce1a83e710a41270fc276 Mon Sep 17 00:00:00 2001 From: wildfont Date: Mon, 11 May 2026 17:02:33 +0200 Subject: [PATCH 01/10] first day miniproject 3 --- server/app.js | 19 ++++++++++++++++--- server/package-lock.json | 27 +++++++++++++++++++++++++++ server/package.json | 1 + 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/server/app.js b/server/app.js index dfe51f49..57bbaebb 100644 --- a/server/app.js +++ b/server/app.js @@ -1,4 +1,5 @@ -const express = require("express"); +const express = require("express") +const cors = require("cors") const morgan = require("morgan"); const cookieParser = require("cookie-parser"); const PORT = 5005; @@ -11,10 +12,11 @@ const PORT = 5005; // INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express const app = express(); - // MIDDLEWARE // Research Team - Set up CORS middleware here: // ... +app.use(cors()) + app.use(express.json()); app.use(morgan("dev")); app.use(express.static("public")); @@ -29,8 +31,19 @@ app.get("/docs", (req, res) => { res.sendFile(__dirname + "/views/docs.html"); }); +const cohorts = require("./cohorts.json") +app.get("/api/cohorts", (req, res) => { + res.json(cohorts); +}) + +const students = require("./students.json") +app.get("/api/students", (req, res) => { + res.json(students); +}) + // START SERVER app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); -}); \ No newline at end of file +}); + diff --git a/server/package-lock.json b/server/package-lock.json index 23e2f78a..2f3fd24a 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "cookie-parser": "^1.4.6", + "cors": "^2.8.6", "express": "^4.18.2", "morgan": "^1.10.0", "nodemon": "^3.0.1" @@ -216,6 +217,23 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -700,6 +718,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", diff --git a/server/package.json b/server/package.json index 7aa0847c..cd696f7f 100644 --- a/server/package.json +++ b/server/package.json @@ -19,6 +19,7 @@ "homepage": "https://github.com/ironhack-labs/cohort-tools-project#readme", "dependencies": { "cookie-parser": "^1.4.6", + "cors": "^2.8.6", "express": "^4.18.2", "morgan": "^1.10.0", "nodemon": "^3.0.1" From b587c1ccb2e6c33a0ff90fe7ea1ade5083ee442a Mon Sep 17 00:00:00 2001 From: wildfont Date: Tue, 12 May 2026 15:34:27 +0200 Subject: [PATCH 02/10] deleting json files --- server/cohorts.json | 57 ----------------------------- server/students.json | 86 -------------------------------------------- 2 files changed, 143 deletions(-) delete mode 100644 server/cohorts.json delete mode 100644 server/students.json diff --git a/server/cohorts.json b/server/cohorts.json deleted file mode 100644 index 3c2bef26..00000000 --- a/server/cohorts.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "_id": 1, - "inProgress": false, - "cohortSlug": "ft-wd-paris-2023-07-03", - "cohortName": "FT WD PARIS 2023 07", - "program": "Web Dev", - "campus": "Paris", - "startDate": "2023-07-03T00:00:00.000Z", - "endDate": "2023-09-08T00:00:00.000Z", - "programManager": "Sally Daher", - "leadTeacher": "Florian Aube", - "totalHours": 360 - }, - { - "_id": 2, - "cohortSlug": "pt-ux-berlin-2023-02-06", - "cohortName": "PT UX BERLIN 2023 02", - "program": "UX/UI", - "format": "Part Time", - "campus": "BERLIN", - "startDate": "2023-02-06T00:00:00.000Z", - "endDate": "2023-08-06T00:00:00.000Z", - "inProgress": false, - "programManager": "Alice Williams", - "leadTeacher": "Bob Johnson", - "totalHours": 360 - }, - { - "_id": 3, - "cohortSlug": "ft-da-miami-2023-03-06", - "cohortName": "FT DA MIAMI 2023 03", - "program": "Data Analytics", - "format": "Full Time", - "campus": "Miami", - "startDate": "2023-03-06T00:00:00.000Z", - "endDate": "2023-05-15T00:00:00.000Z", - "inProgress": true, - "programManager": "Charlie Brown", - "leadTeacher": "Eva Edwards", - "totalHours": 360 - }, - { - "_id": 4, - "cohortSlug": "pt-cy-paris-2023-04-03", - "cohortName": "PT CY PARIS 2023 04", - "program": "Cybersecurity", - "format": "Part Time", - "campus": "Paris", - "startDate": "2023-04-03T00:00:00.000Z", - "endDate": "2023-10-03T00:00:00.000Z", - "inProgress": false, - "programManager": "Eva Edwards", - "leadTeacher": "Frank Foster", - "totalHours": 360 - } -] diff --git a/server/students.json b/server/students.json deleted file mode 100644 index ffd7e34e..00000000 --- a/server/students.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "_id": 1, - "firstName": "Christine", - "lastName": "Clayton", - "email": "christine.clayton@example.com", - "phone": "567-890-1234", - "linkedinUrl": "https://linkedin.com/in/christineclaytonexample", - "languages": ["English", "Dutch"], - "program": "Web Dev", - "background": "Computer Engineering", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 1, - "projects": [] - }, - { - "_id": 2, - "firstName": "Grace", - "lastName": "Green", - "email": "grace.green@example.com", - "phone": "901-234-5678", - "linkedinUrl": "https://linkedin.com/in/gracegreenexample", - "languages": ["English", "Portuguese"], - "program": "Web Dev", - "background": "Software Development", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 1, - "projects": [] - }, - { - "_id": 3, - "firstName": "Jack", - "lastName": "Johnson", - "email": "jack.johnson@example.com", - "phone": "234-567-8901", - "linkedinUrl": "https://linkedin.com/in/jackjohnsonexample", - "languages": ["English", "French"], - "program": "Web Dev", - "background": "System Administration", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 1, - "projects": [] - }, - { - "_id": 4, - "firstName": "John", - "lastName": "Doe", - "email": "john.doe@example.com", - "phone": "123-456-7890", - "linkedinUrl": "https://linkedin.com/in/johndoeexample", - "languages": ["English", "Spanish"], - "program": "UX/UI", - "background": "Computer Science", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 2, - "projects": [] - }, - { - "_id": 5, - "firstName": "Katie", - "lastName": "King", - "email": "katie.king@example.com", - "phone": "345-678-9012", - "linkedinUrl": "https://linkedin.com/in/katiekingexample", - "languages": ["English", "German"], - "program": "UX/UI", - "background": "Information Systems", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 2, - "projects": [] - }, - { - "_id": 6, - "firstName": "Irene", - "lastName": "Iverson", - "email": "irene.iverson@example.com", - "phone": "123-456-7890", - "linkedinUrl": "https://linkedin.com/in/ireneiversonexample", - "languages": ["English", "Spanish"], - "program": "Data Analytics", - "background": "Economics", - "image": "https://i.imgur.com/r8bo8u7.png", - "cohort": 3, - "projects": [] - } -] From f283a75b54076f4b44b1df9ae2edcc7d1552444a Mon Sep 17 00:00:00 2001 From: 250300G <250300g@gmail.com> Date: Tue, 12 May 2026 17:43:50 +0200 Subject: [PATCH 03/10] day2 --- server/app.js | 33 ++-- server/mongoose_schema/cohort.model.js | 19 +++ server/mongoose_schema/student.model.js | 20 +++ server/package-lock.json | 211 ++++++++++++++++++++++++ server/package.json | 1 + 5 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 server/mongoose_schema/cohort.model.js create mode 100644 server/mongoose_schema/student.model.js diff --git a/server/app.js b/server/app.js index 57bbaebb..d8901bda 100644 --- a/server/app.js +++ b/server/app.js @@ -1,13 +1,20 @@ -const express = require("express") -const cors = require("cors") +const express = require("express"); +const cors = require("cors"); const morgan = require("morgan"); const cookieParser = require("cookie-parser"); const PORT = 5005; +const Cohort = require("./mongoose_schema/cohort.model.js"); +const Student = require("./mongoose_schema/student.model.js"); // STATIC DATA // Devs Team - Import the provided files with JSON data of students and cohorts here: // ... +const mongoose = require("mongoose"); +mongoose + .connect("mongodb://127.0.0.1:27017/cohorts-tools-api") + .then((x) => console.log(`Connect to Database:"${x.connections[0].name}"`)) + .catch((err) => console.error("Error connecting to MongoDB", err)); // INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express const app = express(); @@ -15,7 +22,7 @@ const app = express(); // MIDDLEWARE // Research Team - Set up CORS middleware here: // ... -app.use(cors()) +app.use(cors()); app.use(express.json()); app.use(morgan("dev")); @@ -23,7 +30,6 @@ app.use(express.static("public")); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); - // ROUTES - https://expressjs.com/en/starter/basic-routing.html // Devs Team - Start working on the routes here: // ... @@ -31,19 +37,24 @@ app.get("/docs", (req, res) => { res.sendFile(__dirname + "/views/docs.html"); }); -const cohorts = require("./cohorts.json") +//const cohorts = require("./cohorts.json") app.get("/api/cohorts", (req, res) => { - res.json(cohorts); -}) + Cohort.find({}) + .then((cohorts) => { + console.log("Cohort is connected"); + res.json(cohorts); + }) + .catch((error) => { + console.error("error"); + }); +}); -const students = require("./students.json") +//const students = require("./students.json") app.get("/api/students", (req, res) => { res.json(students); -}) - +}); // START SERVER app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); }); - diff --git a/server/mongoose_schema/cohort.model.js b/server/mongoose_schema/cohort.model.js new file mode 100644 index 00000000..59885650 --- /dev/null +++ b/server/mongoose_schema/cohort.model.js @@ -0,0 +1,19 @@ +const mongoose = require("mongoose") +const Schema = mongoose.Schema + +const cohortSchema = new Schema({ +inProgress: Boolean, +cohortSlug: String, +cohortName: String, +program: String, +campus: String, +startDate: String, +endDate: String, +programManager: String, +leadTeacher: String, +totalHours: Number + +}) +const Cohort =mongoose.model("Cohort", cohortSchema) +module.exports = Cohort + diff --git a/server/mongoose_schema/student.model.js b/server/mongoose_schema/student.model.js new file mode 100644 index 00000000..2ea66ee0 --- /dev/null +++ b/server/mongoose_schema/student.model.js @@ -0,0 +1,20 @@ +const mongoose = require("mongoose") +const Schema = mongoose.Schema + +const studentSchema = new Schema({ +firstName: String, + lastName: String, + email: String, + phone: String, + linkedinUrl: String, + languages: [String], + program: String, + background: String, + image: String, + projects: [{ type: Schema.Types.ObjectId, ref: "Project" }], + cohort: { type: Schema.Types.ObjectId, ref: "Cohort" } + +}) +const Student =mongoose.model("Student", StudentSchema) +module.exports = Student + diff --git a/server/package-lock.json b/server/package-lock.json index 2f3fd24a..d920e1d0 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -12,10 +12,35 @@ "cookie-parser": "^1.4.6", "cors": "^2.8.6", "express": "^4.18.2", + "mongoose": "^9.6.2", "morgan": "^1.10.0", "nodemon": "^3.0.1" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.11.tgz", + "integrity": "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -122,6 +147,15 @@ "node": ">=8" } }, + "node_modules/bson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", + "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -544,6 +578,15 @@ "node": ">=0.12.0" } }, + "node_modules/kareem": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.3.0.tgz", + "integrity": "sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -563,6 +606,12 @@ "node": ">= 0.6" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -617,6 +666,92 @@ "node": "*" } }, + "node_modules/mongodb": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.2.0.tgz", + "integrity": "sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^7.2.0", + "mongodb-connection-string-url": "^7.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": ">=7.0.0 <7.1.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", + "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/mongoose": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.6.2.tgz", + "integrity": "sha512-7m8HntjkoRnwEmuPC0kdlwcZXJOQf4twumFj+PNzg/anqqZE2Er7hQslqyzy07mP3JcFjoTSgH5765PyqOXsxw==", + "license": "MIT", + "dependencies": { + "kareem": "3.3.0", + "mongodb": "~7.2", + "mpath": "0.9.0", + "mquery": "6.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/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/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -643,6 +778,24 @@ "node": ">= 0.8" } }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz", + "integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==", + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -795,6 +948,15 @@ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -940,6 +1102,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -951,6 +1119,15 @@ "node": ">=10" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1000,6 +1177,18 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1041,6 +1230,28 @@ "node": ">= 0.8" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/server/package.json b/server/package.json index cd696f7f..74040611 100644 --- a/server/package.json +++ b/server/package.json @@ -21,6 +21,7 @@ "cookie-parser": "^1.4.6", "cors": "^2.8.6", "express": "^4.18.2", + "mongoose": "^9.6.2", "morgan": "^1.10.0", "nodemon": "^3.0.1" } From 616ff5499abcdef5e19965007435a2e4dd1310f7 Mon Sep 17 00:00:00 2001 From: Aybike Celebi Visser Date: Wed, 13 May 2026 16:57:17 +0200 Subject: [PATCH 04/10] day3done --- server/app.js | 196 ++++++++++++++++++++++-- server/mongoose_schema/student.model.js | 2 +- server/package-lock.json | 75 +++++---- server/package.json | 2 +- 4 files changed, 233 insertions(+), 42 deletions(-) diff --git a/server/app.js b/server/app.js index d8901bda..00059a8d 100644 --- a/server/app.js +++ b/server/app.js @@ -38,22 +38,196 @@ app.get("/docs", (req, res) => { }); //const cohorts = require("./cohorts.json") -app.get("/api/cohorts", (req, res) => { - Cohort.find({}) - .then((cohorts) => { - console.log("Cohort is connected"); - res.json(cohorts); - }) - .catch((error) => { - console.error("error"); - }); +app.get("/api/cohorts", async (req, res) => { + try{ + const response = await Cohort.find() + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } }); + +app.post("/api/cohorts", (req, res) => { + + + +console.log(req.body) + + +const newCohort = { + inProgress: req.body.inProgress, +cohortSlug: req.body.cohortSlug, +cohortName: req.body.cohortName, +program: req.body.program, +campus: req.body.campus, +startDate: req.body.startDate, +endDate: req.body.endDate, +programManager: req.body.programManager, +leadTeacher: req.body.leadTeacher, +totalHours: req.body.totalHours +} +Cohort.create(newCohort) +.then(() => { + res.send("Cohort Created") +}) +.catch((error) => { + console.log(error) +}) + +}) + +app.get("/api/cohorts/:cohortId", async (req, res) => { + try{ + const response = await Cohort.findById(req.params.cohortId) + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } +}) + +app.put("/api/cohorts/:cohortId", async (req, res, next) => { + + console.log(req.params) + console.log(req.body) + + try{ + +const updatedCohort = { + inProgress: req.body.inProgress, +cohortSlug: req.body.cohortSlug, +cohortName: req.body.cohortName, +program: req.body.program, +campus: req.body.campus, +startDate: req.body.startDate, +endDate: req.body.endDate, +programManager: req.body.programManager, +leadTeacher: req.body.leadTeacher, +totalHours: req.body.totalHours + +} +const response = await Cohort.findByIdAndUpdate(req.params.cohortId, updatedCohort) + + res.send("cohort updated") + } catch (error) { + console.log(error) + } +}) + + +app.delete("/api/cohorts", async (req, res) => { + try{ + const response = await Cohort.findByIdAndDelete(req.params.cohortId) + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } +}) + //const students = require("./students.json") -app.get("/api/students", (req, res) => { - res.json(students); +app.get("/api/students", async (req, res) => { + try{ + const response = await Student.find() + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } }); +app.post("/api/students", (req, res) => { + + +//1. we need to receive a body +console.log(req.body) +//2. we need to go into the db to create something + +const newStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + cohort: req.body.cohort + +} +Student.create(newStudent) +.then(() => { + res.send("Student created") +}) +.catch((error) => { + console.log(error) +}) + +}) + +app.get("/api/students/:studentId", async (req, res) => { + try{ + const response = await Student.findById(req.params.studentId).populate('cohort') + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } +}) + +app.put("/api/students/:studentId", async (req, res, next) => { + + console.log(req.params) + console.log(req.body) + + try{ + +const updatedStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + + +} +const response = await Student.findByIdAndUpdate(req.params.studentId, updatedStudent) + + res.send("student updated") + } catch (error) { + console.log(error) + } +}) + +app.get("/api/students/cohort/:cohortId", async (req, res, next) => { + try{ + const studentsBelongCohort = await Student.find({cohort: req.params.cohortId}).populate('cohort') + console.log("students belong to cohort") + res.json(studentsBelongCohort) + } catch (error) { + console.log(error) + } +}) + +app.delete("/api/students", async (req, res) => { + try{ + const response = await Cohort.findByIdAndDelete(req.params.studentId) + console.log(response) + res.json(response) + } catch (error) { + console.log(error) + } +}) + // START SERVER app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); diff --git a/server/mongoose_schema/student.model.js b/server/mongoose_schema/student.model.js index 2ea66ee0..bab170c1 100644 --- a/server/mongoose_schema/student.model.js +++ b/server/mongoose_schema/student.model.js @@ -15,6 +15,6 @@ firstName: String, cohort: { type: Schema.Types.ObjectId, ref: "Cohort" } }) -const Student =mongoose.model("Student", StudentSchema) +const Student =mongoose.model("Student", studentSchema) module.exports = Student diff --git a/server/package-lock.json b/server/package-lock.json index d920e1d0..7fdd4e42 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -14,7 +14,7 @@ "express": "^4.18.2", "mongoose": "^9.6.2", "morgan": "^1.10.0", - "nodemon": "^3.0.1" + "nodemon": "^3.1.14" } }, "node_modules/@mongodb-js/saslprep": { @@ -76,9 +76,13 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/basic-auth": { "version": "2.0.1", @@ -128,12 +132,15 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -202,11 +209,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -656,14 +658,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mongodb": { @@ -810,14 +816,15 @@ } }, "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", + "minimatch": "^10.2.1", "pstree.remy": "^1.1.8", "semver": "^7.5.3", "simple-update-notifier": "^2.0.0", @@ -837,17 +844,27 @@ } }, "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/nodemon/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==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nopt": { "version": "1.0.10", diff --git a/server/package.json b/server/package.json index 74040611..06414cdc 100644 --- a/server/package.json +++ b/server/package.json @@ -23,6 +23,6 @@ "express": "^4.18.2", "mongoose": "^9.6.2", "morgan": "^1.10.0", - "nodemon": "^3.0.1" + "nodemon": "^3.1.14" } } From 7d8334e0049b0d24e54080c6a31f39a3df5899bd Mon Sep 17 00:00:00 2001 From: wildfont Date: Thu, 14 May 2026 17:10:46 +0200 Subject: [PATCH 05/10] done day 4 --- server/.env.sample | 1 - server/app.js | 330 +++++++++++++++++++++++---------------------- 2 files changed, 167 insertions(+), 164 deletions(-) delete mode 100644 server/.env.sample diff --git a/server/.env.sample b/server/.env.sample deleted file mode 100644 index 0042a604..00000000 --- a/server/.env.sample +++ /dev/null @@ -1 +0,0 @@ -PORT=5005 \ No newline at end of file diff --git a/server/app.js b/server/app.js index 00059a8d..55dd1555 100644 --- a/server/app.js +++ b/server/app.js @@ -22,7 +22,11 @@ const app = express(); // MIDDLEWARE // Research Team - Set up CORS middleware here: // ... -app.use(cors()); +app.use( + cors({ + origin: process.env.ORIGIN, + }), +); app.use(express.json()); app.use(morgan("dev")); @@ -39,194 +43,194 @@ app.get("/docs", (req, res) => { //const cohorts = require("./cohorts.json") app.get("/api/cohorts", async (req, res) => { - try{ - const response = await Cohort.find() - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } + try { + const response = await Cohort.find(); + res.status(200).json(response); + res.json(response); + } catch (error) { + console.log(error); + } }); - app.post("/api/cohorts", (req, res) => { - - - -console.log(req.body) - - -const newCohort = { - inProgress: req.body.inProgress, -cohortSlug: req.body.cohortSlug, -cohortName: req.body.cohortName, -program: req.body.program, -campus: req.body.campus, -startDate: req.body.startDate, -endDate: req.body.endDate, -programManager: req.body.programManager, -leadTeacher: req.body.leadTeacher, -totalHours: req.body.totalHours -} -Cohort.create(newCohort) -.then(() => { - res.send("Cohort Created") -}) -.catch((error) => { - console.log(error) -}) - -}) + console.log(req.body); + + const newCohort = { + inProgress: req.body.inProgress, + cohortSlug: req.body.cohortSlug, + cohortName: req.body.cohortName, + program: req.body.program, + campus: req.body.campus, + startDate: req.body.startDate, + endDate: req.body.endDate, + programManager: req.body.programManager, + leadTeacher: req.body.leadTeacher, + totalHours: req.body.totalHours, + }; + Cohort.create(newCohort) + .then(() => { + res.send("Cohort Created"); + }) + .catch((error) => { + console.log(error); + }); +}); app.get("/api/cohorts/:cohortId", async (req, res) => { - try{ - const response = await Cohort.findById(req.params.cohortId) - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } -}) + try { + const response = await Cohort.findById(req.params.cohortId); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); app.put("/api/cohorts/:cohortId", async (req, res, next) => { - - console.log(req.params) - console.log(req.body) - - try{ - -const updatedCohort = { - inProgress: req.body.inProgress, -cohortSlug: req.body.cohortSlug, -cohortName: req.body.cohortName, -program: req.body.program, -campus: req.body.campus, -startDate: req.body.startDate, -endDate: req.body.endDate, -programManager: req.body.programManager, -leadTeacher: req.body.leadTeacher, -totalHours: req.body.totalHours - -} -const response = await Cohort.findByIdAndUpdate(req.params.cohortId, updatedCohort) - - res.send("cohort updated") + console.log(req.params); + console.log(req.body); + + try { + const updatedCohort = { + inProgress: req.body.inProgress, + cohortSlug: req.body.cohortSlug, + cohortName: req.body.cohortName, + program: req.body.program, + campus: req.body.campus, + startDate: req.body.startDate, + endDate: req.body.endDate, + programManager: req.body.programManager, + leadTeacher: req.body.leadTeacher, + totalHours: req.body.totalHours, + }; + const response = await Cohort.findByIdAndUpdate( + req.params.cohortId, + updatedCohort, + ); + + res.status(202).send("cohort updated"); } catch (error) { - console.log(error) + next(error); } -}) - +}); -app.delete("/api/cohorts", async (req, res) => { - try{ - const response = await Cohort.findByIdAndDelete(req.params.cohortId) - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } -}) +app.delete("/api/cohorts/:cohortId", async (req, res) => { + try { + const response = await Cohort.findByIdAndDelete(req.params.cohortId); + res.status(202).json(response); + } catch (error) { + next(error); + } +}); //const students = require("./students.json") app.get("/api/students", async (req, res) => { - try{ - const response = await Student.find() - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } + try { + const response = await Student.find().populate("cohort"); + res.status(200).json(response); + } catch (error) { + next(error); + } }); app.post("/api/students", (req, res) => { - - -//1. we need to receive a body -console.log(req.body) -//2. we need to go into the db to create something - -const newStudent = { - firstName: req.body.firstName, - lastName: req.body.lastName, - email: req.body.email, - phone: req.body.phone, - linkedinUrl: req.body.linkedinUrl, - languages: req.body.languages, - program: req.body.program, - background: req.body.background, - image: req.body.image, - projects: req.body.projects, - cohort: req.body.cohort - -} -Student.create(newStudent) -.then(() => { - res.send("Student created") -}) -.catch((error) => { - console.log(error) -}) - -}) + //1. we need to receive a body + console.log(req.body); + //2. we need to go into the db to create something + + const newStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + cohort: req.body.cohort, + }; + Student.create(newStudent) + .then(() => { + res.sendStatus(201); + }) + .catch((error) => { + console.log(error); + }); +}); app.get("/api/students/:studentId", async (req, res) => { - try{ - const response = await Student.findById(req.params.studentId).populate('cohort') - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } -}) + try { + const response = await Student.findById(req.params.studentId).populate( + "cohort", + ); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); app.put("/api/students/:studentId", async (req, res, next) => { - - console.log(req.params) - console.log(req.body) - - try{ - -const updatedStudent = { - firstName: req.body.firstName, - lastName: req.body.lastName, - email: req.body.email, - phone: req.body.phone, - linkedinUrl: req.body.linkedinUrl, - languages: req.body.languages, - program: req.body.program, - background: req.body.background, - image: req.body.image, - projects: req.body.projects, - - -} -const response = await Student.findByIdAndUpdate(req.params.studentId, updatedStudent) - - res.send("student updated") + console.log(req.params); + console.log(req.body); + + try { + const updatedStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + }; + const response = await Student.findByIdAndUpdate( + req.params.studentId, + updatedStudent, + ); + + res.sendStatus(202).send("student updated"); } catch (error) { - console.log(error) + next(error); } -}) +}); app.get("/api/students/cohort/:cohortId", async (req, res, next) => { - try{ - const studentsBelongCohort = await Student.find({cohort: req.params.cohortId}).populate('cohort') - console.log("students belong to cohort") - res.json(studentsBelongCohort) + try { + const studentsBelongCohort = await Student.find({ + cohort: req.params.cohortId, + }).populate("cohort"); + res.status(200).json(studentsBelongCohort); } catch (error) { - console.log(error) + next(error); } -}) - -app.delete("/api/students", async (req, res) => { - try{ - const response = await Cohort.findByIdAndDelete(req.params.studentId) - console.log(response) - res.json(response) - } catch (error) { - console.log(error) - } -}) +}); + +app.delete("/api/students/:studentId", async (req, res) => { + try { + const response = await Student.findByIdAndDelete(req.params.studentId); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); + +// error handling for 404 errors +app.use((req, res) => { + res.status(404).json({ errorMessage: "Sorry, route not found" }); +}); + +// error handling for 500 errors +app.use((error, req, res, next) => { + // express know this is the 500 error handler just because it has 4 parameters. + console.log(error); + res + .status(500) + .json({ errorMessage: "something went BOOM, sorry about this" }); +}); // START SERVER app.listen(PORT, () => { From 5ce15e15bb4cbb15e3cdd5ccc637940217de3e4b Mon Sep 17 00:00:00 2001 From: 250300G <250300g@gmail.com> Date: Fri, 15 May 2026 16:50:08 +0200 Subject: [PATCH 06/10] d5 --- server/app.js | 61 +- server/config/index.js | 29 + server/db/index.js | 38 ++ server/errors/index.js | 22 + .../cohort.model.js | 0 .../student.model.js | 0 server/models/user.models.js | 26 + server/package-lock.json | 536 ++++++++++++------ server/package.json | 1 + server/routes/auth.routes.js | 0 server/routes/cohort.routes.js | 0 server/routes/index.routes.js | 0 server/routes/students.routes.js | 0 13 files changed, 514 insertions(+), 199 deletions(-) create mode 100644 server/config/index.js create mode 100644 server/db/index.js create mode 100644 server/errors/index.js rename server/{mongoose_schema => models}/cohort.model.js (100%) rename server/{mongoose_schema => models}/student.model.js (100%) create mode 100644 server/models/user.models.js create mode 100644 server/routes/auth.routes.js create mode 100644 server/routes/cohort.routes.js create mode 100644 server/routes/index.routes.js create mode 100644 server/routes/students.routes.js diff --git a/server/app.js b/server/app.js index 55dd1555..656723b6 100644 --- a/server/app.js +++ b/server/app.js @@ -1,38 +1,33 @@ -const express = require("express"); -const cors = require("cors"); -const morgan = require("morgan"); -const cookieParser = require("cookie-parser"); const PORT = 5005; -const Cohort = require("./mongoose_schema/cohort.model.js"); -const Student = require("./mongoose_schema/student.model.js"); +const Cohort = require("./models/cohort.model.js"); +const Student = require("./models/student.model.js"); +const express = require("express") +const User = require("./models/user.models.js") + + +const app = express(); +const config = require("./config") +config(app) // STATIC DATA // Devs Team - Import the provided files with JSON data of students and cohorts here: // ... -const mongoose = require("mongoose"); -mongoose - .connect("mongodb://127.0.0.1:27017/cohorts-tools-api") - .then((x) => console.log(`Connect to Database:"${x.connections[0].name}"`)) + +const connectDB = require("./db") +app.use( async (req, res, next) => { +await connectDB() +next() - .catch((err) => console.error("Error connecting to MongoDB", err)); +} ) -// INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express -const app = express(); -// MIDDLEWARE -// Research Team - Set up CORS middleware here: -// ... -app.use( - cors({ - origin: process.env.ORIGIN, - }), -); - -app.use(express.json()); -app.use(morgan("dev")); -app.use(express.static("public")); -app.use(express.urlencoded({ extended: false })); -app.use(cookieParser()); +const errorHandling = require("./errors") +errorHandling(app) + + + + +// INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express // ROUTES - https://expressjs.com/en/starter/basic-routing.html // Devs Team - Start working on the routes here: @@ -218,19 +213,7 @@ app.delete("/api/students/:studentId", async (req, res) => { } }); -// error handling for 404 errors -app.use((req, res) => { - res.status(404).json({ errorMessage: "Sorry, route not found" }); -}); -// error handling for 500 errors -app.use((error, req, res, next) => { - // express know this is the 500 error handler just because it has 4 parameters. - console.log(error); - res - .status(500) - .json({ errorMessage: "something went BOOM, sorry about this" }); -}); // START SERVER app.listen(PORT, () => { diff --git a/server/config/index.js b/server/config/index.js new file mode 100644 index 00000000..df5f4f64 --- /dev/null +++ b/server/config/index.js @@ -0,0 +1,29 @@ +const express = require("express"); +const cors = require("cors"); +const morgan = require("morgan"); + const cookieParser = require("cookie-parser"); + + + +function config(app) { + + + +// MIDDLEWARE +// Research Team - Set up CORS middleware here: +// ... +app.use( + cors({ + origin: process.env.ORIGIN, + }), +); + +app.use(express.json()); +app.use(morgan("dev")); +app.use(express.static("public")); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); + +} + +module.exports = config diff --git a/server/db/index.js b/server/db/index.js new file mode 100644 index 00000000..171d1a41 --- /dev/null +++ b/server/db/index.js @@ -0,0 +1,38 @@ +const mongoose = require("mongoose") + + + +// :information_source: Connects to MongoDB using the URI from environment variables. + + +//const MONGO_URI = "mongodb://127.0.0.1:27017/cohort-tools-api";async () + +async function connectDB () { + +if(mongoose.connection.readyState === 1) +{return +try { +const response = await mongoose.connect(process.env.MONGODB_URI); +const dbName = response.connections[0].name; +console.log(`Connected to Mongo! Database name: "${dbName}"`); +} catch (err) { +console.error("Error connecting to mongo: ", err); +} +} + +mongoose + .connect(MONGO_URI) + .then((x) => console.log(`Connect to Database:"${x.connections[0].name}"`)) + + .catch((err) => console.error("Error connecting to MongoDB", err)); + + + + + +} + + +module.exports = connectDB + + diff --git a/server/errors/index.js b/server/errors/index.js new file mode 100644 index 00000000..916ea114 --- /dev/null +++ b/server/errors/index.js @@ -0,0 +1,22 @@ +function errorHandling(app) { + + + +//error handling for 404 errors +app.use((req, res) => { + res.status(404).json({ errorMessage: "Sorry, route not found" }); +}); + +// error handling for 500 errors +app.use((error, req, res, next) => { + // express know this is the 500 error handler just because it has 4 parameters. + console.log(error); + res + .status(500) + .json({ errorMessage: "something went BOOM, sorry about this" }); +}); + +} + + +module.exports = errorHandling \ No newline at end of file diff --git a/server/mongoose_schema/cohort.model.js b/server/models/cohort.model.js similarity index 100% rename from server/mongoose_schema/cohort.model.js rename to server/models/cohort.model.js diff --git a/server/mongoose_schema/student.model.js b/server/models/student.model.js similarity index 100% rename from server/mongoose_schema/student.model.js rename to server/models/student.model.js diff --git a/server/models/user.models.js b/server/models/user.models.js new file mode 100644 index 00000000..a8e4c670 --- /dev/null +++ b/server/models/user.models.js @@ -0,0 +1,26 @@ +const { Schema, model } = require("mongoose"); + +const userSchema = new Schema( + { + email: { + type: String, + required: [true, "Email is required."], + unique: true, + lowercase: true, + trim: true, + }, + password: { + type: String, + required: [true, "Password is required."], + }, + username: String, + }, + { + // this second object adds extra properties: `createdAt` and `updatedAt` + timestamps: true, + }, +); + +const User = model("User", userSchema); + +module.exports = User; diff --git a/server/package-lock.json b/server/package-lock.json index 7fdd4e42..e00693ca 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "bcryptjs": "^3.0.3", "cookie-parser": "^1.4.6", "cors": "^2.8.6", "express": "^4.18.2", @@ -100,6 +101,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -109,22 +119,23 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", + "bytes": "~3.1.2", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -144,11 +155,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -167,17 +179,35 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/call-bind": { + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -224,24 +254,27 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { @@ -290,90 +323,136 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -382,16 +461,17 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -410,6 +490,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -428,24 +509,51 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -457,15 +565,16 @@ "node": ">= 6" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { @@ -476,10 +585,11 @@ "node": ">=4" } }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -487,36 +597,43 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -532,7 +649,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -576,6 +694,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -600,10 +719,20 @@ "node": ">=10" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "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" } @@ -615,9 +744,13 @@ "license": "MIT" }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", @@ -631,6 +764,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -759,15 +893,16 @@ "license": "MIT" }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -898,9 +1033,13 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -909,6 +1048,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -917,9 +1057,10 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -928,19 +1069,22 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -975,11 +1119,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -992,19 +1137,21 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -1043,7 +1190,8 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { "version": "7.5.4", @@ -1060,23 +1208,24 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" @@ -1085,17 +1234,19 @@ "node_modules/send/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==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" @@ -1104,16 +1255,76 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1146,9 +1357,10 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1168,6 +1380,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -1179,6 +1392,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -1210,6 +1424,7 @@ "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" @@ -1227,6 +1442,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } diff --git a/server/package.json b/server/package.json index 06414cdc..9bbc19f3 100644 --- a/server/package.json +++ b/server/package.json @@ -18,6 +18,7 @@ }, "homepage": "https://github.com/ironhack-labs/cohort-tools-project#readme", "dependencies": { + "bcryptjs": "^3.0.3", "cookie-parser": "^1.4.6", "cors": "^2.8.6", "express": "^4.18.2", diff --git a/server/routes/auth.routes.js b/server/routes/auth.routes.js new file mode 100644 index 00000000..e69de29b diff --git a/server/routes/cohort.routes.js b/server/routes/cohort.routes.js new file mode 100644 index 00000000..e69de29b diff --git a/server/routes/index.routes.js b/server/routes/index.routes.js new file mode 100644 index 00000000..e69de29b diff --git a/server/routes/students.routes.js b/server/routes/students.routes.js new file mode 100644 index 00000000..e69de29b From 66fc3be453f4d2da59f89d16c748020b859cf24b Mon Sep 17 00:00:00 2001 From: Aybike Celebi Visser Date: Fri, 15 May 2026 17:38:53 +0200 Subject: [PATCH 07/10] day5comp --- server/app.js | 187 ++----------------------------- server/routes/auth.routes.js | 64 +++++++++++ server/routes/cohort.routes.js | 87 ++++++++++++++ server/routes/index.routes.js | 31 +++++ server/routes/student.routes.js | 102 +++++++++++++++++ server/routes/students.routes.js | 0 6 files changed, 294 insertions(+), 177 deletions(-) create mode 100644 server/routes/student.routes.js delete mode 100644 server/routes/students.routes.js diff --git a/server/app.js b/server/app.js index 656723b6..20b99e74 100644 --- a/server/app.js +++ b/server/app.js @@ -1,6 +1,9 @@ -const PORT = 5005; -const Cohort = require("./models/cohort.model.js"); -const Student = require("./models/student.model.js"); +try { + process.loadEnvFile() +} catch(error) { + console.warn(".env file not found, using default environment values") +} + const express = require("express") const User = require("./models/user.models.js") @@ -20,6 +23,8 @@ next() } ) +const indexRouter = require("./routes/index.routes.js") +app.use("/api", indexRouter) const errorHandling = require("./errors") errorHandling(app) @@ -27,6 +32,7 @@ errorHandling(app) + // INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express // ROUTES - https://expressjs.com/en/starter/basic-routing.html @@ -37,185 +43,12 @@ app.get("/docs", (req, res) => { }); //const cohorts = require("./cohorts.json") -app.get("/api/cohorts", async (req, res) => { - try { - const response = await Cohort.find(); - res.status(200).json(response); - res.json(response); - } catch (error) { - console.log(error); - } -}); -app.post("/api/cohorts", (req, res) => { - console.log(req.body); - - const newCohort = { - inProgress: req.body.inProgress, - cohortSlug: req.body.cohortSlug, - cohortName: req.body.cohortName, - program: req.body.program, - campus: req.body.campus, - startDate: req.body.startDate, - endDate: req.body.endDate, - programManager: req.body.programManager, - leadTeacher: req.body.leadTeacher, - totalHours: req.body.totalHours, - }; - Cohort.create(newCohort) - .then(() => { - res.send("Cohort Created"); - }) - .catch((error) => { - console.log(error); - }); -}); - -app.get("/api/cohorts/:cohortId", async (req, res) => { - try { - const response = await Cohort.findById(req.params.cohortId); - res.status(200).json(response); - } catch (error) { - next(error); - } -}); -app.put("/api/cohorts/:cohortId", async (req, res, next) => { - console.log(req.params); - console.log(req.body); - - try { - const updatedCohort = { - inProgress: req.body.inProgress, - cohortSlug: req.body.cohortSlug, - cohortName: req.body.cohortName, - program: req.body.program, - campus: req.body.campus, - startDate: req.body.startDate, - endDate: req.body.endDate, - programManager: req.body.programManager, - leadTeacher: req.body.leadTeacher, - totalHours: req.body.totalHours, - }; - const response = await Cohort.findByIdAndUpdate( - req.params.cohortId, - updatedCohort, - ); - - res.status(202).send("cohort updated"); - } catch (error) { - next(error); - } -}); - -app.delete("/api/cohorts/:cohortId", async (req, res) => { - try { - const response = await Cohort.findByIdAndDelete(req.params.cohortId); - res.status(202).json(response); - } catch (error) { - next(error); - } -}); - -//const students = require("./students.json") -app.get("/api/students", async (req, res) => { - try { - const response = await Student.find().populate("cohort"); - res.status(200).json(response); - } catch (error) { - next(error); - } -}); - -app.post("/api/students", (req, res) => { - //1. we need to receive a body - console.log(req.body); - //2. we need to go into the db to create something - - const newStudent = { - firstName: req.body.firstName, - lastName: req.body.lastName, - email: req.body.email, - phone: req.body.phone, - linkedinUrl: req.body.linkedinUrl, - languages: req.body.languages, - program: req.body.program, - background: req.body.background, - image: req.body.image, - projects: req.body.projects, - cohort: req.body.cohort, - }; - Student.create(newStudent) - .then(() => { - res.sendStatus(201); - }) - .catch((error) => { - console.log(error); - }); -}); - -app.get("/api/students/:studentId", async (req, res) => { - try { - const response = await Student.findById(req.params.studentId).populate( - "cohort", - ); - res.status(200).json(response); - } catch (error) { - next(error); - } -}); - -app.put("/api/students/:studentId", async (req, res, next) => { - console.log(req.params); - console.log(req.body); - - try { - const updatedStudent = { - firstName: req.body.firstName, - lastName: req.body.lastName, - email: req.body.email, - phone: req.body.phone, - linkedinUrl: req.body.linkedinUrl, - languages: req.body.languages, - program: req.body.program, - background: req.body.background, - image: req.body.image, - projects: req.body.projects, - }; - const response = await Student.findByIdAndUpdate( - req.params.studentId, - updatedStudent, - ); - - res.sendStatus(202).send("student updated"); - } catch (error) { - next(error); - } -}); - -app.get("/api/students/cohort/:cohortId", async (req, res, next) => { - try { - const studentsBelongCohort = await Student.find({ - cohort: req.params.cohortId, - }).populate("cohort"); - res.status(200).json(studentsBelongCohort); - } catch (error) { - next(error); - } -}); - -app.delete("/api/students/:studentId", async (req, res) => { - try { - const response = await Student.findByIdAndDelete(req.params.studentId); - res.status(200).json(response); - } catch (error) { - next(error); - } -}); // START SERVER app.listen(PORT, () => { - console.log(`Server listening on port ${PORT}`); + console.log(`Server listening on port ${process.env.PORT}`); }); diff --git a/server/routes/auth.routes.js b/server/routes/auth.routes.js index e69de29b..74f9cbbb 100644 --- a/server/routes/auth.routes.js +++ b/server/routes/auth.routes.js @@ -0,0 +1,64 @@ +const router = require("express").Router() + +const User = require("../models/user.models.js") + +const bcrypt = require("bcryptjs") + +// POST "/api/auth/signup" => creates the user document +router.post("/signup", async (req, res, next) => { + + // email, username, password + console.log(req.body) + const { email, username, password } = req.body + + // both email and password are mandatory + if (!email || !password) { + res.status(400).json({errorMessage: "Both email and password are mandatory"}) + return // this means, stop executing the route + } + + // password strong enough + const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm + + if (passwordRegex.test(password) === false) { + res.status(400).json({errorMessage: "Password is not strong enough. It needs at least 8 characters, one uppercase, one lowercase and one number"}) + return // this means, stop executing the route + } + + // email format should be correct. xxx-@xxx-.xx- + // ... done finding the proper regex + + // extra security (sending an email for email verification). Use packages like nodemailer, mailchimp and brevo. + + try { + // email should be unique + const foundUser = await User.findOne({ email: email }) // either the user or null + if (foundUser) { + res.status(400).json({errorMessage: "user already created with that email"}) + return // this means, stop executing the route + } + + const hashedPassword = await bcrypt.hash(password, 12) + + //... create the user + const newUser = { + email: email, + username: username, + password: hashedPassword + } + + const response = await User.create(newUser) + + res.sendStatus(201) + } catch (error) { + next(error) + } +}) + + + + + + + +module.exports = router \ No newline at end of file diff --git a/server/routes/cohort.routes.js b/server/routes/cohort.routes.js index e69de29b..879e0245 100644 --- a/server/routes/cohort.routes.js +++ b/server/routes/cohort.routes.js @@ -0,0 +1,87 @@ +const express = require("express") +const router = express.Router() + +const Cohort = require("../models/cohort.model.js") + + +router.get("/", async (req, res) => { + try { + const response = await Cohort.find(); + res.status(200).json(response); + res.json(response); + } catch (error) { + console.log(error); + } +}); + +router.post("/", (req, res) => { + console.log(req.body); + + const newCohort = { + inProgress: req.body.inProgress, + cohortSlug: req.body.cohortSlug, + cohortName: req.body.cohortName, + program: req.body.program, + campus: req.body.campus, + startDate: req.body.startDate, + endDate: req.body.endDate, + programManager: req.body.programManager, + leadTeacher: req.body.leadTeacher, + totalHours: req.body.totalHours, + }; + Cohort.create(newCohort) + .then(() => { + res.send("Cohort Created"); + }) + .catch((error) => { + console.log(error); + }); +}); + +router.get("/:cohortId", async (req, res) => { + try { + const response = await Cohort.findById(req.params.cohortId); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); + +router.put("/:cohortId", async (req, res, next) => { + console.log(req.params); + console.log(req.body); + + try { + const updatedCohort = { + inProgress: req.body.inProgress, + cohortSlug: req.body.cohortSlug, + cohortName: req.body.cohortName, + program: req.body.program, + campus: req.body.campus, + startDate: req.body.startDate, + endDate: req.body.endDate, + programManager: req.body.programManager, + leadTeacher: req.body.leadTeacher, + totalHours: req.body.totalHours, + }; + const response = await Cohort.findByIdAndUpdate( + req.params.cohortId, + updatedCohort, + ); + + res.status(202).send("cohort updated"); + } catch (error) { + next(error); + } +}); + +router.delete("/:cohortId", async (req, res) => { + try { + const response = await Cohort.findByIdAndDelete(req.params.cohortId); + res.status(202).json(response); + } catch (error) { + next(error); + } +}); + +module.exports = router \ No newline at end of file diff --git a/server/routes/index.routes.js b/server/routes/index.routes.js index e69de29b..44c4a86a 100644 --- a/server/routes/index.routes.js +++ b/server/routes/index.routes.js @@ -0,0 +1,31 @@ +try { + process.loadEnvFile() +} catch(error) { + console.warn(".env file not found, using default environment values") +} + + +const express = require("express") +const router = express.Router() + + +router.get("/test", (req, res, next) => { + + console.log(req.body) + console.log(req.query) + console.log(req.params) + + res.status(200).json({ message: "all good here!" }) +}) + + +const studentRoutes = require("./student.routes.js") +router.use("/students", studentRoutes) + +const cohortRoutes = require("./cohort.routes.js") +router.use("/cohorts", cohortRoutes) + +const authRoutes = require("./auth.routes.js") +router.use("/auth", authRoutes) + +module.exports = router \ No newline at end of file diff --git a/server/routes/student.routes.js b/server/routes/student.routes.js new file mode 100644 index 00000000..87dbb327 --- /dev/null +++ b/server/routes/student.routes.js @@ -0,0 +1,102 @@ +const express = require("express") +const router = express.Router() + +const Student = require("../models/student.model.js"); + +//const students = require("./students.json") +router.get("/", async (req, res) => { + try { + const response = await Student.find().populate("cohort"); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); + +router.post("/", (req, res) => { + //1. we need to receive a body + console.log(req.body); + //2. we need to go into the db to create something + + const newStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + cohort: req.body.cohort, + }; + Student.create(newStudent) + .then(() => { + res.sendStatus(201); + }) + .catch((error) => { + console.log(error); + }); +}); + +router.get("/:studentId", async (req, res) => { + try { + const response = await Student.findById(req.params.studentId).populate( + "cohort", + ); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); + +router.put("/:studentId", async (req, res, next) => { + console.log(req.params); + console.log(req.body); + + try { + const updatedStudent = { + firstName: req.body.firstName, + lastName: req.body.lastName, + email: req.body.email, + phone: req.body.phone, + linkedinUrl: req.body.linkedinUrl, + languages: req.body.languages, + program: req.body.program, + background: req.body.background, + image: req.body.image, + projects: req.body.projects, + }; + const response = await Student.findByIdAndUpdate( + req.params.studentId, + updatedStudent, + ); + + res.sendStatus(202).send("student updated"); + } catch (error) { + next(error); + } +}); + +router.get("/cohort/:cohortId", async (req, res, next) => { + try { + const studentsBelongCohort = await Student.find({ + cohort: req.params.cohortId, + }).populate("cohort"); + res.status(200).json(studentsBelongCohort); + } catch (error) { + next(error); + } +}); + +router.delete("/:studentId", async (req, res) => { + try { + const response = await Student.findByIdAndDelete(req.params.studentId); + res.status(200).json(response); + } catch (error) { + next(error); + } +}); + +module.exports = router \ No newline at end of file diff --git a/server/routes/students.routes.js b/server/routes/students.routes.js deleted file mode 100644 index e69de29b..00000000 From 821fdf98526a4b1ea8f22f6c5a128247b4cdd04d Mon Sep 17 00:00:00 2001 From: Aybike Celebi Visser Date: Fri, 15 May 2026 17:40:40 +0200 Subject: [PATCH 08/10] day5 --- server/app.js | 2 ++ server/routes/index.routes.js | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/server/app.js b/server/app.js index 20b99e74..e496c8b9 100644 --- a/server/app.js +++ b/server/app.js @@ -4,6 +4,8 @@ try { console.warn(".env file not found, using default environment values") } +//TODO ask Jorge about PORT not defined + const express = require("express") const User = require("./models/user.models.js") diff --git a/server/routes/index.routes.js b/server/routes/index.routes.js index 44c4a86a..310a6d66 100644 --- a/server/routes/index.routes.js +++ b/server/routes/index.routes.js @@ -1,8 +1,3 @@ -try { - process.loadEnvFile() -} catch(error) { - console.warn(".env file not found, using default environment values") -} const express = require("express") From 7db3ce756beff96120a49fbfacc8ba695474c6be Mon Sep 17 00:00:00 2001 From: 250300G <250300g@gmail.com> Date: Mon, 18 May 2026 15:33:26 +0200 Subject: [PATCH 09/10] day6 --- server/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app.js b/server/app.js index e496c8b9..bdb56a6c 100644 --- a/server/app.js +++ b/server/app.js @@ -51,6 +51,6 @@ app.get("/docs", (req, res) => { // START SERVER -app.listen(PORT, () => { +app.listen(process.env.PORT, () => { console.log(`Server listening on port ${process.env.PORT}`); }); From e648c87b4c2c97155d9f69483fb97af9d2c041a6 Mon Sep 17 00:00:00 2001 From: wildfont Date: Mon, 18 May 2026 16:46:35 +0200 Subject: [PATCH 10/10] lastDay --- client/.env | 2 +- package-lock.json | 150 +++++++++++++++++++++++++ package.json | 5 + server/app.js | 56 +++------ server/config/index.js | 35 +++--- server/db/index.js | 48 ++------ server/middlewares/auth.middlewares.js | 19 ++++ server/models/user.models.js | 1 - server/routes/auth.routes.js | 110 ++++++++++++------ server/routes/index.routes.js | 34 +++--- server/routes/private-routes.routes.js | 11 ++ server/routes/student.routes.js | 9 +- 12 files changed, 321 insertions(+), 159 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 server/middlewares/auth.middlewares.js create mode 100644 server/routes/private-routes.routes.js diff --git a/client/.env b/client/.env index d6af8451..8cff7794 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -VITE_API_URL=http://localhost:5005 +VITE_API_URL=http://localhost:5005/api diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..832cdb21 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,150 @@ +{ + "name": "cohort-tools-project", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "jsonwebtoken": "^9.0.3" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "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/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..256d43d2 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "jsonwebtoken": "^9.0.3" + } +} diff --git a/server/app.js b/server/app.js index bdb56a6c..1fc874ee 100644 --- a/server/app.js +++ b/server/app.js @@ -1,56 +1,32 @@ try { - process.loadEnvFile() -} catch(error) { - console.warn(".env file not found, using default environment values") + process.loadEnvFile(__dirname + "/.env"); +} catch (error) { + console.warn(".env file not found, using default environment values"); } -//TODO ask Jorge about PORT not defined - -const express = require("express") -const User = require("./models/user.models.js") - +const express = require("express"); +const User = require("./models/user.models.js"); const app = express(); -const config = require("./config") -config(app) - -// STATIC DATA -// Devs Team - Import the provided files with JSON data of students and cohorts here: -// ... - -const connectDB = require("./db") -app.use( async (req, res, next) => { -await connectDB() -next() - -} ) - -const indexRouter = require("./routes/index.routes.js") -app.use("/api", indexRouter) - -const errorHandling = require("./errors") -errorHandling(app) - - +const config = require("./config"); +config(app); +const connectDB = require("./db"); +app.use(async (req, res, next) => { + await connectDB(); + next(); +}); +const indexRouter = require("./routes/index.routes.js"); +app.use("/api", indexRouter); -// INITIALIZE EXPRESS APP - https://expressjs.com/en/4x/api.html#express +const errorHandling = require("./errors"); +errorHandling(app); -// ROUTES - https://expressjs.com/en/starter/basic-routing.html -// Devs Team - Start working on the routes here: -// ... app.get("/docs", (req, res) => { res.sendFile(__dirname + "/views/docs.html"); }); -//const cohorts = require("./cohorts.json") - - - - - -// START SERVER app.listen(process.env.PORT, () => { console.log(`Server listening on port ${process.env.PORT}`); }); diff --git a/server/config/index.js b/server/config/index.js index df5f4f64..a78174db 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -1,29 +1,20 @@ const express = require("express"); const cors = require("cors"); const morgan = require("morgan"); - const cookieParser = require("cookie-parser"); - - +const cookieParser = require("cookie-parser"); function config(app) { - - - -// MIDDLEWARE -// Research Team - Set up CORS middleware here: -// ... -app.use( - cors({ - origin: process.env.ORIGIN, - }), -); - -app.use(express.json()); -app.use(morgan("dev")); -app.use(express.static("public")); -app.use(express.urlencoded({ extended: false })); -app.use(cookieParser()); - + app.use( + cors({ + origin: process.env.ORIGIN, + }), + ); + + app.use(express.json()); + app.use(morgan("dev")); + app.use(express.static("public")); + app.use(express.urlencoded({ extended: false })); + app.use(cookieParser()); } -module.exports = config +module.exports = config; diff --git a/server/db/index.js b/server/db/index.js index 171d1a41..e2ffc110 100644 --- a/server/db/index.js +++ b/server/db/index.js @@ -1,38 +1,14 @@ -const mongoose = require("mongoose") - - - -// :information_source: Connects to MongoDB using the URI from environment variables. - - -//const MONGO_URI = "mongodb://127.0.0.1:27017/cohort-tools-api";async () - -async function connectDB () { - -if(mongoose.connection.readyState === 1) -{return -try { -const response = await mongoose.connect(process.env.MONGODB_URI); -const dbName = response.connections[0].name; -console.log(`Connected to Mongo! Database name: "${dbName}"`); -} catch (err) { -console.error("Error connecting to mongo: ", err); -} +const mongoose = require("mongoose"); + +async function connectDB() { + if (mongoose.connection.readyState === 1) return; + try { + const response = await mongoose.connect(process.env.MONGODB_URI); + const dbName = response.connections[0].name; + console.log(`Connected to Mongo! Database name: "${dbName}"`); + } catch (err) { + console.error("Error connecting to mongo: ", err); + } } - -mongoose - .connect(MONGO_URI) - .then((x) => console.log(`Connect to Database:"${x.connections[0].name}"`)) - - .catch((err) => console.error("Error connecting to MongoDB", err)); - - - - - -} - - -module.exports = connectDB - +module.exports = connectDB; diff --git a/server/middlewares/auth.middlewares.js b/server/middlewares/auth.middlewares.js new file mode 100644 index 00000000..bbef425f --- /dev/null +++ b/server/middlewares/auth.middlewares.js @@ -0,0 +1,19 @@ +const jwt = require("jsonwebtoken"); + +function verifyToken(req, res, next) { + try { + console.log(req.headers); + + const authToken = req.headers.authorization.split(" ")[1]; + + const payload = jwt.verify(authToken, process.env.TOKEN_SECRET); + + req.payload = payload; + + next(); + } catch (error) { + res.status(401).json({ errorMessage: "Token not provided or not valid" }); + } +} + +module.exports = verifyToken; diff --git a/server/models/user.models.js b/server/models/user.models.js index a8e4c670..fbed94e8 100644 --- a/server/models/user.models.js +++ b/server/models/user.models.js @@ -16,7 +16,6 @@ const userSchema = new Schema( username: String, }, { - // this second object adds extra properties: `createdAt` and `updatedAt` timestamps: true, }, ); diff --git a/server/routes/auth.routes.js b/server/routes/auth.routes.js index 74f9cbbb..989ee3ed 100644 --- a/server/routes/auth.routes.js +++ b/server/routes/auth.routes.js @@ -1,64 +1,104 @@ -const router = require("express").Router() +const router = require("express").Router(); -const User = require("../models/user.models.js") +const User = require("../models/user.models.js"); -const bcrypt = require("bcryptjs") +const bcrypt = require("bcryptjs"); +const jwt = require("jsonwebtoken"); -// POST "/api/auth/signup" => creates the user document -router.post("/signup", async (req, res, next) => { +const verifyToken = require("../middlewares/auth.middlewares"); - // email, username, password - console.log(req.body) - const { email, username, password } = req.body +router.post("/signup", async (req, res, next) => { + console.log(req.body); + const { email, username, password } = req.body; - // both email and password are mandatory if (!email || !password) { - res.status(400).json({errorMessage: "Both email and password are mandatory"}) - return // this means, stop executing the route + res + .status(400) + .json({ errorMessage: "Both email and password are mandatory" }); + return; } - - // password strong enough - const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm + + const passwordRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm; if (passwordRegex.test(password) === false) { - res.status(400).json({errorMessage: "Password is not strong enough. It needs at least 8 characters, one uppercase, one lowercase and one number"}) - return // this means, stop executing the route + res.status(400).json({ + errorMessage: + "Password is not strong enough. It needs at least 8 characters, one uppercase, one lowercase and one number", + }); + return; } - - // email format should be correct. xxx-@xxx-.xx- - // ... done finding the proper regex - // extra security (sending an email for email verification). Use packages like nodemailer, mailchimp and brevo. - try { - // email should be unique - const foundUser = await User.findOne({ email: email }) // either the user or null + const foundUser = await User.findOne({ email: email }); if (foundUser) { - res.status(400).json({errorMessage: "user already created with that email"}) - return // this means, stop executing the route + res + .status(400) + .json({ errorMessage: "user already created with that email" }); + return; } - const hashedPassword = await bcrypt.hash(password, 12) - - //... create the user + const hashedPassword = await bcrypt.hash(password, 12); + const newUser = { email: email, username: username, - password: hashedPassword - } + password: hashedPassword, + }; - const response = await User.create(newUser) + const response = await User.create(newUser); - res.sendStatus(201) + res.sendStatus(201); } catch (error) { - next(error) + next(error); } -}) +}); +router.post("/login", async (req, res, next) => { + console.log(req.body); + const { email, password } = req.body; + if (!email || !password) { + res + .status(400) + .json({ errorMessage: "Both email and password are mandatory" }); + return; + } + try { + const foundUser = await User.findOne({ email: email }); + console.log(foundUser); + if (!foundUser) { + res.status(400).json({ + errorMessage: "user not found with that email, please signup first", + }); + return; + } + + const isPasswordMatch = await bcrypt.compare(password, foundUser.password); + if (!isPasswordMatch) { + res.status(400).json({ errorMessage: "the password is not correct" }); + return; + } + + const payload = { + _id: foundUser._id, + email: foundUser.email, + }; + const tokenConfig = { + expiresIn: "7d", + }; + const authToken = jwt.sign(payload, process.env.TOKEN_SECRET, tokenConfig); + + res.status(200).json({ authToken, payload }); + } catch (error) { + next(error); + } +}); +router.get("/verify", verifyToken, (req, res) => { + res.status(200).json({ payload: req.payload }); +}); -module.exports = router \ No newline at end of file +module.exports = router; diff --git a/server/routes/index.routes.js b/server/routes/index.routes.js index 310a6d66..da0cf854 100644 --- a/server/routes/index.routes.js +++ b/server/routes/index.routes.js @@ -1,26 +1,24 @@ - - -const express = require("express") -const router = express.Router() - +const express = require("express"); +const router = express.Router(); router.get("/test", (req, res, next) => { - - console.log(req.body) - console.log(req.query) - console.log(req.params) + console.log(req.body); + console.log(req.query); + console.log(req.params); - res.status(200).json({ message: "all good here!" }) -}) + res.status(200).json({ message: "all good here!" }); +}); +const studentRoutes = require("./student.routes.js"); +router.use("/students", studentRoutes); -const studentRoutes = require("./student.routes.js") -router.use("/students", studentRoutes) +const cohortRoutes = require("./cohort.routes.js"); +router.use("/cohorts", cohortRoutes); -const cohortRoutes = require("./cohort.routes.js") -router.use("/cohorts", cohortRoutes) +const authRoutes = require("./auth.routes.js"); +router.use("/auth", authRoutes); -const authRoutes = require("./auth.routes.js") -router.use("/auth", authRoutes) +const privateRoutes = require("./private-routes.routes.js"); +router.use("/private-routes", privateRoutes); -module.exports = router \ No newline at end of file +module.exports = router; diff --git a/server/routes/private-routes.routes.js b/server/routes/private-routes.routes.js new file mode 100644 index 00000000..ca167d3f --- /dev/null +++ b/server/routes/private-routes.routes.js @@ -0,0 +1,11 @@ +const router = require("express").Router(); + +const verifyToken = require("../middlewares/auth.middlewares"); + +router.get("/", verifyToken, (req, res) => { + console.log(req.payload); + + res.send("sending super secret information"); +}); + +module.exports = router; diff --git a/server/routes/student.routes.js b/server/routes/student.routes.js index 87dbb327..76e5e5c0 100644 --- a/server/routes/student.routes.js +++ b/server/routes/student.routes.js @@ -1,9 +1,8 @@ -const express = require("express") -const router = express.Router() +const express = require("express"); +const router = express.Router(); const Student = require("../models/student.model.js"); -//const students = require("./students.json") router.get("/", async (req, res) => { try { const response = await Student.find().populate("cohort"); @@ -14,9 +13,7 @@ router.get("/", async (req, res) => { }); router.post("/", (req, res) => { - //1. we need to receive a body console.log(req.body); - //2. we need to go into the db to create something const newStudent = { firstName: req.body.firstName, @@ -99,4 +96,4 @@ router.delete("/:studentId", async (req, res) => { } }); -module.exports = router \ No newline at end of file +module.exports = router;