✨ Added session-management with a map!
This commit is contained in:
@@ -252,3 +252,9 @@ async def delete_session(session_id: str, user: User = Depends(get_current_user)
|
|||||||
raise HTTPException(status_code=400, detail="Invalid session id")
|
raise HTTPException(status_code=400, detail="Invalid session id")
|
||||||
await UserSession.objects.filter(user=user, id=session_id).delete()
|
await UserSession.objects.filter(user=user, id=session_id).delete()
|
||||||
return {"message": "Session deleted"}
|
return {"message": "Session deleted"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/session", response_model=UserSession, response_model_exclude={"user", "session_key"})
|
||||||
|
async def get_session(user: User = Depends(get_current_user)):
|
||||||
|
session = await UserSession.objects.filter(user=user).first()
|
||||||
|
return session
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ import io
|
|||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
import qrcode.image.svg
|
import qrcode.image.svg
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter, Depends
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
|
from pydantic import BaseModel, Field, ValidationError
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from classquiz.auth import get_current_user
|
||||||
from classquiz.config import settings
|
from classquiz.config import settings
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
|
||||||
|
from classquiz.db.models import User
|
||||||
|
|
||||||
settings = settings()
|
settings = settings()
|
||||||
|
|
||||||
@@ -23,3 +29,31 @@ async def get_qr(quiz_pin: str):
|
|||||||
qr.make(fit=True)
|
qr.make(fit=True)
|
||||||
qr.make_image(fill_color="black", back_color="white").save(buf, "SVG")
|
qr.make_image(fill_color="black", back_color="white").save(buf, "SVG")
|
||||||
return Response(content=buf.getvalue(), media_type="image/svg+xml")
|
return Response(content=buf.getvalue(), media_type="image/svg+xml")
|
||||||
|
|
||||||
|
|
||||||
|
class IpResponse(BaseModel):
|
||||||
|
status: str
|
||||||
|
country: str
|
||||||
|
countryCode: str
|
||||||
|
region: str
|
||||||
|
regionName: str
|
||||||
|
city: str
|
||||||
|
zip: str
|
||||||
|
lat: float
|
||||||
|
lon: float
|
||||||
|
timezone: str
|
||||||
|
isp: str
|
||||||
|
org: str
|
||||||
|
as_attr: str = Field(alias="as")
|
||||||
|
query: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/ip-lookup/{ip}", response_model=IpResponse)
|
||||||
|
async def get_ip_data(ip: str, _: User = Depends(get_current_user)):
|
||||||
|
async with ClientSession() as session:
|
||||||
|
async with session.get(f"http://ip-api.com/json/{ip}") as response:
|
||||||
|
data = await response.json()
|
||||||
|
try:
|
||||||
|
return IpResponse(**data)
|
||||||
|
except ValidationError:
|
||||||
|
return JSONResponse(status_code=response.status, content=data)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ FROM node:17.8-bullseye as builder
|
|||||||
# ENV API_URL=http://api:80
|
# ENV API_URL=http://api:80
|
||||||
ENV API_URL=https://mawoka.eu
|
ENV API_URL=https://mawoka.eu
|
||||||
ENV REDIS_URL=CHANGE_ME
|
ENV REDIS_URL=CHANGE_ME
|
||||||
|
ENV VITE_MAPBOX_ACCESS_TOKEN=pk.eyJ1IjoibWF3b2thIiwiYSI6ImNsMjBob3d4ZjBhcGszYnE0bWp4aXB1ZW4ifQ.IByxV1qeIuEWpHCWsuB88A
|
||||||
|
# This Mpbox-token is restricted to the following urls: classquiz.de, classquiz.mawoka.eu, test.com
|
||||||
ENV VITE_HCAPTCHA=ee81b2a1-acf3-4d20-b2a4-a7ea94c7eba5
|
ENV VITE_HCAPTCHA=ee81b2a1-acf3-4d20-b2a4-a7ea94c7eba5
|
||||||
ENV VITE_SENTRY=https://4981de1f72f24fd7b5e21b8913b93a02@o661934.ingest.sentry.io/6254641
|
ENV VITE_SENTRY=https://4981de1f72f24fd7b5e21b8913b93a02@o661934.ingest.sentry.io/6254641
|
||||||
# change working directory
|
# change working directory
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"translations-scan": "i18next-scanner --config i18next-scanner.config.engine.cjs src/**/*.svelte"
|
"translations-scan": "i18next-scanner --config i18next-scanner.config.engine.cjs src/**/*.svelte"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@beyonk/svelte-mapbox": "^8.1.4",
|
||||||
"@felte/validator-yup": "^1.0.3",
|
"@felte/validator-yup": "^1.0.3",
|
||||||
"@fontsource/marck-script": "^4.5.5",
|
"@fontsource/marck-script": "^4.5.5",
|
||||||
"@sentry/browser": "^6.19.6",
|
"@sentry/browser": "^6.19.6",
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
"@types/cookie": "^0.4.1",
|
"@types/cookie": "^0.4.1",
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.1",
|
||||||
"@types/luxon": "^2.3.1",
|
"@types/luxon": "^2.3.1",
|
||||||
|
"@types/ua-parser-js": "^0.7.36",
|
||||||
"@types/yup": "^0.29.13",
|
"@types/yup": "^0.29.13",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.19.0",
|
"@typescript-eslint/eslint-plugin": "^5.19.0",
|
||||||
"@typescript-eslint/parser": "^5.19.0",
|
"@typescript-eslint/parser": "^5.19.0",
|
||||||
@@ -39,7 +41,9 @@
|
|||||||
"i18next-browser-languagedetector": "^6.1.4",
|
"i18next-browser-languagedetector": "^6.1.4",
|
||||||
"ioredis": "^5.0.4",
|
"ioredis": "^5.0.4",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
|
"leaflet": "^1.7.1",
|
||||||
"luxon": "^2.3.1",
|
"luxon": "^2.3.1",
|
||||||
|
"mapbox-gl": "^2.8.1",
|
||||||
"node-fetch": "^3.2.3",
|
"node-fetch": "^3.2.3",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
"postcss-load-config": "^3.1.4",
|
"postcss-load-config": "^3.1.4",
|
||||||
@@ -49,6 +53,7 @@
|
|||||||
"socket.io-client": "^4.4.1",
|
"socket.io-client": "^4.4.1",
|
||||||
"svelte": "^3.47.0",
|
"svelte": "^3.47.0",
|
||||||
"svelte-check": "^2.6.0",
|
"svelte-check": "^2.6.0",
|
||||||
|
"svelte-leafletjs": "^0.8.2",
|
||||||
"svelte-preprocess": "^4.10.5",
|
"svelte-preprocess": "^4.10.5",
|
||||||
"svelte-tippy": "^1.3.2",
|
"svelte-tippy": "^1.3.2",
|
||||||
"swiper": "^8.1.0",
|
"swiper": "^8.1.0",
|
||||||
@@ -56,6 +61,8 @@
|
|||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"typescript": "~4.6",
|
"typescript": "~4.6",
|
||||||
|
"ua-parser-js": "^1.0.2",
|
||||||
|
"vite-plugin-iso-import": "^0.1.3",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
Generated
+318
@@ -1,6 +1,7 @@
|
|||||||
lockfileVersion: 5.3
|
lockfileVersion: 5.3
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@beyonk/svelte-mapbox': ^8.1.4
|
||||||
'@felte/validator-yup': ^1.0.3
|
'@felte/validator-yup': ^1.0.3
|
||||||
'@fontsource/marck-script': ^4.5.5
|
'@fontsource/marck-script': ^4.5.5
|
||||||
'@sentry/browser': ^6.19.6
|
'@sentry/browser': ^6.19.6
|
||||||
@@ -12,6 +13,7 @@ specifiers:
|
|||||||
'@types/cookie': ^0.4.1
|
'@types/cookie': ^0.4.1
|
||||||
'@types/js-cookie': ^3.0.1
|
'@types/js-cookie': ^3.0.1
|
||||||
'@types/luxon': ^2.3.1
|
'@types/luxon': ^2.3.1
|
||||||
|
'@types/ua-parser-js': ^0.7.36
|
||||||
'@types/yup': ^0.29.13
|
'@types/yup': ^0.29.13
|
||||||
'@typescript-eslint/eslint-plugin': ^5.19.0
|
'@typescript-eslint/eslint-plugin': ^5.19.0
|
||||||
'@typescript-eslint/parser': ^5.19.0
|
'@typescript-eslint/parser': ^5.19.0
|
||||||
@@ -27,7 +29,9 @@ specifiers:
|
|||||||
i18next-browser-languagedetector: ^6.1.4
|
i18next-browser-languagedetector: ^6.1.4
|
||||||
ioredis: ^5.0.4
|
ioredis: ^5.0.4
|
||||||
js-cookie: ^3.0.1
|
js-cookie: ^3.0.1
|
||||||
|
leaflet: ^1.7.1
|
||||||
luxon: ^2.3.1
|
luxon: ^2.3.1
|
||||||
|
mapbox-gl: ^2.8.1
|
||||||
node-fetch: ^3.2.3
|
node-fetch: ^3.2.3
|
||||||
postcss: ^8.4.12
|
postcss: ^8.4.12
|
||||||
postcss-load-config: ^3.1.4
|
postcss-load-config: ^3.1.4
|
||||||
@@ -37,6 +41,7 @@ specifiers:
|
|||||||
socket.io-client: ^4.4.1
|
socket.io-client: ^4.4.1
|
||||||
svelte: ^3.47.0
|
svelte: ^3.47.0
|
||||||
svelte-check: ^2.6.0
|
svelte-check: ^2.6.0
|
||||||
|
svelte-leafletjs: ^0.8.2
|
||||||
svelte-preprocess: ^4.10.5
|
svelte-preprocess: ^4.10.5
|
||||||
svelte-tippy: ^1.3.2
|
svelte-tippy: ^1.3.2
|
||||||
swiper: ^8.1.0
|
swiper: ^8.1.0
|
||||||
@@ -44,12 +49,15 @@ specifiers:
|
|||||||
tippy.js: ^6.3.7
|
tippy.js: ^6.3.7
|
||||||
tslib: ^2.3.1
|
tslib: ^2.3.1
|
||||||
typescript: ~4.6
|
typescript: ~4.6
|
||||||
|
ua-parser-js: ^1.0.2
|
||||||
|
vite-plugin-iso-import: ^0.1.3
|
||||||
yup: ^0.32.11
|
yup: ^0.32.11
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
i18next: 21.6.16
|
i18next: 21.6.16
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@beyonk/svelte-mapbox': 8.1.4
|
||||||
'@felte/validator-yup': 1.0.3_yup@0.32.11
|
'@felte/validator-yup': 1.0.3_yup@0.32.11
|
||||||
'@fontsource/marck-script': 4.5.5
|
'@fontsource/marck-script': 4.5.5
|
||||||
'@sentry/browser': 6.19.6
|
'@sentry/browser': 6.19.6
|
||||||
@@ -61,6 +69,7 @@ devDependencies:
|
|||||||
'@types/cookie': 0.4.1
|
'@types/cookie': 0.4.1
|
||||||
'@types/js-cookie': 3.0.1
|
'@types/js-cookie': 3.0.1
|
||||||
'@types/luxon': 2.3.1
|
'@types/luxon': 2.3.1
|
||||||
|
'@types/ua-parser-js': 0.7.36
|
||||||
'@types/yup': 0.29.13
|
'@types/yup': 0.29.13
|
||||||
'@typescript-eslint/eslint-plugin': 5.19.0_f34adc8488d2e4f014fe61432d70cbf2
|
'@typescript-eslint/eslint-plugin': 5.19.0_f34adc8488d2e4f014fe61432d70cbf2
|
||||||
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
|
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
|
||||||
@@ -75,7 +84,9 @@ devDependencies:
|
|||||||
i18next-browser-languagedetector: 6.1.4
|
i18next-browser-languagedetector: 6.1.4
|
||||||
ioredis: 5.0.4
|
ioredis: 5.0.4
|
||||||
js-cookie: 3.0.1
|
js-cookie: 3.0.1
|
||||||
|
leaflet: 1.7.1
|
||||||
luxon: 2.3.1
|
luxon: 2.3.1
|
||||||
|
mapbox-gl: 2.8.1
|
||||||
node-fetch: 3.2.3
|
node-fetch: 3.2.3
|
||||||
postcss: 8.4.12
|
postcss: 8.4.12
|
||||||
postcss-load-config: 3.1.4_postcss@8.4.12
|
postcss-load-config: 3.1.4_postcss@8.4.12
|
||||||
@@ -85,6 +96,7 @@ devDependencies:
|
|||||||
socket.io-client: 4.4.1
|
socket.io-client: 4.4.1
|
||||||
svelte: 3.47.0
|
svelte: 3.47.0
|
||||||
svelte-check: 2.6.0_1b6d41eb44819e98e49be8cacdc96c52
|
svelte-check: 2.6.0_1b6d41eb44819e98e49be8cacdc96c52
|
||||||
|
svelte-leafletjs: 0.8.2
|
||||||
svelte-preprocess: 4.10.5_f6bc70e70cf1a2fde5bc22fd7000ea23
|
svelte-preprocess: 4.10.5_f6bc70e70cf1a2fde5bc22fd7000ea23
|
||||||
svelte-tippy: 1.3.2
|
svelte-tippy: 1.3.2
|
||||||
swiper: 8.1.0
|
swiper: 8.1.0
|
||||||
@@ -92,6 +104,8 @@ devDependencies:
|
|||||||
tippy.js: 6.3.7
|
tippy.js: 6.3.7
|
||||||
tslib: 2.3.1
|
tslib: 2.3.1
|
||||||
typescript: 4.6.3
|
typescript: 4.6.3
|
||||||
|
ua-parser-js: 1.0.2
|
||||||
|
vite-plugin-iso-import: 0.1.3
|
||||||
yup: 0.32.11
|
yup: 0.32.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
@@ -104,6 +118,13 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime: 0.13.9
|
regenerator-runtime: 0.13.9
|
||||||
|
|
||||||
|
/@beyonk/svelte-mapbox/8.1.4:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-H7c5i+iWReb3try5Vk2rIeIXJ6BqmO3eb8OeBntrdKAiKEA0ye7n5t4C13Ne4vvMrfqqzyHuV6kGsM0y/g+lJg==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@eslint/eslintrc/1.2.1:
|
/@eslint/eslintrc/1.2.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -197,6 +218,68 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/geojson-rewind/0.5.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-eL7fMmfTBKjrb+VFHXCGv9Ot0zc3C0U+CwXo1IrP+EPwDczLoXv34Tgq3y+2mPSFNVUXgU42ILWJTC7145KPTA==
|
||||||
|
}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
get-stream: 6.0.1
|
||||||
|
minimist: 1.2.6
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/geojson-types/1.0.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/jsonlint-lines-primitives/2.0.2:
|
||||||
|
resolution: { integrity: sha1-zlblOfg1UrWNENZy6k1vya3HsjQ= }
|
||||||
|
engines: { node: '>= 0.6' }
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/mapbox-gl-supported/2.0.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/point-geometry/0.1.0:
|
||||||
|
resolution: { integrity: sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI= }
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/tiny-sdf/2.0.5:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-OhXt2lS//WpLdkqrzo/KwB7SRD8AiNTFFzuo9n14IBupzIMa67yGItcK7I2W9D8Ghpa4T04Sw9FWsKCJG50Bxw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/unitbezier/0.0.0:
|
||||||
|
resolution: { integrity: sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4= }
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/vector-tile/1.3.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
'@mapbox/point-geometry': 0.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@mapbox/whoots-js/3.1.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
|
||||||
|
}
|
||||||
|
engines: { node: '>=6.0.0' }
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@nodelib/fs.scandir/2.1.5:
|
/@nodelib/fs.scandir/2.1.5:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -521,6 +604,13 @@ packages:
|
|||||||
'@types/node': 17.0.23
|
'@types/node': 17.0.23
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/ua-parser-js/0.7.36:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/yup/0.29.13:
|
/@types/yup/0.29.13:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -808,6 +898,17 @@ packages:
|
|||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/axios/0.25.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.14.9
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
dev: true
|
||||||
|
|
||||||
/backo2/1.0.2:
|
/backo2/1.0.2:
|
||||||
resolution: { integrity: sha1-MasayLEpNjRj41s+u2n038+6eUc= }
|
resolution: { integrity: sha1-MasayLEpNjRj41s+u2n038+6eUc= }
|
||||||
dev: true
|
dev: true
|
||||||
@@ -1042,6 +1143,10 @@ packages:
|
|||||||
engines: { node: '>= 6' }
|
engines: { node: '>= 6' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/csscolorparser/1.0.3:
|
||||||
|
resolution: { integrity: sha1-s085HupNqPPpgjHizNjfnAQfFxs= }
|
||||||
|
dev: true
|
||||||
|
|
||||||
/cssesc/3.0.0:
|
/cssesc/3.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -1274,6 +1379,13 @@ packages:
|
|||||||
domhandler: 4.3.1
|
domhandler: 4.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/earcut/2.2.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/electron-to-chromium/1.4.107:
|
/electron-to-chromium/1.4.107:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -1319,6 +1431,13 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/es-module-lexer/0.9.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/es6-promise/3.3.1:
|
/es6-promise/3.3.1:
|
||||||
resolution: { integrity: sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM= }
|
resolution: { integrity: sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM= }
|
||||||
dev: true
|
dev: true
|
||||||
@@ -1900,6 +2019,19 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/follow-redirects/1.14.9:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
|
||||||
|
}
|
||||||
|
engines: { node: '>=4.0' }
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/formdata-polyfill/4.0.10:
|
/formdata-polyfill/4.0.10:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -1943,6 +2075,28 @@ packages:
|
|||||||
resolution: { integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= }
|
resolution: { integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/geojson-vt/3.2.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/get-stream/6.0.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
|
||||||
|
}
|
||||||
|
engines: { node: '>=10' }
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/gl-matrix/3.4.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/glob-parent/5.1.2:
|
/glob-parent/5.1.2:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2023,6 +2177,13 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/grid-index/1.1.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/has-cors/1.1.0:
|
/has-cors/1.1.0:
|
||||||
resolution: { integrity: sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= }
|
resolution: { integrity: sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= }
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2071,6 +2232,13 @@ packages:
|
|||||||
'@babel/runtime': 7.17.9
|
'@babel/runtime': 7.17.9
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ieee754/1.2.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/ignore/5.2.0:
|
/ignore/5.2.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2211,6 +2379,13 @@ packages:
|
|||||||
resolution: { integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= }
|
resolution: { integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/kdbush/3.0.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/kleur/4.1.4:
|
/kleur/4.1.4:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2219,6 +2394,13 @@ packages:
|
|||||||
engines: { node: '>=6' }
|
engines: { node: '>=6' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/leaflet/1.7.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/levn/0.4.1:
|
/levn/0.4.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2320,6 +2502,37 @@ packages:
|
|||||||
sourcemap-codec: 1.4.8
|
sourcemap-codec: 1.4.8
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mapbox-gl/2.8.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-AmttsfvuWonyuOu7HcwM6Ok738A0yVYx5h3tjCAFrAsivY8SiCvF/stK2CXhSw2/6/BbZ3qe/S03J7GvisNskA==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
'@mapbox/geojson-rewind': 0.5.1
|
||||||
|
'@mapbox/geojson-types': 1.0.2
|
||||||
|
'@mapbox/jsonlint-lines-primitives': 2.0.2
|
||||||
|
'@mapbox/mapbox-gl-supported': 2.0.1
|
||||||
|
'@mapbox/point-geometry': 0.1.0
|
||||||
|
'@mapbox/tiny-sdf': 2.0.5
|
||||||
|
'@mapbox/unitbezier': 0.0.0
|
||||||
|
'@mapbox/vector-tile': 1.3.1
|
||||||
|
'@mapbox/whoots-js': 3.1.0
|
||||||
|
csscolorparser: 1.0.3
|
||||||
|
earcut: 2.2.3
|
||||||
|
geojson-vt: 3.2.1
|
||||||
|
gl-matrix: 3.4.3
|
||||||
|
grid-index: 1.1.0
|
||||||
|
minimist: 1.2.6
|
||||||
|
murmurhash-js: 1.0.0
|
||||||
|
pbf: 3.2.1
|
||||||
|
potpack: 1.0.2
|
||||||
|
quickselect: 2.0.0
|
||||||
|
rw: 1.3.3
|
||||||
|
supercluster: 7.1.5
|
||||||
|
tinyqueue: 2.0.3
|
||||||
|
vt-pbf: 3.1.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
/mdn-data/2.0.14:
|
/mdn-data/2.0.14:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2403,6 +2616,10 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/murmurhash-js/1.0.0:
|
||||||
|
resolution: { integrity: sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E= }
|
||||||
|
dev: true
|
||||||
|
|
||||||
/nanoclone/0.2.1:
|
/nanoclone/0.2.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -2561,6 +2778,17 @@ packages:
|
|||||||
engines: { node: '>=8' }
|
engines: { node: '>=8' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pbf/3.2.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==
|
||||||
|
}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
ieee754: 1.2.1
|
||||||
|
resolve-protobuf-schema: 2.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/picocolors/1.0.0:
|
/picocolors/1.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3014,6 +3242,13 @@ packages:
|
|||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/potpack/1.0.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/prelude-ls/1.2.1:
|
/prelude-ls/1.2.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3051,6 +3286,13 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/protocol-buffers-schema/3.6.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/punycode/2.1.1:
|
/punycode/2.1.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3074,6 +3316,13 @@ packages:
|
|||||||
engines: { node: '>=10' }
|
engines: { node: '>=10' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/quickselect/2.0.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/readdirp/3.6.0:
|
/readdirp/3.6.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3126,6 +3375,15 @@ packages:
|
|||||||
engines: { node: '>=4' }
|
engines: { node: '>=4' }
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/resolve-protobuf-schema/2.1.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
protocol-buffers-schema: 3.6.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/resolve/1.22.0:
|
/resolve/1.22.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3186,6 +3444,10 @@ packages:
|
|||||||
queue-microtask: 1.2.3
|
queue-microtask: 1.2.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/rw/1.3.3:
|
||||||
|
resolution: { integrity: sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q= }
|
||||||
|
dev: true
|
||||||
|
|
||||||
/sade/1.8.1:
|
/sade/1.8.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3391,6 +3653,15 @@ packages:
|
|||||||
postcss-selector-parser: 6.0.10
|
postcss-selector-parser: 6.0.10
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/supercluster/7.1.5:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
kdbush: 3.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/supports-color/7.2.0:
|
/supports-color/7.2.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3452,6 +3723,18 @@ packages:
|
|||||||
svelte: 3.47.0
|
svelte: 3.47.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svelte-leafletjs/0.8.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-TCywmwL2Dis28xKJacT6vC7OT0+tt40fbHLaavS8r9uItJOWrOM89qyeXrIMP/QbcJI/8OLfNrm6NuE3C0s8Ow==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
axios: 0.25.0
|
||||||
|
leaflet: 1.7.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
dev: true
|
||||||
|
|
||||||
/svelte-preprocess/4.10.5_f6bc70e70cf1a2fde5bc22fd7000ea23:
|
/svelte-preprocess/4.10.5_f6bc70e70cf1a2fde5bc22fd7000ea23:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3602,6 +3885,13 @@ packages:
|
|||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/tinyqueue/2.0.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tippy.js/6.3.7:
|
/tippy.js/6.3.7:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3679,6 +3969,13 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ua-parser-js/1.0.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==
|
||||||
|
}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/uri-js/4.4.1:
|
/uri-js/4.4.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3699,6 +3996,16 @@ packages:
|
|||||||
}
|
}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vite-plugin-iso-import/0.1.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-gMReA6eqfdSKMhNml0B8lT8VGHOY2FxLmq8rIJWStfuoLQItRzHKb2ntB+zNn8VWWeMe5/jtthfSxrzpgjhCMQ==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
es-module-lexer: 0.9.3
|
||||||
|
magic-string: 0.25.9
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vite/2.9.2_sass@1.50.0:
|
/vite/2.9.2_sass@1.50.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -3727,6 +4034,17 @@ packages:
|
|||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vt-pbf/3.1.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==
|
||||||
|
}
|
||||||
|
dependencies:
|
||||||
|
'@mapbox/point-geometry': 0.1.0
|
||||||
|
'@mapbox/vector-tile': 1.3.1
|
||||||
|
pbf: 3.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/web-streams-polyfill/3.2.1:
|
/web-streams-polyfill/3.2.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { browser } from '$app/env';
|
||||||
|
import { Map, Marker } from '@beyonk/svelte-mapbox';
|
||||||
|
|
||||||
|
export let lng: number;
|
||||||
|
export let lat: number;
|
||||||
|
export let markerText: string;
|
||||||
|
export let zoom = 12;
|
||||||
|
let center: [number, number];
|
||||||
|
$: center = [lng, lat];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if browser}
|
||||||
|
<Map accessToken={import.meta.env.VITE_MAPBOX_ACCESS_TOKEN} bind:center bind:zoom>
|
||||||
|
<Marker bind:lat bind:lng bind:label={markerText} />
|
||||||
|
</Map>
|
||||||
|
{/if}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<svg class="h-8 w-8 animate-spin mx-auto my-20" viewBox="3 3 18 18">
|
||||||
|
<path
|
||||||
|
class="fill-black"
|
||||||
|
d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="fill-blue-100"
|
||||||
|
d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 680 B |
@@ -3,7 +3,7 @@
|
|||||||
if (!session.authenticated) {
|
if (!session.authenticated) {
|
||||||
return {
|
return {
|
||||||
status: 302,
|
status: 302,
|
||||||
redirect: '/account/login'
|
redirect: '/account/login?returnTo=/account/settings'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -16,9 +16,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getLocalization } from '$lib/i18n';
|
import { getLocalization } from '$lib/i18n';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { UAParser } from 'ua-parser-js';
|
||||||
|
import Spinner from '$lib/Spinner.svelte';
|
||||||
|
|
||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
|
|
||||||
|
let showMap = false;
|
||||||
|
|
||||||
interface UserAccount {
|
interface UserAccount {
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -39,6 +44,9 @@
|
|||||||
newPasswordConfirm: ''
|
newPasswordConfirm: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let locationData;
|
||||||
|
let this_session;
|
||||||
|
|
||||||
let passwordChangeDataValid = false;
|
let passwordChangeDataValid = false;
|
||||||
const checkPasswords = (data: ChangePasswordData): void => {
|
const checkPasswords = (data: ChangePasswordData): void => {
|
||||||
passwordChangeDataValid =
|
passwordChangeDataValid =
|
||||||
@@ -83,19 +91,52 @@
|
|||||||
window.location.replace('/account/login');
|
window.location.replace('/account/login');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const formatDate = (date: string): string => {
|
||||||
|
const dt = DateTime.fromISO(date);
|
||||||
|
return dt.toLocaleString(DateTime.DATETIME_MED);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSessions = async () => {
|
||||||
|
const res = await fetch('/api/v1/users/sessions/list');
|
||||||
|
if (res.status === 200) {
|
||||||
|
const res2 = await fetch('/api/v1/users/session');
|
||||||
|
if (res2.status === 200) {
|
||||||
|
this_session = await res2.json();
|
||||||
|
}
|
||||||
|
return await res.json();
|
||||||
|
} else {
|
||||||
|
window.location.replace('/account/login?returnTo=/account/settings');
|
||||||
|
}
|
||||||
|
return await res.json();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFormattedUserAgent = (userAgent: string): string => {
|
||||||
|
const parser = new UAParser(userAgent);
|
||||||
|
const result = parser.getResult();
|
||||||
|
return `${result.browser.name} ${result.browser.version} (${result.os.name})`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkLocation = async (session_ip: string) => {
|
||||||
|
const res = await fetch(`/api/v1/utils/ip-lookup/${session_ip}`);
|
||||||
|
if (res.status === 200) {
|
||||||
|
locationData = await res.json();
|
||||||
|
console.log(locationData.lat, locationData.lon);
|
||||||
|
showMap = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteSession = async (session_id: string) => {
|
||||||
|
const res = await fetch(`/api/v1/users/sessions/${session_id}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
if (res.status === 200) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#await getUser()}
|
{#await getUser()}
|
||||||
<svg class="h-8 w-8 animate-spin mx-auto my-20" viewBox="3 3 18 18">
|
<Spinner />
|
||||||
<path
|
|
||||||
class="fill-black"
|
|
||||||
d="M12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5ZM3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12Z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
class="fill-blue-100"
|
|
||||||
d="M16.9497 7.05015C14.2161 4.31648 9.78392 4.31648 7.05025 7.05015C6.65973 7.44067 6.02656 7.44067 5.63604 7.05015C5.24551 6.65962 5.24551 6.02646 5.63604 5.63593C9.15076 2.12121 14.8492 2.12121 18.364 5.63593C18.7545 6.02646 18.7545 6.65962 18.364 7.05015C17.9734 7.44067 17.3403 7.44067 16.9497 7.05015Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
{:then user}
|
{:then user}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="sm:flex space-x-7 md:items-start items-center">
|
<div class="sm:flex space-x-7 md:items-start items-center">
|
||||||
@@ -146,3 +187,120 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
{#await getSessions()}
|
||||||
|
<Spinner />
|
||||||
|
{:then sessions}
|
||||||
|
<table class="min-w-full">
|
||||||
|
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{$t('overview_page.created_at')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Last seen
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Browser
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Check location
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
Delete this session
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
scope="col"
|
||||||
|
class="py-3 px-6 text-xs font-medium tracking-wider text-left text-gray-700 uppercase dark:text-gray-400"
|
||||||
|
>
|
||||||
|
This session?
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each sessions as session}
|
||||||
|
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{formatDate(session.created_at)}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{formatDate(session.last_seen)}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{getFormattedUserAgent(session.user_agent)}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
checkLocation(session.ip_address);
|
||||||
|
}}>View</button
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
deleteSession(session.id);
|
||||||
|
}}>Delete</button
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="py-4 px-6 text-sm text-gray-500 whitespace-nowrap dark:text-gray-400"
|
||||||
|
>
|
||||||
|
{#if session.id === this_session.id}
|
||||||
|
✅
|
||||||
|
{:else}
|
||||||
|
❌
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<div class="w-5/6 h-5/6 z-20 absolute top-10 pt-16 left-28" class:hidden={!showMap}>
|
||||||
|
{#if showMap}
|
||||||
|
{#await import('$lib/Map.svelte')}
|
||||||
|
<Spinner />
|
||||||
|
{:then c}
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
showMap = false;
|
||||||
|
}}
|
||||||
|
class="bg-black text-white rounded-t-lg px-1">Close</button
|
||||||
|
>
|
||||||
|
<div class="w-full h-full">
|
||||||
|
<svelte:component
|
||||||
|
this={c.default}
|
||||||
|
lat={locationData.lat}
|
||||||
|
lng={locationData.lon}
|
||||||
|
markerText={'Somewhere here was this session registered.'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<li><a href="https://redis.io/">Redis</a></li>
|
<li><a href="https://redis.io/">Redis</a></li>
|
||||||
<li><a href="https://meilisearch.com">Meilisearch</a></li>
|
<li><a href="https://meilisearch.com">Meilisearch</a></li>
|
||||||
<li><a href="https://caddyserver.com"><i>(Optional) Caddy</i></a></li>
|
<li><a href="https://caddyserver.com"><i>(Optional) Caddy</i></a></li>
|
||||||
|
<li>Linux</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h4>Frontend</h4>
|
<h4>Frontend</h4>
|
||||||
@@ -62,6 +63,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
Add the following line to your <code>/etc/hosts</code>-file, so you can visit ClassQuiz
|
||||||
|
via <code>test.com</code> (Required for the Captcha and Mapbox)
|
||||||
|
<pre><code>127.0.0.1 test.com</code></pre>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Set your config up in your .env-file. What you have to set up can you see in the
|
Set your config up in your .env-file. What you have to set up can you see in the
|
||||||
<code>classquiz/config.py</code>-file. The things you have to set are the following:
|
<code>classquiz/config.py</code>-file. The things you have to set are the following:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Requirements</h2>
|
<h2>Requirements</h2>
|
||||||
|
<h3>Software</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://docker.com">Docker</a></li>
|
<li><a href="https://docker.com">Docker</a></li>
|
||||||
<li><a href="https://git-scm.com/">Git</a></li>
|
<li><a href="https://git-scm.com/">Git</a></li>
|
||||||
@@ -38,6 +39,16 @@
|
|||||||
<a href="https://upstash.com">Upstash</a>)
|
<a href="https://upstash.com">Upstash</a>)
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<h3>3rd-Parties</h3>
|
||||||
|
<h4>Required</h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://hcaptcha.com">hCaptcha (Captcha)</a></li>
|
||||||
|
<li><a href="https://www.mapbox.com/">Mapbox (Maps)</a></li>
|
||||||
|
</ul>
|
||||||
|
<h4>Optional</h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://sentry.io">Sentry (Error-Logging)</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2>Installation</h2>
|
<h2>Installation</h2>
|
||||||
<p>At first, clone the repo:</p>
|
<p>At first, clone the repo:</p>
|
||||||
@@ -52,6 +63,15 @@
|
|||||||
<p>
|
<p>
|
||||||
You must set a valid hCaptcha-Sitekey in the <code>frontend/Dockerfile</code>.
|
You must set a valid hCaptcha-Sitekey in the <code>frontend/Dockerfile</code>.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
You'll also have to provide a valid <code>VITE_MAPBOX_ACCESS_TOKEN</code> in
|
||||||
|
<code>frontend/Dockerfile</code>. The provided token only works on the following urls:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>classquiz.mawoka.eu</code></li>
|
||||||
|
<li><code>classquiz.de</code></li>
|
||||||
|
<li><code><b>test.com</b></code></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2>Configuration</h2>
|
<h2>Configuration</h2>
|
||||||
<h3>Storage Provider</h3>
|
<h3>Storage Provider</h3>
|
||||||
@@ -113,6 +133,7 @@ services:
|
|||||||
MAIL_PORT: "587" # SMTP-Port
|
MAIL_PORT: "587" # SMTP-Port
|
||||||
REDIS: "redis://redis:6379/0?decode_responses=True" # decode_response is important!
|
REDIS: "redis://redis:6379/0?decode_responses=True" # decode_response is important!
|
||||||
SECRET_KEY: "ghfvfgjgvjgvbh" # openssl rand -hex 32
|
SECRET_KEY: "ghfvfgjgvjgvbh" # openssl rand -hex 32
|
||||||
|
MEILISEARCH_URL: "http://meilisearch:7700"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES: 30
|
ACCESS_TOKEN_EXPIRE_MINUTES: 30
|
||||||
HCAPTCHA_KEY: "" # Private hCaptcha key for verification
|
HCAPTCHA_KEY: "" # Private hCaptcha key for verification
|
||||||
STORAGE_BACKEND: "deta" # MUST BE EITHER "deta" OR "local"
|
STORAGE_BACKEND: "deta" # MUST BE EITHER "deta" OR "local"
|
||||||
@@ -151,9 +172,20 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8000:8080" # Adjust the 8000 to your needs
|
- "8000:8080" # Adjust the 8000 to your needs
|
||||||
|
|
||||||
|
meilisearch:
|
||||||
|
image: getmeili/meilisearch:latest
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
MEILI_NO_ANALYTICS: true
|
||||||
|
volumes:
|
||||||
|
- meilisearch-data:/data.ms
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
|
meilisearch-data:
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Now build and deploy:</p>
|
<p>Now build and deploy:</p>
|
||||||
<pre><code class="language-bash">docker compose build && docker compose up -d</code></pre>
|
<pre><code>docker compose build && docker compose up -d</code></pre>
|
||||||
|
<p>You'll have to create an index in Meilisearch with the following command:</p>
|
||||||
|
<pre><code>docker compose exec api python3 import_to_meili.py</code></pre>
|
||||||
|
<p><b>Enjoy! ❤️</b></p>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import adapter from '@sveltejs/adapter-node';
|
import adapter from '@sveltejs/adapter-node';
|
||||||
import preprocess from 'svelte-preprocess';
|
import preprocess from 'svelte-preprocess';
|
||||||
|
import { isoImport } from 'vite-plugin-iso-import';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
@@ -22,7 +23,8 @@ const config = {
|
|||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true
|
sourcemap: true
|
||||||
}
|
},
|
||||||
|
plugins: [isoImport()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user