Compare commits
11 Commits
bb78d7f5af
...
1.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
| 25037f4798 | |||
| 38eee8b38c | |||
| 9fbd6e4191 | |||
| 88a9778f3a | |||
| c695d6c733 | |||
| 96388e5a50 | |||
| 888197b1c6 | |||
| 29b2ef1b17 | |||
| b26af58b51 | |||
| f10ccd0d16 | |||
| f6926b2230 |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
README.md
|
||||
.npmrc
|
||||
.prettierrc
|
||||
.eslintrc.cjs
|
||||
.graphqlrc
|
||||
.editorconfig
|
||||
.vscode
|
||||
node_modules
|
||||
build
|
||||
package
|
||||
**/.env
|
||||
.env*
|
||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM node:24-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
RUN npm prune --production
|
||||
|
||||
FROM node:24-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/build build/
|
||||
COPY --from=builder /app/node_modules node_modules/
|
||||
COPY package.json .
|
||||
EXPOSE 3000
|
||||
ENV NODE_ENV=production
|
||||
ENV PUBLIC_JEOPARDY_SERVER=127.0.0.1:12345
|
||||
CMD [ "node", "build" ]
|
||||
46
README.md
46
README.md
@@ -1,38 +1,34 @@
|
||||
# sv
|
||||
# Jeopardy
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```sh
|
||||
# create a new project in the current directory
|
||||
npx sv create
|
||||
|
||||
# create a new project in my-app
|
||||
npx sv create my-app
|
||||
```
|
||||
Ein Jeopardy-Style Projekt
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
Zum entwickeln am besten `docker compose` nutzen. Wichtig hierbei ist, dass man das JeopardyServer Projekt auch gebaut haben muss.
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
npm run docker-build
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Building
|
||||
Eventuell muss das `docker-compose.yml` und das `.env.local` angepasst werden, sollte aber eigentlich alles so stimmen.
|
||||
|
||||
To create a production version of your app:
|
||||
Ansonsten kann man auch mit `npm run dev` entwickeln.
|
||||
|
||||
## Build Production
|
||||
|
||||
1. Versionsnummer in `package.json` updaten
|
||||
2. commit erstellen und mit Versionsnummer taggen
|
||||
3. push des commits **und der tags**
|
||||
4. Auf Server connecten
|
||||
```sh
|
||||
npm run build
|
||||
sudo su
|
||||
cd /opt/jeopardy/Jeopardy
|
||||
git fetch --tags
|
||||
git checkout <versionsnummer>
|
||||
docker build -t jeopardy .
|
||||
docker tag jeopardy:latest jeopardy:<versionsnummer>
|
||||
cd ..
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
||||
|
||||
43
docker-compose.yml
Normal file
43
docker-compose.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
services:
|
||||
jeopardy:
|
||||
image: jeopardy:latest
|
||||
container_name: jeopardy
|
||||
environment:
|
||||
# domain:port or only domain, eg jeopardyserver.akolata.de
|
||||
PUBLIC_JEOPARDY_SERVER: localhost:11001
|
||||
PUBLIC_JEOPARDY_SERVER_PROTOCOL: http
|
||||
ports:
|
||||
- "11000:3000"
|
||||
jeopardyserver:
|
||||
image: jeopardyserver:latest
|
||||
container_name: jeopardyserver
|
||||
environment:
|
||||
JEOPARDYSERVER_MONGO_USERNAME: jeopardyadmin
|
||||
JEOPARDYSERVER_MONGO_PASSWORD: jGpklsI9vCdixel7sDGxVBsydlzdyX8A1Zank6a12QT827PC
|
||||
JEOPARDYSERVER_MONGO_URL: mongo:27017
|
||||
JEOPARDY_URL: http://localhost:11000
|
||||
ports:
|
||||
- "11001:12345"
|
||||
mongo:
|
||||
image: mongo:8.0.14
|
||||
restart: always
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: jeopardyadmin
|
||||
MONGO_INITDB_ROOT_PASSWORD: jGpklsI9vCdixel7sDGxVBsydlzdyX8A1Zank6a12QT827PC
|
||||
ports:
|
||||
- 11002:27017
|
||||
volumes:
|
||||
- mongodb_data_volume:/data/db
|
||||
mongo-express:
|
||||
image: mongo-express
|
||||
restart: always
|
||||
ports:
|
||||
- 11003:8081
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_URL: mongodb://jeopardyadmin:jGpklsI9vCdixel7sDGxVBsydlzdyX8A1Zank6a12QT827PC@mongo:27017/
|
||||
ME_CONFIG_BASICAUTH_ENABLED: true
|
||||
ME_CONFIG_BASICAUTH_USERNAME: Trushy
|
||||
ME_CONFIG_BASICAUTH_PASSWORD: IXvtRcbrXy7wX4VKfmwKzRdRnHwbMlDpLm4ETKk9jgzJoylhakUCpcRWN3xVbAuM
|
||||
|
||||
volumes:
|
||||
mongodb_data_volume:
|
||||
515
package-lock.json
generated
515
package-lock.json
generated
@@ -1,16 +1,20 @@
|
||||
{
|
||||
"name": "jeopardy",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "jeopardy",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.5",
|
||||
"dependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"cookie": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@sveltejs/adapter-auto": "^6.0.0",
|
||||
"@sveltejs/adapter-node": "^5.3.2",
|
||||
"@sveltejs/kit": "^2.22.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
@@ -817,6 +821,112 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs": {
|
||||
"version": "28.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz",
|
||||
"integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^5.0.1",
|
||||
"commondir": "^1.0.1",
|
||||
"estree-walker": "^2.0.2",
|
||||
"fdir": "^6.2.0",
|
||||
"is-reference": "1.2.1",
|
||||
"magic-string": "^0.30.3",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0 || 14 >= 14.17"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.68.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs/node_modules/is-reference": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
|
||||
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-json": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
|
||||
"integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-node-resolve": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz",
|
||||
"integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^5.0.1",
|
||||
"@types/resolve": "1.20.2",
|
||||
"deepmerge": "^4.2.2",
|
||||
"is-module": "^1.0.0",
|
||||
"resolve": "^1.22.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.78.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.47.1.tgz",
|
||||
@@ -1114,14 +1224,20 @@
|
||||
"acorn": "^8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/adapter-auto": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.1.0.tgz",
|
||||
"integrity": "sha512-shOuLI5D2s+0zTv2ab5M5PqfknXqWbKi+0UwB9yLTRIdzsK1R93JOO8jNhIYSHdW+IYXIYnLniu+JZqXs7h9Wg==",
|
||||
"node_modules/@sveltejs/adapter-node": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.3.2.tgz",
|
||||
"integrity": "sha512-nBJSipMb1KLjnAM7uzb+YpnA1VWKb+WdR+0mXEnXI6K1A3XYWbjkcjnW20ubg07sicK8XaGY/FAX3PItw39qBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-commonjs": "^28.0.1",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"rollup": "^4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@sveltejs/kit": "^2.0.0"
|
||||
"@sveltejs/kit": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/kit": {
|
||||
@@ -1163,6 +1279,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/kit/node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.1.3.tgz",
|
||||
@@ -1561,6 +1687,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/resolve": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.40.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz",
|
||||
@@ -1892,6 +2025,23 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axobject-query": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||
@@ -1933,6 +2083,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -2016,6 +2179,25 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commondir": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -2024,13 +2206,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"dev": true,
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
||||
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
@@ -2096,6 +2277,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
@@ -2113,6 +2303,20 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
@@ -2127,6 +2331,51 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.9",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
|
||||
@@ -2394,6 +2643,13 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@@ -2547,6 +2803,42 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
@@ -2562,6 +2854,52 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
@@ -2588,6 +2926,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
@@ -2612,6 +2962,45 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -2649,6 +3038,22 @@
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -2672,6 +3077,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-module": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
@@ -3073,6 +3485,15 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -3110,6 +3531,27 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"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/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/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@@ -3298,6 +3740,13 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -3579,6 +4028,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@@ -3624,6 +4079,27 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
@@ -3816,6 +4292,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "5.38.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.38.2.tgz",
|
||||
|
||||
11
package.json
11
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jeopardy",
|
||||
"private": true,
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
@@ -11,12 +11,13 @@
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint ."
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"docker-build": "docker build -t jeopardy ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@sveltejs/adapter-auto": "^6.0.0",
|
||||
"@sveltejs/adapter-node": "^5.3.2",
|
||||
"@sveltejs/kit": "^2.22.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
@@ -33,5 +34,9 @@
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"vite": "^7.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"cookie": "^1.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
11
src/app.css
11
src/app.css
@@ -17,6 +17,17 @@
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
color: grey !important;
|
||||
border-color: gray !important;
|
||||
cursor: unset !important;
|
||||
}
|
||||
|
||||
.btn:disabled:hover {
|
||||
background-color: unset !important;
|
||||
cursor: unset !important;
|
||||
}
|
||||
|
||||
.inputField {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"
|
||||
/>
|
||||
<script src="https://kit.fontawesome.com/4115dc7344.js" crossorigin="anonymous"></script>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" class="size-full">
|
||||
|
||||
26
src/lib/Auth.svelte.ts
Normal file
26
src/lib/Auth.svelte.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import axios from "axios";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import UserSvelte, { type UserObj } from "./User.svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
export async function isAuthenticated() {
|
||||
if (location.pathname.startsWith("/login")) {
|
||||
return true;
|
||||
}
|
||||
return axios
|
||||
.get(`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/auth`, {
|
||||
withCredentials: true
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
UserSvelte.user = res.data as UserObj;
|
||||
console.log(UserSvelte.id, UserSvelte.username, UserSvelte.role);
|
||||
return true;
|
||||
} else {
|
||||
goto("/login");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
goto("/login");
|
||||
});
|
||||
}
|
||||
85
src/lib/Modal.svelte
Normal file
85
src/lib/Modal.svelte
Normal file
@@ -0,0 +1,85 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
interface Props {
|
||||
showModal: boolean;
|
||||
header: Snippet;
|
||||
children: Snippet;
|
||||
actionButtons?: Snippet;
|
||||
cancelFn?: () => void;
|
||||
okFn: () => Promise<boolean>;
|
||||
oncloseFn?: () => void;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
let {
|
||||
showModal = $bindable(),
|
||||
header,
|
||||
children,
|
||||
cancelFn,
|
||||
okFn,
|
||||
oncloseFn,
|
||||
actionButtons
|
||||
}: Props = $props();
|
||||
|
||||
let dialog: HTMLDialogElement | undefined = $state(); // HTMLDialogElement
|
||||
|
||||
$effect(() => {
|
||||
if (showModal) dialog?.showModal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_noninteractive_element_interactions -->
|
||||
<dialog
|
||||
bind:this={dialog}
|
||||
onclose={() => {
|
||||
showModal = false;
|
||||
if (oncloseFn) oncloseFn();
|
||||
}}
|
||||
onclick={(e) => {
|
||||
if (e.target === dialog) dialog.close();
|
||||
}}
|
||||
class="rounded-md"
|
||||
>
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
{@render header?.()}
|
||||
{@render children?.()}
|
||||
<!-- svelte-ignore a11y_autofocus -->
|
||||
<div class="flex justify-end gap-4">
|
||||
{@render actionButtons?.()}
|
||||
<button
|
||||
autofocus
|
||||
onclick={() => {
|
||||
dialog?.close();
|
||||
if (cancelFn) cancelFn();
|
||||
}}
|
||||
class="btn">Abbrechen</button
|
||||
>
|
||||
<button
|
||||
autofocus
|
||||
onclick={async () => {
|
||||
if (await okFn()) {
|
||||
dialog?.close();
|
||||
}
|
||||
}}
|
||||
class="btn min-w-[64px]">Ok</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<style>
|
||||
dialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
/* Move it back 50% relative to self */
|
||||
-webkit-transform: translateX(-50%) translateY(-50%);
|
||||
-moz-transform: translateX(-50%) translateY(-50%);
|
||||
-ms-transform: translateX(-50%) translateY(-50%);
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
</style>
|
||||
35
src/lib/User.svelte.ts
Normal file
35
src/lib/User.svelte.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
let username: string = $state("");
|
||||
let role: string = $state("");
|
||||
let id: string = $state("");
|
||||
|
||||
export type UserObj = {
|
||||
username: string;
|
||||
role: string;
|
||||
_id: string;
|
||||
};
|
||||
|
||||
export default {
|
||||
get username(): string {
|
||||
return username;
|
||||
},
|
||||
set username(uname: string) {
|
||||
username = uname;
|
||||
},
|
||||
get role(): string {
|
||||
return role;
|
||||
},
|
||||
set role(newrole: string) {
|
||||
role = newrole;
|
||||
},
|
||||
get id(): string {
|
||||
return id;
|
||||
},
|
||||
set id(newid: string) {
|
||||
id = newid;
|
||||
},
|
||||
set user(userobj: UserObj) {
|
||||
username = userobj.username;
|
||||
role = userobj.role;
|
||||
id = userobj._id;
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import { env } from "$env/dynamic/public";
|
||||
|
||||
export enum SocketConnectionType {
|
||||
NONE = "NONE",
|
||||
HOST = "HOST",
|
||||
@@ -11,7 +13,9 @@ let socket: WebSocket | undefined;
|
||||
|
||||
const connectAsHost = () => {
|
||||
if (socket !== undefined) return;
|
||||
socket = new WebSocket("ws://127.0.0.1:12345");
|
||||
socket = new WebSocket(
|
||||
`${location.protocol === "https:" ? "wss" : "ws"}://${env.PUBLIC_JEOPARDY_SERVER ?? "127.0.0.1:12345"}/websocket`
|
||||
);
|
||||
socket.addEventListener("open", onOpen(SocketConnectionType.HOST));
|
||||
socket.addEventListener("message", onFirstMessage);
|
||||
socket.addEventListener("close", onClose);
|
||||
@@ -20,7 +24,9 @@ const connectAsHost = () => {
|
||||
|
||||
const connectAsDisplay = () => {
|
||||
if (socket !== undefined) return;
|
||||
socket = new WebSocket("ws://127.0.0.1:12345");
|
||||
socket = new WebSocket(
|
||||
`${location.protocol === "https:" ? "wss" : "ws"}://${env.PUBLIC_JEOPARDY_SERVER ?? "127.0.0.1:12345"}/websocket`
|
||||
);
|
||||
socket.addEventListener("open", onOpen(SocketConnectionType.DISPLAY));
|
||||
socket.addEventListener("message", onFirstMessage);
|
||||
};
|
||||
@@ -37,10 +43,12 @@ const sendMessage = (obj: unknown) => {
|
||||
};
|
||||
|
||||
function onOpen(type: SocketConnectionType) {
|
||||
return (event: Event) => {
|
||||
return async (event: Event) => {
|
||||
console.log("Connection established");
|
||||
console.log(event);
|
||||
if (socket === undefined) return;
|
||||
// somehow beeing to fast so have to wait some time
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
socket.send(type.toString());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
<script lang="ts">
|
||||
import "../app.css";
|
||||
import favicon from "$lib/assets/favicon.svg";
|
||||
import { afterNavigate } from "$app/navigation";
|
||||
import { isAuthenticated } from "$lib/Auth.svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let renderit = $state(false);
|
||||
|
||||
afterNavigate(() => {
|
||||
isAuthenticated()
|
||||
.then(() => {
|
||||
renderit = true;
|
||||
})
|
||||
.catch(() => {
|
||||
renderit = true;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<link rel="icon" href={favicon} />
|
||||
</svelte:head>
|
||||
|
||||
{#if renderit}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import UserSvelte from "$lib/User.svelte";
|
||||
import websocket, { SocketConnectionType } from "$lib/websocket.svelte";
|
||||
import axios from "axios";
|
||||
|
||||
$effect(() => {
|
||||
if (websocket.connectionType === SocketConnectionType.HOST) {
|
||||
@@ -12,17 +15,72 @@
|
||||
goto("/connected/display");
|
||||
}
|
||||
});
|
||||
|
||||
function logout() {
|
||||
cookieStore
|
||||
.delete("jeopardytoken")
|
||||
.then(() => {
|
||||
goto("/login");
|
||||
})
|
||||
.catch((e) => {
|
||||
alert("Logout fehlgeschlagen!");
|
||||
goto("/login");
|
||||
});
|
||||
}
|
||||
|
||||
async function logoutFromAllDevices() {
|
||||
axios
|
||||
.post(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/user/logout`,
|
||||
{},
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
logout();
|
||||
})
|
||||
.catch(() => {
|
||||
alert("Logout fehlgeschlagen!");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col">
|
||||
<h1 class="m-4 mb-8 text-7xl font-bold">Jeopardy</h1>
|
||||
<div class="ms-4 me-4 flex items-center gap-4">
|
||||
<h1 class="text-7xl font-bold">Jeopardy</h1>
|
||||
<div class="grow"></div>
|
||||
{#if UserSvelte.role === "admin"}
|
||||
<button type="button" class="btn" onclick={() => goto("/admin")}>Administration</button>
|
||||
{/if}
|
||||
<button type="button" class="btn" onclick={() => goto("/settings")}>Einstellungen</button>
|
||||
<button type="button" class="btn" onclick={logout}>Logout</button>
|
||||
<button type="button" class="btn" onclick={logoutFromAllDevices}
|
||||
>Logout von allen Geräten</button
|
||||
>
|
||||
<div class="btn profile ps-2 pe-2">
|
||||
<i class="fa-regular fa-user"></i>
|
||||
{UserSvelte.username}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex h-full grow items-center justify-around p-4">
|
||||
<button class="btn m-2 h-1/2 w-1/2 text-5xl" onclick={websocket.connectAsHost}
|
||||
>Connect as Host</button
|
||||
>Spiel hosten</button
|
||||
>
|
||||
<button class="btn m-2 h-1/2 w-1/2 text-5xl" onclick={websocket.connectAsDisplay}
|
||||
>Connect as Display</button
|
||||
>Spiel darstellen</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.profile {
|
||||
border-color: gray;
|
||||
}
|
||||
|
||||
.profile:hover {
|
||||
background-color: unset !important;
|
||||
cursor: unset !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
350
src/routes/admin/+page.svelte
Normal file
350
src/routes/admin/+page.svelte
Normal file
@@ -0,0 +1,350 @@
|
||||
<script lang="ts">
|
||||
import { afterNavigate, goto } from "$app/navigation";
|
||||
import type { UserObj } from "$lib/User.svelte";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import axios from "axios";
|
||||
import { onMount } from "svelte";
|
||||
import Modal from "$lib/Modal.svelte";
|
||||
import UserSvelte from "$lib/User.svelte";
|
||||
|
||||
let users: UserObj[] = $state([]);
|
||||
let roles: string[] = $state([]);
|
||||
|
||||
let showAddUser = $state(false);
|
||||
let addUserName = $state("");
|
||||
|
||||
let showDeleteUser = $state(false);
|
||||
let showResetPassword = $state(false);
|
||||
let showChangeRole = $state(false);
|
||||
let selectedUser: UserObj | undefined = $state(undefined);
|
||||
let roleToChange: string = $state("");
|
||||
|
||||
let error = $state("");
|
||||
|
||||
async function loadUsers() {
|
||||
console.log("loading users");
|
||||
return axios
|
||||
.get(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/user/list`,
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
users = response.data;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
|
||||
async function loadRoles() {
|
||||
console.log("loading roles");
|
||||
return axios
|
||||
.get(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/roles`,
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
roles = response.data;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
|
||||
afterNavigate(() => {
|
||||
if (UserSvelte.role !== "admin") goto("/");
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
if (UserSvelte.role !== "admin") goto("/");
|
||||
loadRoles().then(loadUsers);
|
||||
});
|
||||
|
||||
async function addUserOk(): Promise<boolean> {
|
||||
error = "";
|
||||
if (addUserName.length <= 0) {
|
||||
error = "Gib einen Nutzernamen ein";
|
||||
return false;
|
||||
}
|
||||
|
||||
return axios
|
||||
.put(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/user`,
|
||||
{
|
||||
username: addUserName
|
||||
},
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
alert(`Passwort: ${response.data.password}`);
|
||||
return true;
|
||||
} else {
|
||||
throw false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
error = "Etwas ist schief gelaufen";
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteUserOk(): Promise<boolean> {
|
||||
error = "";
|
||||
|
||||
if (selectedUser === undefined) {
|
||||
error = "Etwas ist schief gelaufen. Kein Nutzer zum Löschen definiert.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return axios
|
||||
.delete(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/user`,
|
||||
{
|
||||
withCredentials: true,
|
||||
data: {
|
||||
userid: selectedUser._id
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
return true;
|
||||
})
|
||||
.catch(() => {
|
||||
error = "Nutzer konnte nicht gelöscht werden";
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async function resetPasswordOk(): Promise<boolean> {
|
||||
error = "";
|
||||
|
||||
if (selectedUser === undefined) {
|
||||
error = "Etwas ist schief gelaufen. Kein Nutzer zum Löschen definiert.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return axios
|
||||
.post(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/user/resetpw`,
|
||||
{
|
||||
userid: selectedUser._id
|
||||
},
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
alert(`Passwort: ${response.data.password}`);
|
||||
return true;
|
||||
} else {
|
||||
throw false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
error = "Etwas ist schief gelaufen";
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async function changeRoleOk(): Promise<boolean> {
|
||||
error = "";
|
||||
|
||||
if (selectedUser === undefined) {
|
||||
error = "Etwas ist schief gelaufen. Kein Nutzer zum Löschen definiert.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (roleToChange === selectedUser.role) {
|
||||
error = `${selectedUser.username} hat bereits die Rolle ${roleToChange}. Wähle eine andere Rolle aus.`;
|
||||
return false;
|
||||
}
|
||||
|
||||
return axios
|
||||
.post(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/admin/user/changerole`,
|
||||
{
|
||||
userid: selectedUser._id,
|
||||
role: roleToChange
|
||||
},
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
throw false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
error = "Etwas ist schief gelaufen";
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function addUserCancel() {
|
||||
error = "";
|
||||
addUserName = "";
|
||||
}
|
||||
|
||||
function selectedUserCancel() {
|
||||
error = "";
|
||||
selectedUser = undefined;
|
||||
roleToChange = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<div class="flex items-center">
|
||||
<h2 class="text-4xl font-bold">Administration</h2>
|
||||
<div class="grow"></div>
|
||||
<button type="button" class="btn" onclick={() => goto("/")}>Zurück</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each users as user (user._id)}
|
||||
<div class="flex justify-between gap-4 rounded-md border-1 p-2">
|
||||
<div class="shrink-0 grow-0 text-center align-middle">{user._id}</div>
|
||||
<div>{user.username}</div>
|
||||
<div>{user.role}</div>
|
||||
<div class="flex gap-2">
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
disabled={user._id === UserSvelte.id}
|
||||
onclick={() => {
|
||||
selectedUser = user;
|
||||
roleToChange = selectedUser.role;
|
||||
showChangeRole = true;
|
||||
}}><i class="fa-solid fa-user"></i> Rolle ändern</button
|
||||
>
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn"
|
||||
disabled={user._id === UserSvelte.id}
|
||||
onclick={() => {
|
||||
selectedUser = user;
|
||||
showResetPassword = true;
|
||||
}}
|
||||
><i class="fa-solid fa-arrow-rotate-right"></i> Passwort zurücksetzen</button
|
||||
>
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
<button
|
||||
disabled={user._id === UserSvelte.id}
|
||||
type="button"
|
||||
class="btn border-red-600 text-red-600"
|
||||
onclick={() => {
|
||||
selectedUser = user;
|
||||
showDeleteUser = true;
|
||||
}}><i class="fa-solid fa-trash"></i></button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<button type="button" class="btn" onclick={() => (showAddUser = true)}>Nutzer hinzufügen</button
|
||||
>
|
||||
</div>
|
||||
|
||||
<Modal bind:showModal={showAddUser} okFn={addUserOk} cancelFn={addUserCancel} oncloseFn={loadUsers}>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Nutzer hinzufügen</h2>
|
||||
{/snippet}
|
||||
|
||||
<div>
|
||||
<label for="username" class="">Name</label>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
class="borders mt-2 mb-2 w-full"
|
||||
bind:value={addUserName}
|
||||
/>
|
||||
</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
bind:showModal={showDeleteUser}
|
||||
okFn={deleteUserOk}
|
||||
cancelFn={selectedUserCancel}
|
||||
oncloseFn={loadUsers}
|
||||
>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Nutzer löschen</h2>
|
||||
{/snippet}
|
||||
|
||||
<div>Soll Nutzer {selectedUser?.username} wirklich gelöscht werden?</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
bind:showModal={showResetPassword}
|
||||
okFn={resetPasswordOk}
|
||||
cancelFn={selectedUserCancel}
|
||||
oncloseFn={loadUsers}
|
||||
>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Passwort zurücksetzen</h2>
|
||||
{/snippet}
|
||||
|
||||
<div>
|
||||
Soll das Passwort von Nutzer {selectedUser?.username} wirklich zurückgesetzt werden?
|
||||
</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
bind:showModal={showChangeRole}
|
||||
okFn={changeRoleOk}
|
||||
cancelFn={selectedUserCancel}
|
||||
oncloseFn={loadUsers}
|
||||
>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Rolle von {selectedUser?.username} ändern</h2>
|
||||
{/snippet}
|
||||
|
||||
<div>
|
||||
{#if selectedUser}
|
||||
<select name="roles" id="role-select" class="btn w-full" bind:value={roleToChange}>
|
||||
{#each roles as role, index (index)}
|
||||
<option value={role}>{role}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.borders {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
69
src/routes/login/+page.svelte
Normal file
69
src/routes/login/+page.svelte
Normal file
@@ -0,0 +1,69 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import UserState, { type UserObj } from "$lib/User.svelte";
|
||||
import axios from "axios";
|
||||
|
||||
let username = $state("");
|
||||
let password = $state("");
|
||||
let error = $state("");
|
||||
|
||||
async function login() {
|
||||
axios
|
||||
.post(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/auth/login`,
|
||||
{
|
||||
username: username,
|
||||
password: password
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
UserState.user = response.data as UserObj;
|
||||
console.log(UserState.id, UserState.username, UserState.role);
|
||||
goto("/");
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
error = "Login fehlgeschlagen";
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex h-full w-full items-center justify-center">
|
||||
<div class="borders flex-col items-center justify-center">
|
||||
<div>
|
||||
<label for="username" class="ms-4">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
class="borders ms-4 me-4 mt-2 mb-4"
|
||||
bind:value={username}
|
||||
/>
|
||||
<label for="password" class="ms-4">Passwort</label>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
class="borders ms-4 me-4 mt-2 mb-4"
|
||||
bind:value={password}
|
||||
/>
|
||||
</div>
|
||||
<button type="button" class="btn mb-2 w-fit ps-4 pe-4" onclick={login}>Login</button>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.borders {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
font-size: larger;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
92
src/routes/settings/+page.svelte
Normal file
92
src/routes/settings/+page.svelte
Normal file
@@ -0,0 +1,92 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import UserState, { type UserObj } from "$lib/User.svelte";
|
||||
import axios from "axios";
|
||||
|
||||
let oldpassword = $state("");
|
||||
let newpassword = $state("");
|
||||
let reppassword = $state("");
|
||||
let error = $state("");
|
||||
|
||||
async function changePassword() {
|
||||
if (newpassword !== reppassword) {
|
||||
error = "Passwörter stimmen nicht überein.";
|
||||
} else {
|
||||
error = "";
|
||||
}
|
||||
|
||||
axios
|
||||
.post(
|
||||
`${env.PUBLIC_JEOPARDY_SERVER_PROTOCOL}://${env.PUBLIC_JEOPARDY_SERVER}/user/changepw`,
|
||||
{
|
||||
old: oldpassword,
|
||||
new: newpassword
|
||||
},
|
||||
{ withCredentials: true }
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
goto("/login");
|
||||
} else {
|
||||
error = "Passwort ändern fehlgeschlagen";
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
error = "Passwort ändern fehlgeschlagen";
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<div class="flex items-center">
|
||||
<h2 class="text-4xl font-bold">Einstellungen</h2>
|
||||
<div class="grow"></div>
|
||||
<button type="button" class="btn" onclick={() => goto("/")}>Zurück</button>
|
||||
</div>
|
||||
<div class="rounded-md border-1 p-4">
|
||||
<h4 class="font-bold">Passwort ändern</h4>
|
||||
<div>
|
||||
<label for="oldpassword" class="">Altes Passwort</label>
|
||||
<input
|
||||
type="password"
|
||||
name="oldpassword"
|
||||
id="oldpassword"
|
||||
class="borders me-4 mt-2 mb-4"
|
||||
bind:value={oldpassword}
|
||||
/>
|
||||
<label for="newpassword" class="">Neues Passwort</label>
|
||||
<input
|
||||
type="password"
|
||||
name="newpassword"
|
||||
id="newpassword"
|
||||
class="borders me-4 mt-2 mb-4"
|
||||
bind:value={newpassword}
|
||||
/>
|
||||
<label for="reppassword" class="">Neues Passwort wiederholen</label>
|
||||
<input
|
||||
type="password"
|
||||
name="reppassword"
|
||||
id="reppassword"
|
||||
class="borders me-4 mt-2 mb-4"
|
||||
bind:value={reppassword}
|
||||
/>
|
||||
</div>
|
||||
<button type="button" class="btn mb-2 w-fit ps-4 pe-4" onclick={changePassword}
|
||||
>Passwort ändern</button
|
||||
>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.borders {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
font-size: larger;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
import adapter from "@sveltejs/adapter-node";
|
||||
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
@@ -8,8 +8,6 @@ const config = {
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss(), sveltekit()]
|
||||
plugins: [sveltekit(), tailwindcss()]
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user