diff --git a/package-lock.json b/package-lock.json
index 6e70bb2..ae4e2bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,13 +9,14 @@
"version": "0.1.0",
"dependencies": {
"@next/font": "13.1.6",
- "@prisma/client": "^4.9.0",
+ "@prisma/client": "^4.10.0",
"@types/node": "18.11.19",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"eslint": "8.33.0",
"eslint-config-next": "13.1.6",
"next": "13.1.6",
+ "next-auth": "^4.19.2",
"next-superjson-plugin": "^0.5.4",
"react": "18.2.0",
"react-dom": "18.2.0",
@@ -26,13 +27,14 @@
"remark-gfm": "^3.0.1",
"remark-stringify": "^10.0.2",
"sass": "^1.58.0",
+ "swr": "^2.0.3",
"typescript": "4.9.5",
"url-join": "^5.0.0"
},
"devDependencies": {
"@types/react-select": "^5.0.1",
"@types/react-syntax-highlighter": "^15.5.6",
- "prisma": "^4.9.0"
+ "prisma": "^4.10.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -964,6 +966,14 @@
"node": ">= 8"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.2.tgz",
+ "integrity": "sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@pkgr/utils": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz",
@@ -984,12 +994,12 @@
}
},
"node_modules/@prisma/client": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz",
- "integrity": "sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.10.0.tgz",
+ "integrity": "sha512-sBmYb1S6SMKFIESaLMfKqWSalv3pH73cMCsFt9HslJvYjIIcKQCA6PDL2O4SZGWvc4JBef9cg5Gd7d9x3AtKjw==",
"hasInstallScript": true,
"dependencies": {
- "@prisma/engines-version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5"
+ "@prisma/engines-version": "4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d"
},
"engines": {
"node": ">=14.17"
@@ -1004,16 +1014,16 @@
}
},
"node_modules/@prisma/engines": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.9.0.tgz",
- "integrity": "sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.10.0.tgz",
+ "integrity": "sha512-ZPPo7q+nQZdTlPFedS7mFXPE3oZ2kWtTh3GO4sku0XQ8ikLqEyinuTPJbQCw/8qel2xglIEQicsK6yI4Jgh20A==",
"devOptional": true,
"hasInstallScript": true
},
"node_modules/@prisma/engines-version": {
- "version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5",
- "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz",
- "integrity": "sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA=="
+ "version": "4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d.tgz",
+ "integrity": "sha512-UVpmVlvSaGfY4ue+hh8CTkIesbuXCFUfrr8zk//+u85WwkKfWMtt6nLB2tNSzR1YO8eAA8+HqNf8LM7mnXIq5w=="
},
"node_modules/@rushstack/eslint-patch": {
"version": "1.2.0",
@@ -1660,6 +1670,14 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/copy-anything": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.3.tgz",
@@ -3414,6 +3432,14 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
+ "node_modules/jose": {
+ "version": "4.11.4",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz",
+ "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
@@ -4474,6 +4500,33 @@
}
}
},
+ "node_modules/next-auth": {
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.19.2.tgz",
+ "integrity": "sha512-6V2YG3IJQVhgCAH7mvT3yopTW92gMdUrcwGX7NQ0dCreT/+axGua/JmVdarjec0C/oJukKpIYRgjMlV+L5ZQOQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.16.3",
+ "@panva/hkdf": "^1.0.1",
+ "cookie": "^0.5.0",
+ "jose": "^4.9.3",
+ "oauth": "^0.9.15",
+ "openid-client": "^5.1.0",
+ "preact": "^10.6.3",
+ "preact-render-to-string": "^5.1.19",
+ "uuid": "^8.3.2"
+ },
+ "peerDependencies": {
+ "next": "^12.2.5 || ^13",
+ "nodemailer": "^6.6.5",
+ "react": "^17.0.2 || ^18",
+ "react-dom": "^17.0.2 || ^18"
+ },
+ "peerDependenciesMeta": {
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next-superjson-plugin": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/next-superjson-plugin/-/next-superjson-plugin-0.5.4.tgz",
@@ -4500,6 +4553,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/oauth": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4508,6 +4566,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-hash": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
@@ -4613,6 +4679,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/oidc-token-hash": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz",
+ "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==",
+ "engines": {
+ "node": "^10.13.0 || >=12.0.0"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -4637,6 +4711,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/openid-client": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.0.tgz",
+ "integrity": "sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ==",
+ "dependencies": {
+ "jose": "^4.10.0",
+ "lru-cache": "^6.0.0",
+ "object-hash": "^2.0.1",
+ "oidc-token-hash": "^5.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -4811,6 +4899,26 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/preact": {
+ "version": "10.12.0",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.0.tgz",
+ "integrity": "sha512-+w8ix+huD8CNZemheC53IPjMUFk921i02o30u0K6h53spMX41y/QhVDnG/nU2k42/69tvqWmVsgNLIiwRAcmxg==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "5.2.6",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
+ "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
+ "dependencies": {
+ "pretty-format": "^3.8.0"
+ },
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -4819,14 +4927,19 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ },
"node_modules/prisma": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz",
- "integrity": "sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.10.0.tgz",
+ "integrity": "sha512-xUHcF3Glc8QGgW8x0rfPITvyyTo04fskUdG7pI4kQbvDX/rhzDP4046x/FvazYqYHXMLR5/KTIi2p2Gth5vKOQ==",
"devOptional": true,
"hasInstallScript": true,
"dependencies": {
- "@prisma/engines": "4.9.0"
+ "@prisma/engines": "4.10.0"
},
"bin": {
"prisma": "build/index.js",
@@ -5491,6 +5604,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/swr": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.0.3.tgz",
+ "integrity": "sha512-sGvQDok/AHEWTPfhUWXEHBVEXmgGnuahyhmRQbjl9XBYxT/MSlAzvXEKQpyM++bMPaI52vcWS2HiKNaW7+9OFw==",
+ "dependencies": {
+ "use-sync-external-store": "^1.2.0"
+ },
+ "engines": {
+ "pnpm": "7"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/synckit": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
@@ -5803,6 +5930,22 @@
}
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/uvu": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz",
@@ -6616,6 +6759,11 @@
"fastq": "^1.6.0"
}
},
+ "@panva/hkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.2.tgz",
+ "integrity": "sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA=="
+ },
"@pkgr/utils": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz",
@@ -6630,23 +6778,23 @@
}
},
"@prisma/client": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz",
- "integrity": "sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.10.0.tgz",
+ "integrity": "sha512-sBmYb1S6SMKFIESaLMfKqWSalv3pH73cMCsFt9HslJvYjIIcKQCA6PDL2O4SZGWvc4JBef9cg5Gd7d9x3AtKjw==",
"requires": {
- "@prisma/engines-version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5"
+ "@prisma/engines-version": "4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d"
}
},
"@prisma/engines": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.9.0.tgz",
- "integrity": "sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.10.0.tgz",
+ "integrity": "sha512-ZPPo7q+nQZdTlPFedS7mFXPE3oZ2kWtTh3GO4sku0XQ8ikLqEyinuTPJbQCw/8qel2xglIEQicsK6yI4Jgh20A==",
"devOptional": true
},
"@prisma/engines-version": {
- "version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5",
- "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz",
- "integrity": "sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA=="
+ "version": "4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d.tgz",
+ "integrity": "sha512-UVpmVlvSaGfY4ue+hh8CTkIesbuXCFUfrr8zk//+u85WwkKfWMtt6nLB2tNSzR1YO8eAA8+HqNf8LM7mnXIq5w=="
},
"@rushstack/eslint-patch": {
"version": "1.2.0",
@@ -7103,6 +7251,11 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
"copy-anything": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.3.tgz",
@@ -8345,6 +8498,11 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
+ "jose": {
+ "version": "4.11.4",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz",
+ "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ=="
+ },
"js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
@@ -9015,6 +9173,22 @@
"styled-jsx": "5.1.1"
}
},
+ "next-auth": {
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.19.2.tgz",
+ "integrity": "sha512-6V2YG3IJQVhgCAH7mvT3yopTW92gMdUrcwGX7NQ0dCreT/+axGua/JmVdarjec0C/oJukKpIYRgjMlV+L5ZQOQ==",
+ "requires": {
+ "@babel/runtime": "^7.16.3",
+ "@panva/hkdf": "^1.0.1",
+ "cookie": "^0.5.0",
+ "jose": "^4.9.3",
+ "oauth": "^0.9.15",
+ "openid-client": "^5.1.0",
+ "preact": "^10.6.3",
+ "preact-render-to-string": "^5.1.19",
+ "uuid": "^8.3.2"
+ }
+ },
"next-superjson-plugin": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/next-superjson-plugin/-/next-superjson-plugin-0.5.4.tgz",
@@ -9034,11 +9208,21 @@
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
+ "oauth": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="
+ },
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
+ "object-hash": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+ "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
+ },
"object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
@@ -9108,6 +9292,11 @@
"es-abstract": "^1.20.4"
}
},
+ "oidc-token-hash": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz",
+ "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ=="
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -9126,6 +9315,17 @@
"is-wsl": "^2.2.0"
}
},
+ "openid-client": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.0.tgz",
+ "integrity": "sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ==",
+ "requires": {
+ "jose": "^4.10.0",
+ "lru-cache": "^6.0.0",
+ "object-hash": "^2.0.1",
+ "oidc-token-hash": "^5.0.1"
+ }
+ },
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -9239,18 +9439,36 @@
"source-map-js": "^1.0.2"
}
},
+ "preact": {
+ "version": "10.12.0",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.0.tgz",
+ "integrity": "sha512-+w8ix+huD8CNZemheC53IPjMUFk921i02o30u0K6h53spMX41y/QhVDnG/nU2k42/69tvqWmVsgNLIiwRAcmxg=="
+ },
+ "preact-render-to-string": {
+ "version": "5.2.6",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz",
+ "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==",
+ "requires": {
+ "pretty-format": "^3.8.0"
+ }
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
},
+ "pretty-format": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
+ "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
+ },
"prisma": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz",
- "integrity": "sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w==",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.10.0.tgz",
+ "integrity": "sha512-xUHcF3Glc8QGgW8x0rfPITvyyTo04fskUdG7pI4kQbvDX/rhzDP4046x/FvazYqYHXMLR5/KTIi2p2Gth5vKOQ==",
"devOptional": true,
"requires": {
- "@prisma/engines": "4.9.0"
+ "@prisma/engines": "4.10.0"
}
},
"prismjs": {
@@ -9698,6 +9916,14 @@
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
+ "swr": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.0.3.tgz",
+ "integrity": "sha512-sGvQDok/AHEWTPfhUWXEHBVEXmgGnuahyhmRQbjl9XBYxT/MSlAzvXEKQpyM++bMPaI52vcWS2HiKNaW7+9OFw==",
+ "requires": {
+ "use-sync-external-store": "^1.2.0"
+ }
+ },
"synckit": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
@@ -9907,6 +10133,17 @@
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
"requires": {}
},
+ "use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "requires": {}
+ },
+ "uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+ },
"uvu": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz",
diff --git a/package.json b/package.json
index 1307367..7c373b1 100644
--- a/package.json
+++ b/package.json
@@ -10,13 +10,14 @@
},
"dependencies": {
"@next/font": "13.1.6",
- "@prisma/client": "^4.9.0",
+ "@prisma/client": "^4.10.0",
"@types/node": "18.11.19",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"eslint": "8.33.0",
"eslint-config-next": "13.1.6",
"next": "13.1.6",
+ "next-auth": "^4.19.2",
"next-superjson-plugin": "^0.5.4",
"react": "18.2.0",
"react-dom": "18.2.0",
@@ -27,12 +28,13 @@
"remark-gfm": "^3.0.1",
"remark-stringify": "^10.0.2",
"sass": "^1.58.0",
+ "swr": "^2.0.3",
"typescript": "4.9.5",
"url-join": "^5.0.0"
},
"devDependencies": {
"@types/react-select": "^5.0.1",
"@types/react-syntax-highlighter": "^15.5.6",
- "prisma": "^4.9.0"
+ "prisma": "^4.10.0"
}
}
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 669de45..ba425f8 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -8,16 +8,17 @@ import Footer from "@/components/Footer";
import Nav from "@/components/Nav";
import { Category } from "@prisma/client";
import prisma from "@/lib/prisma";
+import { SessionProvider } from "next-auth/react";
-export default function App({ Component, pageProps }: AppProps) {
+export default function App({ Component, pageProps: { session, ...pageProps } }: AppProps) {
return (
- <>
+
- >
+
);
}
diff --git a/pages/admin/editor/article/[articleId].tsx b/pages/admin/editor/article/[articleId].tsx
index d6d207c..5097e50 100644
--- a/pages/admin/editor/article/[articleId].tsx
+++ b/pages/admin/editor/article/[articleId].tsx
@@ -13,9 +13,13 @@ import { apiUrl } from "@/global";
import Markdown from "@/components/Markdown";
import prisma, { ArticleWithIncludes, CategoryWithIncludes } from "@/lib/prisma";
import { CLIENT_RENEG_LIMIT } from "tls";
+import { useSession } from "next-auth/react";
export default function AdminArticlesEditorPage({ article, categories }: { article: ArticleWithIncludes | null; categories: CategoryWithIncludes[] }) {
const router = useRouter();
+ const { status } = useSession({
+ required: true,
+ });
const [title, setTitle] = useState
(article?.title ?? "");
const [selectCategoriesOptions, setSelectCategoriesOptions] = useState<{ value: string; label: string }[]>(
@@ -116,132 +120,136 @@ export default function AdminArticlesEditorPage({ article, categories }: { artic
.catch(console.error);
}
- return (
-
-
{article ? "Update article" : "Create new article"}
-
-
-
-
+ if (status === "authenticated") {
+ return (
+
+
{article ? "Update article" : "Create new article"}
+
+
+
+
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
) => {
- setTitle(e.target.value);
+ setIntroduction(e.target.value);
}}
- className={!isValidText(title) && title ? "error" : ""}
+ className={!isValidText(introduction) && introduction ? "error" : ""}
type="text"
- name="title"
- placeholder="title"
- ref={titleRef}
- defaultValue={title}
+ name="introduction"
+ placeholder="Introduction"
+ ref={introductionRef}
+ defaultValue={introduction}
/>
-
-
-
-
-
-
-
-
- ) => {
- setIntroduction(e.target.value);
- }}
- className={!isValidText(introduction) && introduction ? "error" : ""}
- type="text"
- name="introduction"
- placeholder="Introduction"
- ref={introductionRef}
- defaultValue={introduction}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
- {contentTable?.map((entry: IContentTableEntry, i: number) => {
- return (
-
- {
- changeContentTableEntryAnchor(i, e.target.value);
- }}
- type="text"
- placeholder={"Anchor"}
- defaultValue={entry.anchor}
- />
- {
- changeContentTableEntryTitle(i, e.target.value);
- }}
- type="text"
- placeholder={"Title"}
- defaultValue={entry.title}
- />{" "}
-
-
- );
- })}
-
-
-
- );
+ );
+ } else {
+ return <>>;
+ }
}
export async function getServerSideProps(context: any) {
diff --git a/pages/admin/editor/category/[categoryId].tsx b/pages/admin/editor/category/[categoryId].tsx
index 209558f..23e6f39 100644
--- a/pages/admin/editor/category/[categoryId].tsx
+++ b/pages/admin/editor/category/[categoryId].tsx
@@ -9,8 +9,13 @@ import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { apiUrl } from "@/global";
import prisma, { CategoryWithIncludes } from "@/lib/prisma";
+import { useSession } from "next-auth/react";
export default function AdminCategoriesEditor({ category }: { category: CategoryWithIncludes | null }) {
+ const { status } = useSession({
+ required: true,
+ });
+
const router = useRouter();
const [title, setTitle] = useState
(category?.title ?? "");
const [color, setColor] = useState(category?.color ?? "");
@@ -85,80 +90,84 @@ export default function AdminCategoriesEditor({ category }: { category: Category
.catch(console.error);
}
- return (
-
-
{category ? "Update category" : "Create new category"}
-
-
-
-
-
-
-
-
- ) => {
- setTitle(e.target.value);
- }}
- className={!isValidText(title) && title ? "error" : ""}
- type="text"
- name="title"
- placeholder="title"
- ref={titleRef}
- defaultValue={title}
- />
-
-
-
-
-
+ if (status === "authenticated") {
+ return (
+
+
{category ? "Update category" : "Create new category"}
+
+
+
+
+
+
-
-
-
- ) => {
- setColor(e.target.value);
- }}
- type="color"
- ref={colorRef}
- defaultValue={color}
- />
-
-
- );
+ );
+ } else {
+ return <>>;
+ }
}
export async function getServerSideProps(context: any) {
diff --git a/pages/api/articles/[articleId].ts b/pages/api/articles/[articleId].ts
index 4db8bb6..64e8d4a 100644
--- a/pages/api/articles/[articleId].ts
+++ b/pages/api/articles/[articleId].ts
@@ -6,66 +6,72 @@ import prisma, { ArticleWithIncludes } from "../../../lib/prisma";
import type { NextApiRequest, NextApiResponse } from 'next'
import { UpdateArticle } from "../../../types/api";
import { isValidText } from "../../../validators";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../auth/[...nextauth]";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- const articleId: string = formatTextToUrlName(req.query?.articleId?.toString() ?? "")
-
- if (req.method == "PUT") {//* PUT
- console.log("PUT")
+ const session = await getServerSession(req, res, authOptions);
+ if (session) {
+ const articleId: string = formatTextToUrlName(req.query?.articleId?.toString() ?? "")
+ if (req.method == "PUT") {//* PUT
+ console.log("PUT")
- console.log(`API articleId: ${articleId}`)
- const articleData: UpdateArticle = req.body;
+ console.log(`API articleId: ${articleId}`)
+ const articleData: UpdateArticle = req.body;
- if (articleData.title && !isValidText(articleData.title)) {
- res.json({ target: "title", error: "Not a valid title" });
- return;
- }
-
- if (articleData.introduction && !isValidText(articleData.introduction)) {
- res.json({ target: "introduction", error: "Not a valid introduction" });
- return;
- }
-
- const newArticle: Prisma.ArticleUncheckedUpdateInput = {
- title: articleData.title ?? undefined,
- name: articleData.title ? formatTextToUrlName(articleData.title) : undefined,
- introduction: articleData.introduction ?? undefined,
-
- categoryId: articleData.categoryId ?? undefined,
- contentTable: articleData.contentTable ?? undefined,
- markdown: articleData.markdown ?? undefined,
- imageUrl: articleData.imageUrl ?? undefined,
- }
- console.log(newArticle)
- await prisma.article.update({ data: newArticle, where: { id: articleId }, include: { category: true } })
- .then(
- (data) => {
- res.json({ success: true, data: data });
- },
- (errorReason) => {
- console.log(errorReason)
- if (errorReason.code === "P2002") {
- res.json({ target: errorReason.meta.target[0], error: "Already exists" });
- }
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
- } else if (req.method == "DELETE") {
- console.log("DELETE article")
- prisma.article.delete({ where: { id: articleId }, include: { category: true } }).then((result: ArticleWithIncludes | null) => {
- if (result) {
- res.status(200).json(result)
- } else {
- res.status(500).json({ error: true, message: "No article found" })
+ if (articleData.title && !isValidText(articleData.title)) {
+ res.json({ target: "title", error: "Not a valid title" });
+ return;
}
- }, (err) => {
- console.log(err)
- res.status(500).end(err)
- })
+
+ if (articleData.introduction && !isValidText(articleData.introduction)) {
+ res.json({ target: "introduction", error: "Not a valid introduction" });
+ return;
+ }
+
+ const newArticle: Prisma.ArticleUncheckedUpdateInput = {
+ title: articleData.title ?? undefined,
+ name: articleData.title ? formatTextToUrlName(articleData.title) : undefined,
+ introduction: articleData.introduction ?? undefined,
+
+ categoryId: articleData.categoryId ?? undefined,
+ contentTable: articleData.contentTable ?? undefined,
+ markdown: articleData.markdown ?? undefined,
+ imageUrl: articleData.imageUrl ?? undefined,
+ }
+ console.log(newArticle)
+ await prisma.article.update({ data: newArticle, where: { id: articleId }, include: { category: true } })
+ .then(
+ (data) => {
+ res.json({ success: true, data: data });
+ },
+ (errorReason) => {
+ console.log(errorReason)
+ if (errorReason.code === "P2002") {
+ res.json({ target: errorReason.meta.target[0], error: "Already exists" });
+ }
+ }
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ } else if (req.method == "DELETE") {
+ console.log("DELETE article")
+ prisma.article.delete({ where: { id: articleId }, include: { category: true } }).then((result: ArticleWithIncludes | null) => {
+ if (result) {
+ res.status(200).json(result)
+ } else {
+ res.status(500).json({ error: true, message: "No article found" })
+ }
+ }, (err) => {
+ console.log(err)
+ res.status(500).end(err)
+ })
+ }
+ } else {
+ res.status(403).json({ error: true, message: "Authorization Required" });
}
}
diff --git a/pages/api/articles/index.ts b/pages/api/articles/index.ts
index 768d372..eedfb88 100644
--- a/pages/api/articles/index.ts
+++ b/pages/api/articles/index.ts
@@ -6,56 +6,64 @@ import { isValidText } from "../../../validators";
import type { NextApiRequest, NextApiResponse } from 'next'
import { Prisma } from '@prisma/client';
+import { getServerSession } from 'next-auth';
+import { authOptions } from "../auth/[...nextauth]";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- if (req.method == "POST") { //* POST
- console.log("API new article")
- const articleData: CreateArticle = req.body
- console.log(articleData)
+ const session = await getServerSession(req, res, authOptions);
+ if (session) {
+ if (req.method == "POST") { //* POST
+ console.log("API new article")
+ const articleData: CreateArticle = req.body
+ console.log(articleData)
- if (!isValidText(articleData.title)) {
- res.status(500).json({ target: "title", error: "Not a valid title" });
- return;
- }
+ if (!isValidText(articleData.title)) {
+ res.status(500).json({ target: "title", error: "Not a valid title" });
+ return;
+ }
- if (!isValidText(articleData.introduction)) {
- res.status(500).json({ target: "introduction", error: "Not a valid introduction" });
- return;
- }
+ if (!isValidText(articleData.introduction)) {
+ res.status(500).json({ target: "introduction", error: "Not a valid introduction" });
+ return;
+ }
- if (!articleData.categoryId) {
- res.status(500).json({ target: "category", error: "Category is required" });
- return;
- }
+ if (!articleData.categoryId) {
+ res.status(500).json({ target: "category", error: "Category is required" });
+ return;
+ }
- const newArticle: Prisma.ArticleUncheckedCreateInput = {
- title: articleData.title,
- name: formatTextToUrlName(articleData.title),
- introduction: articleData.introduction,
- categoryId: articleData.categoryId,
- markdown: articleData.markdown ?? "",
- contentTable: articleData.contentTable ?? {},
- imageUrl: articleData.imageUrl ?? ""
- }
+ const newArticle: Prisma.ArticleUncheckedCreateInput = {
+ title: articleData.title,
+ name: formatTextToUrlName(articleData.title),
+ introduction: articleData.introduction,
+ categoryId: articleData.categoryId,
+ markdown: articleData.markdown ?? "",
+ contentTable: articleData.contentTable ?? {},
+ imageUrl: articleData.imageUrl ?? ""
+ }
- prisma.article
- .create({ data: newArticle, include: { category: true } })
- .then(
- (data: ArticleWithIncludes) => {
- res.json({ success: true, data: data });
- },
- (errorReason) => {
- console.log("reason", errorReason)
- if (errorReason.code === "P2002") {
- res.json({ target: errorReason.meta.target[0], error: "Already exists" });
+ prisma.article
+ .create({ data: newArticle, include: { category: true } })
+ .then(
+ (data: ArticleWithIncludes) => {
+ res.json({ success: true, data: data });
+ },
+ (errorReason) => {
+ console.log("reason", errorReason)
+ if (errorReason.code === "P2002") {
+ res.json({ target: errorReason.meta.target[0], error: "Already exists" });
+ }
}
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ }
+ } else {
+ res.status(403).json({ error: true, message: "Authorization Required" });
}
+
}
diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts
new file mode 100644
index 0000000..63aa665
--- /dev/null
+++ b/pages/api/auth/[...nextauth].ts
@@ -0,0 +1,30 @@
+import NextAuth, { AuthOptions } from "next-auth"
+import GithubProvider from "next-auth/providers/github"
+export const authOptions: AuthOptions = {
+ // Configure one or more authentication providers
+ providers: [
+ GithubProvider({
+ clientId: "1afc604704e6ac0149e3", //! env vars
+ clientSecret: "b8f76990fc0a9181eaba23359a27b2d140ab67e7", //! env vars
+ }),
+ // ...add more providers here
+ ], callbacks: {
+ async signIn({ user, account, profile, email, credentials }) {
+
+ if (user.id.toString() == "76851529") { //! env vars
+ return true
+ } else {
+ // Return false to display a default error message
+ return false
+ // Or you can return a URL to redirect to:
+ // return '/unauthorized'
+ }
+ }
+ },
+ secret: "@AWeFkHpv!jzVr^a9nRXS8^PcRFnDaLvt65mJb&*C^pcCgpbHFzzKN",
+
+
+
+}
+export default NextAuth(authOptions)
+
diff --git a/pages/api/categories/[categoryId].ts b/pages/api/categories/[categoryId].ts
index d4d47d5..f29a63e 100644
--- a/pages/api/categories/[categoryId].ts
+++ b/pages/api/categories/[categoryId].ts
@@ -7,76 +7,83 @@ import type { NextApiRequest, NextApiResponse } from 'next'
import { formatTextToUrlName } from "../../../utils";
import { isValidText } from "../../../validators";
import { UpdateCategory } from '../../../types/api';
+import { getServerSession } from "next-auth";
+import { authOptions } from "../auth/[...nextauth]";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const categoryId: string = req.query.categoryId?.toString() ?? "";
- if (req.method == "PUT") {
+ const session = await getServerSession(req, res, authOptions);
+ if (session) {
+ if (req.method == "PUT") {
- const categoryData: UpdateCategory = req.body;
+ const categoryData: UpdateCategory = req.body;
- if (categoryData.title && !isValidText(categoryData.title)) {
- res.json({ target: "title", error: "Not a valid title" });
- return;
- }
-
- const newSvg: Prisma.SvgUncheckedUpdateInput = {
- viewbox: categoryData.svg?.viewbox ?? undefined,
- path: categoryData.svg?.path ?? undefined,
- };
-
- const newCategory: Prisma.CategoryUncheckedUpdateInput = {
- title: categoryData.title ?? undefined,
- name: categoryData.title ? formatTextToUrlName(categoryData.title) : undefined,
- color: categoryData.color ?? undefined,
- };
-
- await prisma.category
- .update({
- data: newCategory,
- where: { id: categoryId },
- include: { svg: true },
- })
- .then(
- async (categoryData) => {
- await prisma.svg
- .update({ data: newSvg, where: { id: categoryData.svg.id } })
- .then(
- (svgData) => {
- console.log("3");
- res.json({ success: true, data: categoryData });
- },
- (errorReason) => {
- res.status(500).end(errorReason);
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
- },
- (errorReason) => {
- console.log(errorReason);
- if (errorReason.code === "P2002") {
- res.json({ target: errorReason.meta.target[0], error: "Already exists" });
- }
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
- } else if (req.method == "DELETE") {
- console.log("DELETE category")
- prisma.category.delete({ where: { id: categoryId }, include: { articles: true, svg: true } }).then((result: CategoryWithIncludes | null) => {
- if (result) {
- res.status(200).json(result)
- } else {
- res.status(500).json({ error: true, message: "No category found" })
+ if (categoryData.title && !isValidText(categoryData.title)) {
+ res.json({ target: "title", error: "Not a valid title" });
+ return;
}
- }, (err) => {
- console.log(err)
- res.status(500).end(err)
- })
+
+ const newSvg: Prisma.SvgUncheckedUpdateInput = {
+ viewbox: categoryData.svg?.viewbox ?? undefined,
+ path: categoryData.svg?.path ?? undefined,
+ };
+
+ const newCategory: Prisma.CategoryUncheckedUpdateInput = {
+ title: categoryData.title ?? undefined,
+ name: categoryData.title ? formatTextToUrlName(categoryData.title) : undefined,
+ color: categoryData.color ?? undefined,
+ };
+
+ await prisma.category
+ .update({
+ data: newCategory,
+ where: { id: categoryId },
+ include: { svg: true },
+ })
+ .then(
+ async (categoryData) => {
+ await prisma.svg
+ .update({ data: newSvg, where: { id: categoryData.svg.id } })
+ .then(
+ (svgData) => {
+ console.log("3");
+ res.json({ success: true, data: categoryData });
+ },
+ (errorReason) => {
+ res.status(500).end(errorReason);
+ }
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ },
+ (errorReason) => {
+ console.log(errorReason);
+ if (errorReason.code === "P2002") {
+ res.json({ target: errorReason.meta.target[0], error: "Already exists" });
+ }
+ }
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ } else if (req.method == "DELETE") {
+ console.log("DELETE category")
+ prisma.category.delete({ where: { id: categoryId }, include: { articles: true, svg: true } }).then((result: CategoryWithIncludes | null) => {
+ if (result) {
+ res.status(200).json(result)
+ } else {
+ res.status(500).json({ error: true, message: "No category found" })
+ }
+ }, (err) => {
+ console.log(err)
+ res.status(500).end(err)
+ })
+ }
+ } else {
+ res.status(403).json({ error: true, message: "Authorization Required" });
}
}
diff --git a/pages/api/categories/index.ts b/pages/api/categories/index.ts
index c0d2db2..0f35eb0 100644
--- a/pages/api/categories/index.ts
+++ b/pages/api/categories/index.ts
@@ -8,8 +8,12 @@ import { isValidText } from "../../../validators";
import type { NextApiRequest, NextApiResponse } from 'next'
import { CreateCategory } from "@/types/api";
+import { getServerSession } from "next-auth";
+import { authOptions } from "../auth/[...nextauth]";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ const session = await getServerSession(req, res, authOptions);
+
if (req.method == "GET") {
console.log("API get categories")
await prisma.category.findMany().then((result: Category[]) => {
@@ -22,65 +26,69 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
})
} else
if (req.method == "POST") {
- console.log("API new category")
- const categoryData: CreateCategory = req.body;
- console.log(categoryData)
+ if (session) {
+ console.log("API new category")
+ const categoryData: CreateCategory = req.body;
+ console.log(categoryData)
- if (!isValidText(categoryData.title)) {
- res.json({ target: "title", error: "Not a valid title" });
- return;
- }
+ if (!isValidText(categoryData.title)) {
+ res.json({ target: "title", error: "Not a valid title" });
+ return;
+ }
- categoryData.svg.viewbox = categoryData.svg.viewbox.length > 1 ? categoryData.svg.viewbox : "";
+ categoryData.svg.viewbox = categoryData.svg.viewbox.length > 1 ? categoryData.svg.viewbox : "";
- const newSvg: Prisma.SvgUncheckedCreateInput = {
- viewbox: categoryData.svg.viewbox,
- path: categoryData.svg.path
- }
+ const newSvg: Prisma.SvgUncheckedCreateInput = {
+ viewbox: categoryData.svg.viewbox,
+ path: categoryData.svg.path
+ }
- await prisma.svg
- .create({ data: newSvg })
- .then(
- async (createdSvg: Svg) => {
- const newCategory: Prisma.CategoryUncheckedCreateInput = {
- title: categoryData.title,
- name: formatTextToUrlName(categoryData.title),
- color: categoryData.color ?? "teal",
- svgId: createdSvg.id,
+ await prisma.svg
+ .create({ data: newSvg })
+ .then(
+ async (createdSvg: Svg) => {
+ const newCategory: Prisma.CategoryUncheckedCreateInput = {
+ title: categoryData.title,
+ name: formatTextToUrlName(categoryData.title),
+ color: categoryData.color ?? "teal",
+ svgId: createdSvg.id,
+ }
+
+ await prisma.category
+ .create({
+ data: newCategory,
+ include: { svg: true, articles: true },
+ })
+ .then(
+ (createdCategory: CategoryWithIncludes | null) => {
+ if (createdCategory) {
+ res.json({ success: true, data: createdCategory });
+ } else {
+ res.json({ error: true, message: "Could not create category" });
+ }
+ },
+ (errorReason) => {
+ console.log(errorReason)
+ if (errorReason.code === "P2002") {
+ res.json({ target: errorReason.meta.target[0], error: "Already exists" });
+ }
+ }
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ },
+ (errorReason) => {
+ res.status(500).end(errorReason);
}
-
- await prisma.category
- .create({
- data: newCategory,
- include: { svg: true, articles: true },
- })
- .then(
- (createdCategory: CategoryWithIncludes | null) => {
- if (createdCategory) {
- res.json({ success: true, data: createdCategory });
- } else {
- res.json({ error: true, message: "Could not create category" });
- }
- },
- (errorReason) => {
- console.log(errorReason)
- if (errorReason.code === "P2002") {
- res.json({ target: errorReason.meta.target[0], error: "Already exists" });
- }
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
- },
- (errorReason) => {
- res.status(500).end(errorReason);
- }
- )
- .catch((err) => {
- console.error(err);
- res.status(500).end();
- });
+ )
+ .catch((err) => {
+ console.error(err);
+ res.status(500).end();
+ });
+ } else {
+ res.status(403).json({ error: true, message: "Authorization Required" });
+ }
}
}
diff --git a/pages/articles/[categoryName]/[articleName]/index.tsx b/pages/articles/[categoryName]/[articleName]/index.tsx
index db2336b..a1353dd 100644
--- a/pages/articles/[categoryName]/[articleName]/index.tsx
+++ b/pages/articles/[categoryName]/[articleName]/index.tsx
@@ -8,13 +8,14 @@ import prisma, { ArticleWithIncludes, CategoryWithIncludes } from "@/lib/prisma"
import ArticleControl from "../../../../components/ArticleControl";
import { IContentTableEntry } from "@/types/contentTable";
import { Prisma } from "@prisma/client";
+import { useSession, signIn, signOut } from "next-auth/react";
+import { CLIENT_RENEG_LIMIT } from "tls";
//* MAIN
export default function ArticlePage({ article }: { article: ArticleWithIncludes }) {
const dateUpdated: Date = new Date(article?.dateUpdated);
const dateCreated: Date = new Date(article?.dateCreated);
const dateOptions: Intl.DateTimeFormatOptions = { month: "long", day: "numeric", year: "numeric" };
-
return (
<>
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 6b88e97..01aee73 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -27,7 +27,7 @@ model Category {
title String @unique
color String
svgId String
- svg Svg @relation(fields: [svgId], references: [id])
+ svg Svg @relation(fields: [svgId], references: [id], onDelete: Cascade)
articles Article[]
dateCreated DateTime @default(now())
dateUpdated DateTime @default(now())