diff --git a/Pipfile b/Pipfile
index 6334632..875dc00 100644
--- a/Pipfile
+++ b/Pipfile
@@ -17,6 +17,7 @@ pydantic = "*"
redis = "==4.2.0rc1"
aiohttp = "*"
gunicorn = { version = "*"}
+qrcode = "*"
[dev-packages]
diff --git a/Pipfile.lock b/Pipfile.lock
index 0f9538a..b307300 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "6667340defc4a3152bca65e1359586067a229573e833d055c86a6ef800e64c15"
+ "sha256": "dc7b78e9bce0cdb40c43f8d8bcdc80a2d4dc8d56c430808ea702ae8b0d6740fa"
},
"pipfile-spec": 6,
"requires": {
@@ -226,7 +226,7 @@
"sha256:081649da27ced5e75709a1ee542136eaba9842a0fe4c03da4fb0a3d3ed1f3c44",
"sha256:e79351e032d0b606b98d38a4b0e6e2275b31a5b85c873e587cc11b73aca026d6"
],
- "markers": "python_version >= '3.6' and python_full_version < '4.0.0'",
+ "markers": "python_version >= '3.6' and python_version < '4'",
"version": "==2.2.0"
},
"ecdsa": {
@@ -783,6 +783,13 @@
],
"version": "==6.0"
},
+ "qrcode": {
+ "hashes": [
+ "sha256:375a6ff240ca9bd41adc070428b5dfc1dcfbb0f2507f1ac848f6cded38956578"
+ ],
+ "index": "pypi",
+ "version": "==7.3.1"
+ },
"redis": {
"hashes": [
"sha256:95ff6381bc15acbb330d24896601fb8c50468003c0f30c9503afda2907225d08",
@@ -796,7 +803,7 @@
"sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17",
"sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"
],
- "markers": "python_version >= '3.6' and python_full_version < '4.0.0'",
+ "markers": "python_version >= '3.6' and python_version < '4'",
"version": "==4.8"
},
"setuptools": {
diff --git a/classquiz/__init__.py b/classquiz/__init__.py
index abc15d6..2285731 100644
--- a/classquiz/__init__.py
+++ b/classquiz/__init__.py
@@ -2,7 +2,7 @@ from fastapi import FastAPI
from classquiz.socket_server import sio
from socketio import ASGIApp
-from classquiz.routers import users, quiz
+from classquiz.routers import users, quiz, utils
from classquiz.db import database
app = FastAPI()
@@ -25,4 +25,5 @@ async def shutdown() -> None:
app.include_router(users.router, tags=["users"], prefix="/api/v1/users")
app.include_router(quiz.router, tags=["quiz"], prefix="/api/v1/quiz")
+app.include_router(utils.router, tags=["utils"], prefix="/api/v1/utils")
app.mount("/", ASGIApp(sio))
diff --git a/classquiz/routers/utils.py b/classquiz/routers/utils.py
new file mode 100644
index 0000000..201fa76
--- /dev/null
+++ b/classquiz/routers/utils.py
@@ -0,0 +1,24 @@
+import io
+
+import qrcode
+import qrcode.image.svg
+from fastapi import APIRouter
+from classquiz.config import settings
+from fastapi.responses import Response
+
+router = APIRouter()
+
+
+@router.get("/qr/{quiz_pin}")
+async def get_qr(quiz_pin: str):
+ """
+ Get QR code for quiz
+ """
+ factory = qrcode.image.svg.SvgImage
+ qr = qrcode.QRCode(image_factory=qrcode.image.svg.SvgPathImage, version=1
+ , box_size=20, border=0)
+ qr.add_data(f"{settings.root_address}/play?pin={quiz_pin}")
+ buf = io.BytesIO()
+ qr.make(fit=True)
+ qr.make_image(fill_color="black", back_color="white").save(buf, "SVG")
+ return Response(content=buf.getvalue(), media_type="image/svg+xml")
diff --git a/frontend/package.json b/frontend/package.json
index e8a39c8..8f1d78d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -41,6 +41,7 @@
"svelte": "^3.44.0",
"svelte-check": "^2.2.6",
"svelte-preprocess": "^4.10.1",
+ "sveltejs-tippy": "^3.0.0",
"tailwindcss": "^3.0.12",
"tslib": "^2.3.1",
"typescript": "~4.5.4",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 7b59078..683992b 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -29,6 +29,7 @@ specifiers:
svelte: ^3.44.0
svelte-check: ^2.2.6
svelte-preprocess: ^4.10.1
+ sveltejs-tippy: ^3.0.0
tailwindcss: ^3.0.12
tslib: ^2.3.1
typescript: ~4.5.4
@@ -63,6 +64,7 @@ devDependencies:
svelte: 3.46.4
svelte-check: 2.4.5_bb21b93d557fc716a6ae071c4dce10e1
svelte-preprocess: 4.10.4_c54fd0a3479054b5002c3dc2e70c9c9a
+ sveltejs-tippy: 3.0.0
tailwindcss: 3.0.23_autoprefixer@10.4.2
tslib: 2.3.1
typescript: 4.5.5
@@ -180,6 +182,10 @@ packages:
fastq: 1.13.0
dev: true
+ /@popperjs/core/2.11.2:
+ resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==}
+ dev: true
+
/@rollup/pluginutils/4.1.2:
resolution: {integrity: sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==}
engines: {node: '>= 8.0.0'}
@@ -2174,6 +2180,12 @@ packages:
engines: {node: '>= 8'}
dev: true
+ /sveltejs-tippy/3.0.0:
+ resolution: {integrity: sha512-LAfQikm61AeqZW1hCFWUsmGEMmhMHDvrPV0JhbT38Ell9SqBjmFaY//+YKUxaJvx6nLMxGQdlcHA1rDg2Ml8tQ==}
+ dependencies:
+ tippy.js: 6.0.3
+ dev: true
+
/table/6.8.0:
resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==}
engines: {node: '>=10.0.0'}
@@ -2229,6 +2241,12 @@ packages:
globrex: 0.1.2
dev: true
+ /tippy.js/6.0.3:
+ resolution: {integrity: sha512-buQF6HugTA4YeSA/s9xBhu0ferEAx7sRSn45G+Juh3p+Dz3vEKfxtqdg6JUnHIWDCV/r0u8Lrobs9AB4dtYcUQ==}
+ dependencies:
+ '@popperjs/core': 2.11.2
+ dev: true
+
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
diff --git a/frontend/src/lib/play/join.svelte b/frontend/src/lib/play/join.svelte
index bc8d2b8..8d9fac4 100644
--- a/frontend/src/lib/play/join.svelte
+++ b/frontend/src/lib/play/join.svelte
@@ -1,7 +1,8 @@
-
{errorMessage}
{/if} {:else if !game_started} +Pin: {quiz_data.game_pin}
Loading...
+ +{:then quizzes} + +| + Title + | ++ Created at + | ++ Question count + | ++ Play + | ++ Edit + | +
|---|---|---|---|---|
| + {quiz.title} + | ++ {formatDate(quiz.created_at)} + | ++ {quiz.questions.length} + | ++ + | ++ Edit + | +
{err}
+{/await}