mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2025-06-27 11:20:40 -04:00
feat: added file upload + dir creation
This commit is contained in:
parent
b1c295d2ac
commit
eedab606f8
25 changed files with 965 additions and 103 deletions
262
file-uploader/package-lock.json
generated
262
file-uploader/package-lock.json
generated
|
@ -10,12 +10,15 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.5.0",
|
||||
"@quixo3/prisma-session-store": "^3.1.13",
|
||||
"bcrypt": "^5.1.1",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.1",
|
||||
"express-validator": "^7.2.1",
|
||||
"passport": "^0.7.0"
|
||||
"multer": "^1.4.5-lts.2",
|
||||
"passport": "^0.7.0",
|
||||
"passport-local": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^7.1.2",
|
||||
|
@ -521,6 +524,27 @@
|
|||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz",
|
||||
"integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^14.21.3 || >=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@paralleldrive/cuid2": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz",
|
||||
"integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/client": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.5.0.tgz",
|
||||
|
@ -597,6 +621,24 @@
|
|||
"@prisma/debug": "6.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@quixo3/prisma-session-store": {
|
||||
"version": "3.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@quixo3/prisma-session-store/-/prisma-session-store-3.1.13.tgz",
|
||||
"integrity": "sha512-EAuOvYAaAsQ0OqxkdJG/Qs3cxlT4VV8SFHjtsA3G01uB1b6r7xftX3oeg7mcG0HN/DI1qOqwvy3YFoJ38ls0iA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@paralleldrive/cuid2": "^2.2.0",
|
||||
"ts-dedent": "^2.2.0",
|
||||
"type-fest": "^2.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@prisma/client": ">=2.16.1",
|
||||
"express-session": ">=1.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
|
||||
|
@ -1009,6 +1051,12 @@
|
|||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
|
@ -1146,9 +1194,19 @@
|
|||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
@ -1322,6 +1380,51 @@
|
|||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"engines": [
|
||||
"node >= 0.8"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-stream/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
|
@ -1360,6 +1463,12 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
||||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
|
@ -2539,6 +2648,12 @@
|
|||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
|
@ -2754,6 +2869,15 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
|
@ -2805,6 +2929,79 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/multer": {
|
||||
"version": "1.4.5-lts.2",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
|
||||
"integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^1.0.0",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multer/node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/multer/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/multer/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/multer/node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/multer/node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
|
@ -3057,6 +3254,17 @@
|
|||
"url": "https://github.com/sponsors/jaredhanson"
|
||||
}
|
||||
},
|
||||
"node_modules/passport-local": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
||||
"integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==",
|
||||
"dependencies": {
|
||||
"passport-strategy": "1.x.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/passport-strategy": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
||||
|
@ -3286,6 +3494,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
@ -3791,6 +4005,14 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
|
@ -3975,6 +4197,15 @@
|
|||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-dedent": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
|
||||
"integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.10"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
|
@ -3982,6 +4213,18 @@
|
|||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||
|
@ -3995,6 +4238,12 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
|
@ -4304,6 +4553,15 @@
|
|||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
|
|
@ -11,12 +11,15 @@
|
|||
"description": "",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.5.0",
|
||||
"@quixo3/prisma-session-store": "^3.1.13",
|
||||
"bcrypt": "^5.1.1",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.1",
|
||||
"express-validator": "^7.2.1",
|
||||
"passport": "^0.7.0"
|
||||
"multer": "^1.4.5-lts.2",
|
||||
"passport": "^0.7.0",
|
||||
"passport-local": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^7.1.2",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sid" TEXT NOT NULL,
|
||||
"data" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_sid_key" ON "Session"("sid");
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `mimetype` to the `File` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `size` to the `File` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "File" ADD COLUMN "mimetype" TEXT NOT NULL,
|
||||
ADD COLUMN "size" INTEGER NOT NULL;
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `full_path` to the `Folder` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `modification_date` to the `Folder` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `parent_folder_id` to the `Folder` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Folder" ADD COLUMN "creation_date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "full_path" TEXT NOT NULL,
|
||||
ADD COLUMN "modification_date" TIMESTAMP(3) NOT NULL,
|
||||
ADD COLUMN "owner_user_id" INTEGER,
|
||||
ADD COLUMN "parent_folder_id" INTEGER NOT NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Folder" ADD CONSTRAINT "Folder_owner_user_id_fkey" FOREIGN KEY ("owner_user_id") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `full_path` on the `Folder` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `parent_folder_id` on the `Folder` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Folder" DROP COLUMN "full_path",
|
||||
DROP COLUMN "parent_folder_id",
|
||||
ADD COLUMN "parentId" INTEGER;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Folder" ADD CONSTRAINT "Folder_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Folder"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Folder" ALTER COLUMN "modification_date" SET DEFAULT CURRENT_TIMESTAMP;
|
|
@ -15,17 +15,20 @@ datasource db {
|
|||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique @db.VarChar(50)
|
||||
email String @unique
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique @db.VarChar(50)
|
||||
email String @unique
|
||||
password String
|
||||
files File[]
|
||||
Folder Folder[]
|
||||
}
|
||||
|
||||
model File {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(255)
|
||||
url String
|
||||
size Int
|
||||
mimetype String
|
||||
createdAt DateTime @default(now())
|
||||
owner User? @relation(fields: [ownerId], references: [id])
|
||||
ownerId Int?
|
||||
|
@ -34,7 +37,21 @@ model File {
|
|||
}
|
||||
|
||||
model Folder {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(255)
|
||||
File File[]
|
||||
id Int @id @default(autoincrement())
|
||||
name String @db.VarChar(255)
|
||||
creation_date DateTime @default(now())
|
||||
modification_date DateTime @default(now())
|
||||
File File[]
|
||||
owner User? @relation(fields: [owner_user_id], references: [id])
|
||||
owner_user_id Int?
|
||||
parentId Int?
|
||||
parent Folder? @relation("ParentDirectory", fields: [parentId], references: [id])
|
||||
Directories Folder[] @relation("ParentDirectory")
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id
|
||||
sid String @unique
|
||||
data String
|
||||
expiresAt DateTime
|
||||
}
|
||||
|
|
142
file-uploader/public/css/style.css
Normal file
142
file-uploader/public/css/style.css
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* 1. Use a more-intuitive box-sizing model */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 2. Remove default margin */
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 3. Enable keyword animations */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
html {
|
||||
interpolate-size: allow-keywords;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
/* 4. Add accessible line-height */
|
||||
line-height: 1.5;
|
||||
/* 5. Improve text rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* 6. Improve media defaults */
|
||||
img,
|
||||
picture,
|
||||
video,
|
||||
canvas,
|
||||
svg {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 7. Inherit fonts for form controls */
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* 8. Avoid text overflows */
|
||||
p,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* 9. Improve line wrapping */
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
/*
|
||||
10. Create a root stacking context
|
||||
*/
|
||||
#root,
|
||||
#__next {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
outline: none;
|
||||
padding: 4px;
|
||||
margin: -4px;
|
||||
}
|
||||
|
||||
input[type='file']::file-selector-button {
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
padding: 0 1em;
|
||||
height: 2em;
|
||||
background-color: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.16);
|
||||
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.05);
|
||||
margin-right: 16px;
|
||||
transition: background-color 200ms;
|
||||
}
|
||||
|
||||
/* file upload button hover state */
|
||||
input[type='file']::file-selector-button:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
/* file upload button active state */
|
||||
input[type='file']::file-selector-button:active {
|
||||
background-color: #e5e7eb;
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
position: relative;
|
||||
outline: none;
|
||||
padding: 4px;
|
||||
margin: -4px;
|
||||
}
|
||||
|
||||
input[type='file']:focus-within::file-selector-button,
|
||||
input[type='file']:focus::file-selector-button {
|
||||
outline: 2px solid #0964b0;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@supports (-moz-appearance: none) {
|
||||
input[type='file']::file-selector-button {
|
||||
color: #0964b0;
|
||||
}
|
||||
}
|
||||
|
||||
/* .file { */
|
||||
/* opacity: 0; */
|
||||
/* width: 0.1px; */
|
||||
/* height: 0.1px; */
|
||||
/* position: absolute; */
|
||||
/* } */
|
|
@ -1,14 +1,57 @@
|
|||
console.log('form stuff');
|
||||
|
||||
const usernameCheck = async (username) => {
|
||||
let res = await fetch(`/auth/username?username=${username}`);
|
||||
return await res.json();
|
||||
if (username.length > 0) {
|
||||
let res = await fetch(`/auth/username?username=${username}`);
|
||||
const data = await res.json();
|
||||
// return true if username is available
|
||||
return data.results === false;
|
||||
}
|
||||
};
|
||||
|
||||
const input = document.querySelector("input[name='username']");
|
||||
const emailCheck = async (email) => {
|
||||
if (email.length > 0) {
|
||||
let res = await fetch(`/auth/email?email=${email}`);
|
||||
const data = await res.json();
|
||||
return data.results === false;
|
||||
}
|
||||
};
|
||||
|
||||
input.addEventListener('input', async (e) => {
|
||||
let input = e.target.value;
|
||||
let test = await usernameCheck(input);
|
||||
test.results ? console.log('user exists') : console.log('user doesnt');
|
||||
});
|
||||
const isDataValid = async (e, callback) => {
|
||||
let test = await callback(e.target.value);
|
||||
test
|
||||
? (e.target.style.border = '3px green solid')
|
||||
: (e.target.style.border = 'red solid 3px');
|
||||
};
|
||||
|
||||
const passwordValid = () => {
|
||||
const password = document.querySelector('#password');
|
||||
const passwordConfirmation = document.querySelector(
|
||||
'#password-confirmation',
|
||||
);
|
||||
|
||||
const passwordConfirmationCheck = (value) => {
|
||||
return password.value === value;
|
||||
};
|
||||
|
||||
const passwordValidityCheck = (password) => {
|
||||
if (!/\d/.test(password)) return false;
|
||||
if (!/[\!@#%\^&\*\(\)\_\+\-=\[\]{}\|;':",\.\/\<\>\~\`]/.test(password))
|
||||
return false;
|
||||
if (password.length < 8) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
password.addEventListener('input', (e) =>
|
||||
isDataValid(e, passwordValidityCheck),
|
||||
);
|
||||
passwordConfirmation.addEventListener('input', (e) =>
|
||||
isDataValid(e, passwordConfirmationCheck),
|
||||
);
|
||||
};
|
||||
|
||||
const usernameInput = document.querySelector("input[name='username']");
|
||||
usernameInput.addEventListener('input', (e) => isDataValid(e, usernameCheck));
|
||||
|
||||
const emailInput = document.querySelector("input[name='email']");
|
||||
emailInput.addEventListener('input', (e) => isDataValid(e, emailCheck));
|
||||
|
||||
passwordValid();
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
const { Auth } = require('../models/auth');
|
||||
const Db = require('../models/db');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const db = new Auth();
|
||||
const db = new Db();
|
||||
|
||||
const loginGet = (req, res, next) => {
|
||||
res.send('Login Route');
|
||||
};
|
||||
|
||||
const logout = (req, res, next) => {
|
||||
req.logout((err) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.redirect('/');
|
||||
});
|
||||
};
|
||||
|
||||
const registerGet = (req, res) => {
|
||||
res.render('register');
|
||||
res.render('register', { pageTitle: 'Register' });
|
||||
};
|
||||
const registerPost = async (req, res, next) => {
|
||||
const { username, email, password } = req.body;
|
||||
|
||||
try {
|
||||
const hashedPassword = bcrypt.hash(password);
|
||||
const result = await db.createUser({
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
const result = await db.auth.createUser({
|
||||
username: username,
|
||||
password: hashedPassword,
|
||||
email: email,
|
||||
|
@ -38,7 +47,7 @@ const findByUsername = async (req, res, next) => {
|
|||
|
||||
try {
|
||||
if (username && username.length > 0) {
|
||||
const exists = (await db.getUserByUsername(username))
|
||||
const exists = (await db.auth.getUserByUsername(username))
|
||||
? true
|
||||
: false;
|
||||
|
||||
|
@ -50,4 +59,24 @@ const findByUsername = async (req, res, next) => {
|
|||
}
|
||||
};
|
||||
|
||||
module.exports = { findByUsername, loginGet, registerPost, registerGet };
|
||||
const findByEmail = async (req, res, next) => {
|
||||
const { email } = req.query;
|
||||
try {
|
||||
if (email && email.length > 0) {
|
||||
const exists = (await db.auth.getByEmail(email)) ? true : false;
|
||||
const data = { results: exists };
|
||||
res.json(data);
|
||||
}
|
||||
} catch (e) {
|
||||
res.json({ error: e });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
findByUsername,
|
||||
findByEmail,
|
||||
loginGet,
|
||||
logout,
|
||||
registerPost,
|
||||
registerGet,
|
||||
};
|
||||
|
|
65
file-uploader/src/controllers/fileController.js
Normal file
65
file-uploader/src/controllers/fileController.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
const multer = require('multer');
|
||||
const Db = require('../models/db');
|
||||
const upload = multer({ dest: '/tmp/testing/' });
|
||||
|
||||
const db = new Db();
|
||||
//
|
||||
// const createUserRootDir = async () => {
|
||||
// const user = await db.auth.getUserByUsername(username);
|
||||
// console.log(`USERID: ${user.id}`);
|
||||
// const dir = await db.file.createDirectory(user, 'root');
|
||||
// if (dir.error) {
|
||||
// console.log(dir.error);
|
||||
// } else {
|
||||
// console.log(dir.message);
|
||||
// }
|
||||
// };
|
||||
|
||||
const createDirectory = async (req, res) => {
|
||||
const { parentId, 'directory-name': directoryName } = req.body;
|
||||
|
||||
const result = await db.file.createDirectory(
|
||||
req.user,
|
||||
directoryName,
|
||||
Number(parentId),
|
||||
);
|
||||
|
||||
res.redirect('/');
|
||||
};
|
||||
|
||||
const fileUpload = async (req, res) => {
|
||||
console.log(req.file);
|
||||
const { folderId } = req.body;
|
||||
const file = {
|
||||
name: req.file.originalname,
|
||||
path: req.file.path,
|
||||
filename: req.file.filename,
|
||||
folderId: Number(folderId),
|
||||
mimetype: req.file.mimetype,
|
||||
size: req.file.size,
|
||||
};
|
||||
console.log(file, req.user);
|
||||
try {
|
||||
const result = await db.file.createFile(req.user.id, file);
|
||||
console.log(result);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
res.redirect('/');
|
||||
};
|
||||
|
||||
const userDirs = (req, res) => {
|
||||
if (req.user) {
|
||||
// logic to grab the current dir based on path maybe
|
||||
// logic to grab all user dirs?
|
||||
}
|
||||
};
|
||||
|
||||
const getFiles = (req, res) => {
|
||||
if (req.user) {
|
||||
// logic to grab the files
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { createDirectory, upload, fileUpload };
|
|
@ -1,9 +1,17 @@
|
|||
// const db = require("../models/auth");
|
||||
const Db = require('../models/db');
|
||||
|
||||
const db = new Db();
|
||||
const indexGet = async (req, res) => {
|
||||
// const data = await db.allUsers()
|
||||
// console.dir(data)
|
||||
res.render("main");
|
||||
// const data = await db.allUsers()
|
||||
// console.dir(data)
|
||||
if (req.user) {
|
||||
const id = await db.file.getUserRootDirectoryId(req.user.id);
|
||||
if (id === null) console.log('id is null');
|
||||
console.log(id);
|
||||
res.render('main', { pageTitle: 'FileUpload', folder: { id: id } });
|
||||
} else {
|
||||
res.render('main', { pageTitle: 'FileUpload', folder: {} });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { indexGet };
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
const passport = require('passport');
|
||||
const expressSession = require('express-session');
|
||||
const { PrismaSessionStore } = require('@quixo3/prisma-session-store');
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const { passport } = require('./middlewares/auth');
|
||||
const path = require('node:path');
|
||||
|
||||
const port = process.env.APP_PORT || 3000;
|
||||
|
@ -9,17 +11,40 @@ const app = express();
|
|||
const assetsPath = path.join(path.dirname(__dirname), 'public');
|
||||
app.use(express.static(assetsPath));
|
||||
|
||||
app.use(
|
||||
expressSession({
|
||||
cookie: {
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000,
|
||||
},
|
||||
secret: 'deez',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
store: new PrismaSessionStore(new PrismaClient(), {
|
||||
checkPeriod: 2 * 60 * 1000,
|
||||
dbRecordIdFunction: undefined,
|
||||
dbRecordIdIsSessionId: true,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
app.use(passport.session());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
|
||||
const authRouter = require('./routes/authRouter');
|
||||
const indexRouter = require('./routes/indexRouter');
|
||||
const fileRouter = require('./routes/fileRouter');
|
||||
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'ejs');
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
res.locals.currentUser = req.user;
|
||||
next();
|
||||
});
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use('/auth', authRouter);
|
||||
app.use('/file', fileRouter);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`App listening on ${port}`);
|
||||
});
|
||||
|
||||
|
|
51
file-uploader/src/middlewares/auth.js
Normal file
51
file-uploader/src/middlewares/auth.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
const bcrypt = require('bcrypt');
|
||||
const passport = require('passport');
|
||||
const Db = require('../models/db');
|
||||
const LocalStrategy = require('passport-local').Strategy;
|
||||
|
||||
const db = new Db();
|
||||
|
||||
passport.use(
|
||||
new LocalStrategy(async (username, password, done) => {
|
||||
try {
|
||||
const user = await db.auth.getUserByUsername(username);
|
||||
|
||||
if (!user) {
|
||||
return done(null, false, {
|
||||
message: 'Incorrect username or passowrd',
|
||||
});
|
||||
}
|
||||
|
||||
const passwordMatch = await bcrypt.compare(password, user.password);
|
||||
if (!passwordMatch) {
|
||||
return done(null, false, {
|
||||
message: 'inccorect username or password',
|
||||
});
|
||||
}
|
||||
|
||||
// ensure users root directory has been created
|
||||
const rootDirId = await db.file.getUserRootDirectoryId(user.id);
|
||||
console.log(rootDirId);
|
||||
if (rootDirId === null)
|
||||
await db.file.createDirectory(user, 'root', null);
|
||||
return done(null, user);
|
||||
} catch (err) {
|
||||
return done(err);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user.id);
|
||||
});
|
||||
|
||||
passport.deserializeUser(async (id, done) => {
|
||||
try {
|
||||
const user = await db.auth.getUserById(id);
|
||||
done(null, user);
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = { passport };
|
|
@ -1,45 +1,72 @@
|
|||
const { PrismaClient, Prisma } = require("@prisma/client");
|
||||
const { PrismaClient, Prisma } = require('@prisma/client');
|
||||
// const { Prisma } = require("prisma");
|
||||
|
||||
class Auth {
|
||||
constructor() {
|
||||
this.primsa = new PrismaClient();
|
||||
}
|
||||
async createUser(user) {
|
||||
try {
|
||||
await this.primsa.user.create({
|
||||
data: {
|
||||
username: user.username,
|
||||
email: user?.email,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
return { message: "user created" };
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (e.code === "P2002") {
|
||||
console.log("User must use a unique username");
|
||||
return { error: "must use unique username" };
|
||||
constructor() {
|
||||
this.prisma = new PrismaClient();
|
||||
}
|
||||
async createUser(user) {
|
||||
try {
|
||||
await this.prisma.user.create({
|
||||
data: {
|
||||
username: user.username,
|
||||
email: user?.email,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
return { message: 'user created' };
|
||||
} catch (e) {
|
||||
console.log(`PRISMA error ${e}`);
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (e.code === 'P2002') {
|
||||
console.log('There is a unique constraint violation');
|
||||
return {
|
||||
error: 'must use unique username and a unique email.',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async allUsers() {
|
||||
return await this.primsa.user.findMany();
|
||||
}
|
||||
|
||||
async getUserByUsername(username) {
|
||||
try {
|
||||
return await this.primsa.user.findUnique({
|
||||
where: {
|
||||
username: username,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
async allUsers() {
|
||||
return await this.prisma.user.findMany();
|
||||
}
|
||||
|
||||
async getUserByUsername(username) {
|
||||
try {
|
||||
return await this.prisma.user.findUnique({
|
||||
where: {
|
||||
username: username,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
}
|
||||
}
|
||||
|
||||
async getUserById(id) {
|
||||
try {
|
||||
return await this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
}
|
||||
}
|
||||
|
||||
async getByEmail(email) {
|
||||
try {
|
||||
return await this.prisma.user.findUnique({
|
||||
where: {
|
||||
email: email,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// async function main() {
|
||||
|
@ -58,4 +85,3 @@ class Auth {
|
|||
// })
|
||||
|
||||
module.exports = { Auth };
|
||||
|
||||
|
|
11
file-uploader/src/models/db.js
Normal file
11
file-uploader/src/models/db.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const { Auth } = require('./auth');
|
||||
const { File } = require('./file');
|
||||
|
||||
class Db {
|
||||
constructor() {
|
||||
this.auth = new Auth();
|
||||
this.file = new File();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Db;
|
77
file-uploader/src/models/file.js
Normal file
77
file-uploader/src/models/file.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
const { PrismaClient } = require('@prisma/client');
|
||||
|
||||
class File {
|
||||
constructor() {
|
||||
this.prisma = new PrismaClient();
|
||||
}
|
||||
|
||||
async createDirectory(user, dirName, parentId) {
|
||||
try {
|
||||
await this.prisma.folder.create({
|
||||
data: {
|
||||
name: dirName,
|
||||
owner_user_id: user.id,
|
||||
parentId: parentId,
|
||||
},
|
||||
});
|
||||
return { message: 'dir created' };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { error: 'issue creating dir' };
|
||||
}
|
||||
}
|
||||
|
||||
async getDirectoryIdByName(dirId, userId) {
|
||||
try {
|
||||
await this.prisma.folder.findUnique({
|
||||
where: {
|
||||
id: dirId,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async getUserRootDirectoryId(userId) {
|
||||
try {
|
||||
const dir = await this.prisma.folder.findFirst({
|
||||
where: {
|
||||
owner_user_id: userId,
|
||||
name: 'root',
|
||||
parentId: null,
|
||||
},
|
||||
});
|
||||
|
||||
if (dir !== null) {
|
||||
return dir.id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getDirectoriesByUser() {}
|
||||
|
||||
async createFile(userId, file) {
|
||||
try {
|
||||
await this.prisma.file.create({
|
||||
data: {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
mimetype: file.mimetype,
|
||||
url: file.path,
|
||||
folderId: file.folderId,
|
||||
ownerId: userId,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { File };
|
|
@ -1,12 +1,21 @@
|
|||
const { Router } = require('express');
|
||||
const authController = require('../controllers/authController');
|
||||
const { passport } = require('../middlewares/auth');
|
||||
|
||||
const authRouter = Router();
|
||||
|
||||
authRouter.get('/login', authController.loginGet);
|
||||
authRouter.post(
|
||||
'/login',
|
||||
passport.authenticate('local', {
|
||||
successRedirect: '/',
|
||||
failureRedirect: '/',
|
||||
}),
|
||||
);
|
||||
authRouter.get('/logout', authController.logout);
|
||||
authRouter.get('/register', authController.registerGet);
|
||||
authRouter.post('/register', authController.registerPost);
|
||||
authRouter.get('/username', authController.findByUsername);
|
||||
authRouter.get('/email', authController.findByEmail);
|
||||
|
||||
module.exports = authRouter;
|
||||
|
||||
|
|
13
file-uploader/src/routes/fileRouter.js
Normal file
13
file-uploader/src/routes/fileRouter.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const { Router } = require('express');
|
||||
const fileController = require('../controllers/fileController');
|
||||
|
||||
const fileRouter = Router();
|
||||
|
||||
fileRouter.post(
|
||||
'/',
|
||||
fileController.upload.single('fileUpload'),
|
||||
fileController.fileUpload,
|
||||
);
|
||||
fileRouter.post('/directory', fileController.createDirectory);
|
||||
|
||||
module.exports = fileRouter;
|
|
@ -1,13 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
|
||||
<%- include('partials/header') %>
|
||||
<body>
|
||||
<% if(currentUser) { %>
|
||||
<p> Hello <%= currentUser.username %> </p>
|
||||
<a href="/auth/logout">sign out</a>
|
||||
<%- include('partials/fileUpload') %>
|
||||
<% } else { %>
|
||||
<form action="/auth/login" method="post">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" name="username">
|
||||
|
@ -16,6 +13,6 @@
|
|||
<button type="submit">Submit</button>
|
||||
<a href="/auth/register">Click here to register</a>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<% } %>
|
||||
<%- include('partials/footer') %>
|
||||
|
|
17
file-uploader/src/views/partials/fileUpload.ejs
Normal file
17
file-uploader/src/views/partials/fileUpload.ejs
Normal file
|
@ -0,0 +1,17 @@
|
|||
<form action="/file" method="post" enctype="multipart/form-data">
|
||||
<div class="container file-upload">
|
||||
<input type="file" name="fileUpload" id="fileUpload" class="file">
|
||||
<input type="hidden" name="folderId" value=<%= folder.id %>>
|
||||
<button type="submit">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<form action="/file/directory" method="post">
|
||||
<div class="container">
|
||||
<label for="directory-name">Directory Name:</label>
|
||||
<input type="text" name="directory-name" placeholder="">
|
||||
<input type="hidden" name="parentId" value=<%= folder.id %>>
|
||||
<button>Create Directory</button>
|
||||
</div>
|
||||
</form>
|
3
file-uploader/src/views/partials/footer.ejs
Normal file
3
file-uploader/src/views/partials/footer.ejs
Normal file
|
@ -0,0 +1,3 @@
|
|||
</body>
|
||||
|
||||
</html>
|
11
file-uploader/src/views/partials/header.ejs
Normal file
11
file-uploader/src/views/partials/header.ejs
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<title><%= pageTitle %></title>
|
||||
</head>
|
||||
|
||||
<body>
|
|
@ -1,25 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<%- include('partials/header') %>
|
||||
<form action="/auth/register" method="post" class="register-form">
|
||||
<div class="form-input">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" name="username">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form action="/auth/register" method="post">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" name="username">
|
||||
</div>
|
||||
<div class="form-input">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password">
|
||||
<label for="password-confirmation">Password Confirmation</label>
|
||||
<input type="password-confirmation" name="password-confirmation" id="password-confirmation">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email">
|
||||
<input type="password" name="password" id="password" required>
|
||||
</div>
|
||||
<div class="form-input">
|
||||
<label for="password-confirmation">Password Confirmation</label>
|
||||
<input type="password" name="password-confirmation" id="password-confirmation" required>
|
||||
</div>
|
||||
<div class="form-input">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email" required>
|
||||
</div>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<script src="/js/form.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<script src="/js/form.js"></script>
|
||||
|
||||
<%- include('partials/footer') %>
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue