mirror of
https://github.com/donavon04/DocuCenter.git
synced 2025-01-18 09:40:56 -07:00
Changes, so many changes
This commit is contained in:
parent
5586c740bf
commit
1af235296c
@ -1,5 +1,7 @@
|
|||||||
MONGODB_URI='mongodb://localhost:27017'
|
MONGODB_URI='mongodb://localhost:27017'
|
||||||
|
MONGODB_NAME='docucenter'
|
||||||
|
|
||||||
|
NODE_ENV='development' #If set to production it will require https to function
|
||||||
|
|
||||||
|
JWT_SECRET='IjkAORBx^cLYpSb6Btz@te&vAJ3Pt*$z'
|
||||||
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_ID='3cdfac60-e7fb-4648-89d3-67966c497d35'
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_SECRET='5Gi8Q~_pmDtvN3.Jwqt85kiI.uiyAAC7Z.4iFayY'
|
|
||||||
AUTH_MICROSOFT_ENTRA_ID_ISSUER='538b9b1c-23fa-4102-b36e-a4d83fc9c4c1'
|
|
@ -22,7 +22,6 @@ app.use(express.urlencoded({ limit: '100mb', extended: true })); // For URL-enco
|
|||||||
const allowedOrigins = [
|
const allowedOrigins = [
|
||||||
'https://docucenter.mpe.ca', // Production frontend
|
'https://docucenter.mpe.ca', // Production frontend
|
||||||
'http://localhost:5173', // Development frontend
|
'http://localhost:5173', // Development frontend
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const corsOptions = {
|
const corsOptions = {
|
||||||
|
539
backend/package-lock.json
generated
539
backend/package-lock.json
generated
@ -10,13 +10,17 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/msal-node": "^2.16.2",
|
"@azure/msal-node": "^2.16.2",
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
|
"cookie-parser": "^1.4.7",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
"mariadb": "^3.4.0",
|
"mariadb": "^3.4.0",
|
||||||
"mongodb": "^6.12.0",
|
"mongodb": "^6.12.0",
|
||||||
|
"mongoose": "^8.9.0",
|
||||||
|
"nodemailer": "^6.9.16",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-azure-ad": "^4.3.5",
|
"passport-azure-ad": "^4.3.5",
|
||||||
"redis": "^4.7.0"
|
"redis": "^4.7.0"
|
||||||
@ -45,6 +49,60 @@
|
|||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mapbox/node-pre-gyp": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.0",
|
||||||
|
"https-proxy-agent": "^5.0.0",
|
||||||
|
"make-dir": "^3.1.0",
|
||||||
|
"node-fetch": "^2.6.7",
|
||||||
|
"nopt": "^5.0.0",
|
||||||
|
"npmlog": "^5.0.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"semver": "^7.3.5",
|
||||||
|
"tar": "^6.1.11"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-pre-gyp": "bin/node-pre-gyp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mapbox/node-pre-gyp/node_modules/glob": {
|
||||||
|
"version": "7.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
|
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||||
|
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||||
|
"dependencies": {
|
||||||
|
"fs.realpath": "^1.0.0",
|
||||||
|
"inflight": "^1.0.4",
|
||||||
|
"inherits": "2",
|
||||||
|
"minimatch": "^3.1.1",
|
||||||
|
"once": "^1.3.0",
|
||||||
|
"path-is-absolute": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mongodb-js/saslprep": {
|
"node_modules/@mongodb-js/saslprep": {
|
||||||
"version": "1.1.9",
|
"version": "1.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
|
||||||
@ -138,6 +196,11 @@
|
|||||||
"@types/webidl-conversions": "*"
|
"@types/webidl-conversions": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/abbrev": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
@ -182,6 +245,32 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"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=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/aproba": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
|
||||||
|
},
|
||||||
|
"node_modules/are-we-there-yet": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
|
||||||
|
"deprecated": "This package is no longer supported.",
|
||||||
|
"dependencies": {
|
||||||
|
"delegates": "^1.0.0",
|
||||||
|
"readable-stream": "^3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
@ -195,8 +284,7 @@
|
|||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
@ -225,6 +313,19 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bcrypt": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@mapbox/node-pre-gyp": "^1.0.11",
|
||||||
|
"node-addon-api": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.3",
|
"version": "1.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||||
@ -252,7 +353,6 @@
|
|||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@ -375,6 +475,14 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cluster-key-slot": {
|
"node_modules/cluster-key-slot": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
@ -384,11 +492,23 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color-support": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||||
|
"bin": {
|
||||||
|
"color-support": "bin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||||
"optional": true
|
},
|
||||||
|
"node_modules/console-control-strings": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
|
||||||
},
|
},
|
||||||
"node_modules/content-disposition": {
|
"node_modules/content-disposition": {
|
||||||
"version": "0.5.4",
|
"version": "0.5.4",
|
||||||
@ -417,6 +537,26 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cookie-parser": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.7.2",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cookie-parser/node_modules/cookie": {
|
||||||
|
"version": "0.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||||
|
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cookie-signature": {
|
"node_modules/cookie-signature": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
@ -458,6 +598,11 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delegates": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
|
||||||
|
},
|
||||||
"node_modules/denque": {
|
"node_modules/denque": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
@ -483,6 +628,14 @@
|
|||||||
"npm": "1.2.8000 || >= 1.4.16"
|
"npm": "1.2.8000 || >= 1.4.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.4.7",
|
"version": "16.4.7",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||||
@ -534,6 +687,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||||
},
|
},
|
||||||
|
"node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||||
|
},
|
||||||
"node_modules/encodeurl": {
|
"node_modules/encodeurl": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||||
@ -685,6 +843,33 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fs-minipass": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs-minipass/node_modules/minipass": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs.realpath": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
@ -693,6 +878,26 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/gauge": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
|
||||||
|
"deprecated": "This package is no longer supported.",
|
||||||
|
"dependencies": {
|
||||||
|
"aproba": "^1.0.3 || ^2.0.0",
|
||||||
|
"color-support": "^1.1.2",
|
||||||
|
"console-control-strings": "^1.0.0",
|
||||||
|
"has-unicode": "^2.0.1",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"signal-exit": "^3.0.0",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"strip-ansi": "^6.0.1",
|
||||||
|
"wide-align": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/generic-pool": {
|
"node_modules/generic-pool": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
|
||||||
@ -773,6 +978,11 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-unicode": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||||
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
@ -867,7 +1077,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
@ -886,6 +1095,14 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsonwebtoken": {
|
"node_modules/jsonwebtoken": {
|
||||||
"version": "9.0.2",
|
"version": "9.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||||
@ -935,6 +1152,14 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/kareem": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
@ -997,6 +1222,28 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/make-dir": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/make-dir/node_modules/semver": {
|
||||||
|
"version": "6.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mariadb": {
|
"node_modules/mariadb": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.4.0.tgz",
|
||||||
@ -1086,7 +1333,6 @@
|
|||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
},
|
},
|
||||||
@ -1103,6 +1349,37 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/minipass": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minizlib": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minizlib/node_modules/minipass": {
|
||||||
|
"version": "3.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||||
|
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
@ -1178,6 +1455,72 @@
|
|||||||
"whatwg-url": "^13.0.0"
|
"whatwg-url": "^13.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mongoose": {
|
||||||
|
"version": "8.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.0.tgz",
|
||||||
|
"integrity": "sha512-b58zY3PLNBcoz6ZXFckr0leJcVVBMAOBvD+7Bj2ZjghAwntXmNnqwlDixTKQU3UYoQIGTv+AQx/0ThsvaeVrCA==",
|
||||||
|
"dependencies": {
|
||||||
|
"bson": "^6.10.1",
|
||||||
|
"kareem": "2.6.3",
|
||||||
|
"mongodb": "~6.12.0",
|
||||||
|
"mpath": "0.9.0",
|
||||||
|
"mquery": "5.0.0",
|
||||||
|
"ms": "2.1.3",
|
||||||
|
"sift": "17.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.20.1"
|
||||||
|
},
|
||||||
|
"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=="
|
||||||
|
},
|
||||||
|
"node_modules/mpath": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mquery": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "4.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mquery/node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mquery/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=="
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
@ -1220,6 +1563,49 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch/node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||||
@ -1256,6 +1642,40 @@
|
|||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nodemailer": {
|
||||||
|
"version": "6.9.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
|
||||||
|
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nopt": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"abbrev": "1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nopt": "bin/nopt.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/npmlog": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
|
||||||
|
"deprecated": "This package is no longer supported.",
|
||||||
|
"dependencies": {
|
||||||
|
"are-we-there-yet": "^2.0.0",
|
||||||
|
"console-control-strings": "^1.1.0",
|
||||||
|
"gauge": "^3.0.0",
|
||||||
|
"set-blocking": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/oauth": {
|
"node_modules/oauth": {
|
||||||
"version": "0.9.15",
|
"version": "0.9.15",
|
||||||
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
|
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
|
||||||
@ -1303,7 +1723,6 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@ -1389,7 +1808,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -1476,6 +1894,19 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/redis": {
|
"node_modules/redis": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz",
|
||||||
@ -1598,6 +2029,11 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||||
|
},
|
||||||
"node_modules/set-function-length": {
|
"node_modules/set-function-length": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||||
@ -1636,6 +2072,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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=="
|
||||||
|
},
|
||||||
|
"node_modules/signal-exit": {
|
||||||
|
"version": "3.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||||
|
},
|
||||||
"node_modules/sparse-bitfield": {
|
"node_modules/sparse-bitfield": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||||
@ -1652,6 +2098,65 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"minipass": "^5.0.0",
|
||||||
|
"minizlib": "^2.1.1",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@ -1707,6 +2212,11 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
|
},
|
||||||
"node_modules/utils-merge": {
|
"node_modules/utils-merge": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
@ -1757,11 +2267,18 @@
|
|||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wide-align": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/wrappy": {
|
"node_modules/wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
@ -11,13 +11,17 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/msal-node": "^2.16.2",
|
"@azure/msal-node": "^2.16.2",
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
|
"cookie-parser": "^1.4.7",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
"mariadb": "^3.4.0",
|
"mariadb": "^3.4.0",
|
||||||
"mongodb": "^6.12.0",
|
"mongodb": "^6.12.0",
|
||||||
|
"mongoose": "^8.9.0",
|
||||||
|
"nodemailer": "^6.9.16",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-azure-ad": "^4.3.5",
|
"passport-azure-ad": "^4.3.5",
|
||||||
"redis": "^4.7.0"
|
"redis": "^4.7.0"
|
||||||
|
51
backend/server.js
Normal file
51
backend/server.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const express = require('express');
|
||||||
|
const cors = require('cors');
|
||||||
|
const connectDB = require('./src/utils/database');
|
||||||
|
//Import routes
|
||||||
|
const userRoutes = require('./src/routes/userRoutes');
|
||||||
|
const authRoutes = require('./src/routes/authRoutes');
|
||||||
|
const documentRoutes = require('./src/routes/documentRoutes');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(express.urlencoded({ extended: true })); // Parses form data
|
||||||
|
app.use(express.json()); // Parses JSON data
|
||||||
|
|
||||||
|
// Configure CORS to allow specific origins
|
||||||
|
const allowedOrigins = [
|
||||||
|
'https://docucenter.mpe.ca', // Production frontend
|
||||||
|
'http://localhost:5173', // Development frontend
|
||||||
|
];
|
||||||
|
|
||||||
|
const corsOptions = {
|
||||||
|
origin: (origin, callback) => {
|
||||||
|
// Allow requests with no origin (e.g., mobile apps or curl)
|
||||||
|
if (!origin || allowedOrigins.includes(origin)) {
|
||||||
|
callback(null, true);
|
||||||
|
} else {
|
||||||
|
callback(new Error('Not allowed by CORS'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: ['GET', 'POST', 'PUT', 'DELETE'], // Specify allowed HTTP methods
|
||||||
|
allowedHeaders: ['Content-Type', 'Authorization'], // Specify allowed headers
|
||||||
|
credentials: true, // Enable cookies and credentials sharing
|
||||||
|
};
|
||||||
|
|
||||||
|
app.use(cors(corsOptions));
|
||||||
|
|
||||||
|
// Connect to database
|
||||||
|
connectDB();
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
app.use('/api/user', userRoutes);
|
||||||
|
app.use('/api/auth', authRoutes);
|
||||||
|
app.use('/api/document', documentRoutes);
|
||||||
|
|
||||||
|
const PORT = process.env.PORT || 3000;
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Server running on port ${PORT}`);
|
||||||
|
});
|
76
backend/src/controllers/authController.js
Normal file
76
backend/src/controllers/authController.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
const bcrypt = require('bcrypt'); // For password comparison
|
||||||
|
const jwt = require('jsonwebtoken'); // For generating JWTs
|
||||||
|
const User = require('../models/User');
|
||||||
|
const Email = require('../services/Email');
|
||||||
|
const Logger = require('../utils/logger');
|
||||||
|
|
||||||
|
exports.login = async (req, res) => {
|
||||||
|
const { email, password } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Find the user by email
|
||||||
|
const user = await User.findOne({ email });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ message: 'User not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the provided password with the stored hashed password
|
||||||
|
const isMatch = await bcrypt.compare(password, user.password);
|
||||||
|
|
||||||
|
if (!isMatch) {
|
||||||
|
return res.status(401).json({ message: 'Invalid email or password' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a JWT for the authenticated user
|
||||||
|
const token = jwt.sign(
|
||||||
|
{ id: user._id, email: user.email }, // Payload
|
||||||
|
process.env.JWT_SECRET, // Secret key
|
||||||
|
{ expiresIn: '1h' } // Token expiration
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the token was generated successfully
|
||||||
|
if (!token) {
|
||||||
|
return res.status(500).json({ message: 'Error generating authentication token' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the token as an HttpOnly cookie
|
||||||
|
res.cookie('authToken', token, {
|
||||||
|
httpOnly: true, // Cannot be accessed by JavaScript
|
||||||
|
secure: process.env.NODE_ENV === 'production', // Use Secure flag only in production (requires HTTPS)
|
||||||
|
sameSite: 'Strict', // Prevents CSRF attacks
|
||||||
|
maxAge: 3600000, // 1 hour
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a success response without including the token in the body
|
||||||
|
return res.status(200).json({ message: 'Login successful' });
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login error:', error);
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.forgotPassword = async (req, res) => {
|
||||||
|
const { email } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate email and fetch user (omitted for brevity)
|
||||||
|
|
||||||
|
await Email.send(email, 'Test', 'Testttt');
|
||||||
|
Logger.log('email', 'info', 'An email was sent to' + email, 'authController.js');
|
||||||
|
res.status(200).json({ message: 'Password reset email sent!' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.resetPassword = async (req, res) => {
|
||||||
|
const { email, password } = req.body;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getStatus = async (req, res) => {
|
||||||
|
|
||||||
|
res.status(200).json({ authenticated: true, user: req.user });
|
||||||
|
};
|
||||||
|
|
69
backend/src/controllers/documentController.js
Normal file
69
backend/src/controllers/documentController.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
const Document = require('../models/Document');
|
||||||
|
|
||||||
|
exports.createDocument = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const document = new Document(req.body);
|
||||||
|
await document.save();
|
||||||
|
res.status(201).json(document);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getDocument = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const documents = await Document.find();
|
||||||
|
res.json(documents);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getDocumentById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const documentId = req.params.id;
|
||||||
|
|
||||||
|
const document = await Document.findById(documentId);
|
||||||
|
res.json(document);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.updateDocumentById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const documentId = req.params.id;
|
||||||
|
const updates = req.body;
|
||||||
|
|
||||||
|
const updatedDocument = await Document.findByIdAndUpdate(
|
||||||
|
documentId,
|
||||||
|
updates,
|
||||||
|
{ new: true, runValidators: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!updatedDocument) {
|
||||||
|
return res.status(404).json({ message: 'Document not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(updatedDocument);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.deleteDocumentById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const documentId = req.params.id;
|
||||||
|
|
||||||
|
const deletedDocument = await Document.findByIdAndDelete(documentId);
|
||||||
|
|
||||||
|
if (!deletedDocument) {
|
||||||
|
return res.status(404).json({ message: 'Document not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ message: 'Document deleted successfully' });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
70
backend/src/controllers/userController.js
Normal file
70
backend/src/controllers/userController.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const User = require('../models/User');
|
||||||
|
|
||||||
|
exports.createUser = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const user = new User(req.body);
|
||||||
|
await user.save();
|
||||||
|
// Redirect to the login page
|
||||||
|
res.status(201).json(user);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getUsers = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const users = await User.find();
|
||||||
|
res.json(users);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getUserById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.params.id; // Get the ID from the request parameters
|
||||||
|
|
||||||
|
const user = await User.findById(userId);
|
||||||
|
res.json(user);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.updateUserById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.params.id; // Extract user ID from request parameters
|
||||||
|
const updates = req.body; // Data to update from request body
|
||||||
|
|
||||||
|
const updatedUser = await User.findByIdAndUpdate(
|
||||||
|
userId,
|
||||||
|
updates,
|
||||||
|
{ new: true, runValidators: true } // Options: return updated document and run validators
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!updatedUser) {
|
||||||
|
return res.status(404).json({ message: 'User not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(updatedUser); // Send the updated user data
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message }); // Handle any server errors
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.deleteUserById = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.params.id; // Extract user ID from request parameters
|
||||||
|
|
||||||
|
const deletedUser = await User.findByIdAndDelete(userId); // Delete the user by ID
|
||||||
|
|
||||||
|
if (!deletedUser) {
|
||||||
|
return res.status(404).json({ message: 'User not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ message: 'User deleted successfully' }); // Send success message
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: error.message }); // Handle any server errors
|
||||||
|
}
|
||||||
|
};
|
23
backend/src/middleware/authenticateToken.js
Normal file
23
backend/src/middleware/authenticateToken.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const jwt = require('jsonwebtoken');
|
||||||
|
|
||||||
|
const authenticateToken = (req, res, next) => {
|
||||||
|
// Retrieve the token from the Authorization header
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
|
||||||
|
const token = authHeader && authHeader.split(' ')[1]; // Extract the token part after "Bearer"
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return res.status(401).json({ message: 'Access denied. No token provided.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Verify the token
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET); // Use your secret key
|
||||||
|
req.user = decoded; // Attach the decoded token payload to the request object
|
||||||
|
next(); // Proceed to the next middleware or route handler
|
||||||
|
} catch (error) {
|
||||||
|
res.status(403).json({ message: 'Invalid or expired token.' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = authenticateToken;
|
31
backend/src/models/Document.js
Normal file
31
backend/src/models/Document.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
|
const DocumentSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
title: { //Create, Delete, Update, Get
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
visibility: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: "Public",
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
type: [String], //Array of strings
|
||||||
|
required: false,
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
created_by: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ timestamps: true } // Adds createdAt and updatedAt automatically
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Document', DocumentSchema);
|
25
backend/src/models/Log.js
Normal file
25
backend/src/models/Log.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
|
const LogSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
event: { //Create, Delete, Update, Get
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
severity: { //info, warn, error, debug, critical
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
message: { //What happened / extra details
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
source: { //What module the log came from
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ timestamps: true } // Adds createdAt and updatedAt automatically
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Log', LogSchema);
|
50
backend/src/models/User.js
Normal file
50
backend/src/models/User.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const bcrypt = require('bcrypt');
|
||||||
|
|
||||||
|
const UserSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
unique: true, // Ensures no duplicate emails
|
||||||
|
trim: true,
|
||||||
|
match: [/.+@.+\..+/, 'Please enter a valid email address'], // Simple email validation
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: String,
|
||||||
|
required: false, // Optional for OAuth users
|
||||||
|
},
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
required: false, // Optional for OAuth users
|
||||||
|
default: "User", //User = Read, Write Permissions | Admin = Read, Write, Delete Permissions
|
||||||
|
},
|
||||||
|
oauthProviders: [
|
||||||
|
{
|
||||||
|
provider: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
enum: ['microsoft'], // Add other providers as needed
|
||||||
|
},
|
||||||
|
providerId: {
|
||||||
|
type: String,
|
||||||
|
required: false, // Unique ID from the OAuth provider
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ timestamps: true } // Adds createdAt and updatedAt automatically
|
||||||
|
);
|
||||||
|
|
||||||
|
// Hash the password before saving
|
||||||
|
UserSchema.pre('save', async function (next) {
|
||||||
|
if (!this.isModified('password')) return next();
|
||||||
|
this.password = await bcrypt.hash(this.password, 10);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('User', UserSchema);
|
11
backend/src/routes/authRoutes.js
Normal file
11
backend/src/routes/authRoutes.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const authController = require('../controllers/authController');
|
||||||
|
const authenticateToken = require('../middleware/authenticateToken');
|
||||||
|
|
||||||
|
router.get('/status', authenticateToken, authController.getStatus); //Check if the user is authenticated
|
||||||
|
router.post('/login', authController.login); //Check credentials
|
||||||
|
router.post('/forgot-password', authController.forgotPassword); //Forgot password
|
||||||
|
router.put('/reset-password', authController.resetPassword); //Update the password
|
||||||
|
|
||||||
|
module.exports = router;
|
12
backend/src/routes/documentRoutes.js
Normal file
12
backend/src/routes/documentRoutes.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const authenticateToken = require('../middleware/authenticateToken');
|
||||||
|
const router = express.Router();
|
||||||
|
const documentController = require('../controllers/documentController');
|
||||||
|
|
||||||
|
router.post('/', documentController.createDocument); //Create
|
||||||
|
router.get('/', documentController.getDocument); //Get all documents
|
||||||
|
router.get('/:id', documentController.getDocumentById); //Get a document by id
|
||||||
|
router.put('/:id', authenticateToken, documentController.updateDocumentById); //Update a document by id
|
||||||
|
router.delete('/:id', authenticateToken, documentController.deleteDocumentById); //Delete a document by id
|
||||||
|
|
||||||
|
module.exports = router;
|
12
backend/src/routes/userRoutes.js
Normal file
12
backend/src/routes/userRoutes.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const authenticateToken = require('../middleware/authenticateToken');
|
||||||
|
const router = express.Router();
|
||||||
|
const userController = require('../controllers/userController');
|
||||||
|
|
||||||
|
router.post('/', userController.createUser); //Create
|
||||||
|
router.get('/', authenticateToken, userController.getUsers); //Get all users
|
||||||
|
router.get('/:id', authenticateToken, userController.getUserById); //Get a user by id
|
||||||
|
router.put('/:id', authenticateToken, userController.updateUserById); //Update a user by id
|
||||||
|
router.delete('/:id', authenticateToken, userController.deleteUserById); //Delete a user by id
|
||||||
|
|
||||||
|
module.exports = router;
|
21
backend/src/services/Email.js
Normal file
21
backend/src/services/Email.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const nodemailer = require('nodemailer');
|
||||||
|
|
||||||
|
exports.send = async (to, subject, text) => {
|
||||||
|
const transporter = nodemailer.createTransport({
|
||||||
|
service: 'Gmail',
|
||||||
|
auth: {
|
||||||
|
user: process.env.EMAIL_USER,
|
||||||
|
pass: process.env.EMAIL_PASS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const mailOptions = {
|
||||||
|
from: process.env.EMAIL_FROM,
|
||||||
|
to,
|
||||||
|
subject,
|
||||||
|
text,
|
||||||
|
};
|
||||||
|
|
||||||
|
return transporter.sendMail(mailOptions);
|
||||||
|
};
|
||||||
|
|
16
backend/src/utils/database.js
Normal file
16
backend/src/utils/database.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
|
const connectDB = async () => {
|
||||||
|
try {
|
||||||
|
await mongoose.connect(process.env.MONGODB_URI+'/'+ process.env.MONGODB_NAME, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true
|
||||||
|
});
|
||||||
|
console.log('MongoDB connected');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('MongoDB connection error:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = connectDB;
|
11
backend/src/utils/logger.js
Normal file
11
backend/src/utils/logger.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const Log = require('../models/Log');
|
||||||
|
|
||||||
|
exports.log = async (event, severity, message, source) => {
|
||||||
|
try {
|
||||||
|
const log = new Log({event: event, severity: severity, message: message, source: source});
|
||||||
|
await log.save();
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
import { SvelteKitAuth } from "@auth/sveltekit"
|
|
||||||
import Entra from "@auth/sveltekit/providers/microsoft-entra-id"
|
|
||||||
import { env } from "$env/dynamic/private"
|
|
||||||
|
|
||||||
export const { handle, signIn, signOut } = SvelteKitAuth({
|
|
||||||
providers: [
|
|
||||||
Entra({
|
|
||||||
clientId: env.AUTH_MICROSOFT_ENTRA_ID_ID,
|
|
||||||
clientSecret: env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
|
|
||||||
issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
@ -1 +0,0 @@
|
|||||||
export { handle } from "./auth"
|
|
5
frontend/src/lib/stores/auth.ts
Normal file
5
frontend/src/lib/stores/auth.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export const isAuthenticated = writable(false);
|
||||||
|
export const name = writable(false);
|
||||||
|
export const errorMessage = writable('');
|
@ -1,9 +1,42 @@
|
|||||||
import type { LayoutServerLoad } from "./$types"
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
|
|
||||||
export const load: LayoutServerLoad = async (event) => {
|
export const load: LayoutServerLoad = async ({ cookies, fetch }) => {
|
||||||
const session = await event.locals.auth()
|
let isAuthenticated = false;
|
||||||
|
let user = null;
|
||||||
|
let errorMessage = '';
|
||||||
|
|
||||||
return {
|
// Retrieve the auth token from cookies
|
||||||
session,
|
const token = cookies.get('authToken');
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
errorMessage = 'No auth token found. Please log in.';
|
||||||
|
return { isAuthenticated, user, errorMessage };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
try {
|
||||||
|
// Make a server-side fetch request to validate the token
|
||||||
|
const response = await fetch(`${PUBLIC_BASE_URL}/auth/status`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
credentials: 'include',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
isAuthenticated = data.authenticated;
|
||||||
|
user = data.user;
|
||||||
|
} else {
|
||||||
|
errorMessage = 'Authentication failed. Please log in again.';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking authentication:', error);
|
||||||
|
errorMessage = 'An error occurred while checking authentication.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return data to the layout
|
||||||
|
return { isAuthenticated, user, errorMessage };
|
||||||
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,31 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
import '../app.postcss';
|
import '../app.postcss';
|
||||||
import { signIn, signOut } from "@auth/sveltekit/client"
|
import { page } from "$app/stores";
|
||||||
import { page } from "$app/stores"
|
import { isAuthenticated } from '$lib/stores/auth';
|
||||||
|
|
||||||
let dropDown = false;
|
let dropDown = false; // For the dropdown menu (login menu)
|
||||||
|
|
||||||
|
export let data: {
|
||||||
|
isAuthenticated: boolean;
|
||||||
|
errorMessage: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the store values when this layout is loaded
|
||||||
|
$: isAuthenticated.set(data.isAuthenticated); //This is a store (MAGIC)
|
||||||
|
|
||||||
|
const handleSignOut = async () => {
|
||||||
|
const response = await fetch('/signout', {
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
data.isAuthenticated = false;
|
||||||
|
} else {
|
||||||
|
console.error('Failed to sign out.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -15,15 +37,13 @@
|
|||||||
<div class="relative dropdown-container">
|
<div class="relative dropdown-container">
|
||||||
<button class="rounded-3xl bg-blue-500 p-2 flex flex-row justify-center items-center p-1 hover:bg-blue-400"
|
<button class="rounded-3xl bg-blue-500 p-2 flex flex-row justify-center items-center p-1 hover:bg-blue-400"
|
||||||
on:click={() => dropDown = !dropDown}>
|
on:click={() => dropDown = !dropDown}>
|
||||||
{#if $page.data.session}
|
{#if data.isAuthenticated}
|
||||||
{#if $page.data.session.user?.image}
|
|
||||||
<img
|
<img
|
||||||
src={$page.data.session.user.image}
|
src="https://www.citypng.com/public/uploads/preview/hd-mcdonalds-red-round-circular-circle-logo-icon-png-image-7017516947898359qtpcakiqi.png"
|
||||||
class="avatar rounded-full size-8"
|
class="avatar rounded-full size-8"
|
||||||
alt="User Avatar"
|
alt="User Avatar"
|
||||||
/>
|
/>
|
||||||
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||||
{/if}
|
|
||||||
{:else}
|
{:else}
|
||||||
<i class="fa-solid fa-right-to-bracket" style="color: #FFFFFF;"></i>
|
<i class="fa-solid fa-right-to-bracket" style="color: #FFFFFF;"></i>
|
||||||
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||||
@ -33,23 +53,24 @@
|
|||||||
{#if dropDown}
|
{#if dropDown}
|
||||||
<!-- Dropdown menu -->
|
<!-- Dropdown menu -->
|
||||||
<div class="absolute right-0 mt-2 bg-white shadow-lg rounded-md p-4 z-50 text-nowrap">
|
<div class="absolute right-0 mt-2 bg-white shadow-lg rounded-md p-4 z-50 text-nowrap">
|
||||||
{#if $page.data.session}
|
{#if data.isAuthenticated}
|
||||||
<span class="signedInText block mb-2 text-sm">
|
<span class="signedInText block mb-2 text-sm">
|
||||||
<small>Signed in as</small><br/>
|
<small>Signed in</small><br/>
|
||||||
<strong>{$page.data.session.user?.name ?? "User"}</strong>
|
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
||||||
on:click={() => { signOut(); dropDown = false;}}>
|
on:click={() => {dropDown = false; handleSignOut();}}>
|
||||||
Sign Out
|
Sign Out
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="notSignedInText block mb-2">You are not signed in</span>
|
<span class="notSignedInText block mb-2">You are not signed in</span>
|
||||||
|
<a href="/login" on:click={() => {dropDown = false;}}>
|
||||||
<button
|
<button
|
||||||
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
||||||
on:click={() => { signIn('microsoft-entra-id'); dropDown = false;}}>
|
>
|
||||||
Sign In
|
Sign In
|
||||||
</button>
|
</button>
|
||||||
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
59
frontend/src/routes/+layout.svelte_old
Normal file
59
frontend/src/routes/+layout.svelte_old
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import '../app.postcss';
|
||||||
|
import { signIn, signOut } from "@auth/sveltekit/client"
|
||||||
|
import { page } from "$app/stores"
|
||||||
|
|
||||||
|
let dropDown = false;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="bg-blue-700 flex flex-row p-4 place-content-between items-center font-roboto shadow-xl">
|
||||||
|
<a href="/home">
|
||||||
|
<img class="max-w-36 mr-5 ml-4 aspect-auto" src="/branding/mpe_logo.png" alt="MPE Logo">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="relative dropdown-container">
|
||||||
|
<button class="rounded-3xl bg-blue-500 p-2 flex flex-row justify-center items-center p-1 hover:bg-blue-400"
|
||||||
|
on:click={() => dropDown = !dropDown}>
|
||||||
|
{#if $page.data.session}
|
||||||
|
{#if $page.data.session.user?.image}
|
||||||
|
<img
|
||||||
|
src={$page.data.session.user.image}
|
||||||
|
class="avatar rounded-full size-8"
|
||||||
|
alt="User Avatar"
|
||||||
|
/>
|
||||||
|
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<i class="fa-solid fa-right-to-bracket" style="color: #FFFFFF;"></i>
|
||||||
|
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if dropDown}
|
||||||
|
<!-- Dropdown menu -->
|
||||||
|
<div class="absolute right-0 mt-2 bg-white shadow-lg rounded-md p-4 z-50 text-nowrap">
|
||||||
|
{#if $page.data.session}
|
||||||
|
<span class="signedInText block mb-2 text-sm">
|
||||||
|
<small>Signed in as</small><br/>
|
||||||
|
<strong>{$page.data.session.user?.name ?? "User"}</strong>
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
||||||
|
on:click={() => { signOut(); dropDown = false;}}>
|
||||||
|
Sign Out
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<span class="notSignedInText block mb-2">You are not signed in</span>
|
||||||
|
<button
|
||||||
|
class="bg-blue-500 text-white px-4 py-2 rounded-3xl hover:bg-blue-400 text-nowrap w-full"
|
||||||
|
on:click={() => { signIn('microsoft-entra-id'); dropDown = false;}}>
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<slot />
|
@ -13,7 +13,7 @@
|
|||||||
let title = "";
|
let title = "";
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
const url = PUBLIC_BASE_URL+"/documents";
|
const url = PUBLIC_BASE_URL+"/document";
|
||||||
|
|
||||||
let created_by = $page.data.session.user?.name ?? "User";
|
let created_by = $page.data.session.user?.name ?? "User";
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<script lang="js">
|
<script lang="js">
|
||||||
import { page } from "$app/stores"
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
|
import { isAuthenticated } from '$lib/stores/auth';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let document = null; // To store fetched document data
|
let document = null; // To store fetched document data
|
||||||
let error = null; // To store any error that occurs during fetch
|
let error = null; // To store any error that occurs during fetch
|
||||||
@ -19,7 +21,7 @@
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Make the GET request to your API
|
// Make the GET request to your API
|
||||||
const response = await fetch(PUBLIC_BASE_URL+`/documents/${id}`);
|
const response = await fetch(PUBLIC_BASE_URL+`/document/${id}`);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
document = await response.json(); // Store document data
|
document = await response.json(); // Store document data
|
||||||
} else {
|
} else {
|
||||||
@ -69,7 +71,6 @@ async function deleteDocument(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log(result.message);
|
|
||||||
|
|
||||||
// Redirect after successful deletion
|
// Redirect after successful deletion
|
||||||
window.location.href = "/home";
|
window.location.href = "/home";
|
||||||
@ -124,7 +125,7 @@ async function deleteDocument(id) {
|
|||||||
<div class="flex flex-col justify-between">
|
<div class="flex flex-col justify-between">
|
||||||
<div class="w-full flex flex-row justify-between">
|
<div class="w-full flex flex-row justify-between">
|
||||||
<h1 class="text-2xl">{document.title}</h1>
|
<h1 class="text-2xl">{document.title}</h1>
|
||||||
{#if $page.data.session}
|
{#if $isAuthenticated}
|
||||||
<div>
|
<div>
|
||||||
<a href="/edit?id={id}"><button class="bg-yellow-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto"><i class="fa-solid fa-pencil fa-lg"></i></button></a>
|
<a href="/edit?id={id}"><button class="bg-yellow-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto"><i class="fa-solid fa-pencil fa-lg"></i></button></a>
|
||||||
<button class="bg-red-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto" on:click={() => { deleteDocument(id)}}><i class="fa-solid fa-trash fa-lg"></i></button>
|
<button class="bg-red-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto" on:click={() => { deleteDocument(id)}}><i class="fa-solid fa-trash fa-lg"></i></button>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
// Function to fetch the document by ID
|
// Function to fetch the document by ID
|
||||||
async function fetchDocumentById(id) {
|
async function fetchDocumentById(id) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(PUBLIC_BASE_URL+`/documents/${id}`);
|
const response = await fetch(PUBLIC_BASE_URL+`/document/${id}`);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const fetchedDocument = await response.json();
|
const fetchedDocument = await response.json();
|
||||||
document = fetchedDocument; // Update document data
|
document = fetchedDocument; // Update document data
|
||||||
@ -57,7 +57,7 @@
|
|||||||
async function save() {
|
async function save() {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const id = urlParams.get('id'); // Get the `id` from the query string
|
const id = urlParams.get('id'); // Get the `id` from the query string
|
||||||
const url = PUBLIC_BASE_URL+"/documents/"+id;
|
const url = PUBLIC_BASE_URL+"/document/"+id;
|
||||||
|
|
||||||
console.log("Title value:", title);
|
console.log("Title value:", title);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { page } from "$app/stores"
|
import { page } from "$app/stores"
|
||||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
|
import { isAuthenticated } from '$lib/stores/auth';
|
||||||
|
|
||||||
let query = false;
|
let query = false;
|
||||||
let searchQuery = "";
|
let searchQuery = "";
|
||||||
@ -41,7 +42,7 @@
|
|||||||
// Function to fetch all documents from the API
|
// Function to fetch all documents from the API
|
||||||
async function getAllDocuments() {
|
async function getAllDocuments() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(PUBLIC_BASE_URL+`/documents`);
|
const res = await fetch(PUBLIC_BASE_URL+`/document`);
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`Failed to fetch documents: ${res.statusText}`);
|
throw new Error(`Failed to fetch documents: ${res.statusText}`);
|
||||||
@ -71,14 +72,16 @@
|
|||||||
documents = await getAllDocuments();
|
documents = await getAllDocuments();
|
||||||
console.log("Fetched documents:", documents);
|
console.log("Fetched documents:", documents);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let message = "Hello";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>Home</title>
|
<title>DocuCenter</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="flex items-center justify-center h-full flex-col">
|
<div class="flex items-center justify-center h-full flex-col">
|
||||||
{#if $page.data.session}
|
{#if $isAuthenticated}
|
||||||
<div class="flex flex-row justify-end w-full">
|
<div class="flex flex-row justify-end w-full">
|
||||||
<a href="/add" class="bg-green-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 mr-4 mt-3 text-white font-roboto">
|
<a href="/add" class="bg-green-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 mr-4 mt-3 text-white font-roboto">
|
||||||
<i class="fa-solid fa-folder-plus fa-lg"></i>
|
<i class="fa-solid fa-folder-plus fa-lg"></i>
|
||||||
@ -140,6 +143,5 @@
|
|||||||
<p class="text-center text-gray-500">No results found.</p>
|
<p class="text-center text-gray-500">No results found.</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,14 +1,49 @@
|
|||||||
<script>
|
<script>
|
||||||
import { signIn, signOut } from "@auth/sveltekit/client"
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
import { page } from "$app/stores"
|
|
||||||
|
async function handleSignIn(event) {
|
||||||
|
event.preventDefault(); // Prevent the default form submission
|
||||||
|
|
||||||
|
const form = event.target;
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
// Convert FormData to a JSON object
|
||||||
|
const data = Object.fromEntries(formData.entries());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${PUBLIC_BASE_URL}/auth/login`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: 'include', // Important to send and receive cookies
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const { token } = await response.json();
|
||||||
|
sessionStorage.setItem('authToken', token); // Store the token
|
||||||
|
|
||||||
|
// Redirect to the login page after success
|
||||||
|
window.location.href = '/home';
|
||||||
|
} else {
|
||||||
|
const error = await response.json();
|
||||||
|
alert(error.message);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
alert('An error occurred while signing up.');
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Sign in to your account</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Sign in to your account</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 sm:mx-auto sm:w-full sm:max-w-sm">
|
<div class="mt-4 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
<form class="space-y-6" action="#" method="POST">
|
<form class="space-y-6" on:submit={handleSignIn}>
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address</label>
|
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address</label>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
@ -35,7 +70,7 @@
|
|||||||
|
|
||||||
<p class="mt-10 text-center text-sm/6 text-gray-500">
|
<p class="mt-10 text-center text-sm/6 text-gray-500">
|
||||||
Not a member?
|
Not a member?
|
||||||
<a href="#" class="font-semibold text-blue-500 hover:text-blue-400">Sign Up Now</a>
|
<a href="/signup" class="font-semibold text-blue-500 hover:text-blue-400">Sign Up Now</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,3 +0,0 @@
|
|||||||
import { signOut } from "../../auth"
|
|
||||||
import type { Actions } from "./$types"
|
|
||||||
export const actions: Actions = { default: signOut }
|
|
12
frontend/src/routes/signout/+server.ts
Normal file
12
frontend/src/routes/signout/+server.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export const POST: RequestHandler = async ({ cookies }) => {
|
||||||
|
try {
|
||||||
|
// Clear the authToken cookie
|
||||||
|
cookies.delete('authToken', { path: '/' });
|
||||||
|
return new Response(JSON.stringify({ success: true }), { status: 200 });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during sign out:', error);
|
||||||
|
return new Response(JSON.stringify({ success: false, message: 'Failed to sign out.' }), { status: 500 });
|
||||||
|
}
|
||||||
|
};
|
71
frontend/src/routes/signup/+page.svelte
Normal file
71
frontend/src/routes/signup/+page.svelte
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<script>
|
||||||
|
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||||
|
|
||||||
|
async function handleSignup(event) {
|
||||||
|
event.preventDefault(); // Prevent the default form submission
|
||||||
|
|
||||||
|
const form = event.target;
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
// Convert FormData to a JSON object
|
||||||
|
const data = Object.fromEntries(formData.entries());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${PUBLIC_BASE_URL}/user`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// Redirect to the login page after success
|
||||||
|
window.location.href = '/login';
|
||||||
|
} else {
|
||||||
|
const error = await response.json();
|
||||||
|
alert(error.message);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
alert('An error occurred while signing up.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
|
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Sign up</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<form class="space-y-6" on:submit={handleSignup}>
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm/6 font-medium text-gray-900">Name</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="text" name="name" id="name" class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-blue-500 sm:text-sm/6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address *</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="email" name="email" id="email" autocomplete="email" required class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-blue-500 sm:text-sm/6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<label for="password" class="block text-sm/6 font-medium text-gray-900">Password *</label>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="password" name="password" id="password" autocomplete="current-password" required class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-blue-500 sm:text-sm/6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="submit" class="flex w-full justify-center rounded-md bg-blue-500 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500">Create account</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Block a user