✨ Added stats to homepage
This commit is contained in:
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|||||||
from socketio import ASGIApp
|
from socketio import ASGIApp
|
||||||
|
|
||||||
from classquiz.db import database
|
from classquiz.db import database
|
||||||
from classquiz.routers import users, quiz, utils
|
from classquiz.routers import users, quiz, utils, stats
|
||||||
from classquiz.socket_server import sio
|
from classquiz.socket_server import sio
|
||||||
|
|
||||||
app = FastAPI(redoc_url="", docs_url="/api/docs")
|
app = FastAPI(redoc_url="", docs_url="/api/docs")
|
||||||
@@ -26,4 +26,5 @@ async def shutdown() -> None:
|
|||||||
app.include_router(users.router, tags=["users"], prefix="/api/v1/users")
|
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(quiz.router, tags=["quiz"], prefix="/api/v1/quiz")
|
||||||
app.include_router(utils.router, tags=["utils"], prefix="/api/v1/utils")
|
app.include_router(utils.router, tags=["utils"], prefix="/api/v1/utils")
|
||||||
|
app.include_router(stats.router, tags=["stats"], prefix="/api/v1/stats")
|
||||||
app.mount("/", ASGIApp(sio))
|
app.mount("/", ASGIApp(sio))
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ router = APIRouter()
|
|||||||
@router.post("/create")
|
@router.post("/create")
|
||||||
async def create_quiz_lol(quiz_input: QuizInput, user: User = Depends(get_current_user)):
|
async def create_quiz_lol(quiz_input: QuizInput, user: User = Depends(get_current_user)):
|
||||||
quiz = Quiz(**quiz_input.dict(), user_id=user.id, id=uuid.uuid4())
|
quiz = Quiz(**quiz_input.dict(), user_id=user.id, id=uuid.uuid4())
|
||||||
|
await redis.delete("global_quiz_count")
|
||||||
return await quiz.save()
|
return await quiz.save()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Response
|
||||||
|
from fastapi.background import BackgroundTasks
|
||||||
|
from fastapi.responses import JSONResponse, RedirectResponse
|
||||||
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from classquiz.auth import *
|
||||||
|
from classquiz.config import redis
|
||||||
|
from classquiz.db.models import *
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/quizzes")
|
||||||
|
async def get_quiz_count() -> int:
|
||||||
|
redis_res = await redis.get("global_quiz_count")
|
||||||
|
if redis_res is None:
|
||||||
|
quiz_res = await Quiz.objects.count()
|
||||||
|
await redis.set("global_quiz_count", quiz_res, ex=3600)
|
||||||
|
return quiz_res
|
||||||
|
else:
|
||||||
|
return int(redis_res)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/users")
|
||||||
|
async def get_user_count() -> int:
|
||||||
|
redis_res = await redis.get("global_user_count")
|
||||||
|
if redis_res is None:
|
||||||
|
quiz_res = await User.objects.count()
|
||||||
|
await redis.set("global_user_count", quiz_res, ex=3600)
|
||||||
|
return quiz_res
|
||||||
|
else:
|
||||||
|
return int(redis_res)
|
||||||
|
|
||||||
|
|
||||||
|
class CombinedOutput(BaseModel):
|
||||||
|
quiz_count: int
|
||||||
|
user_count: int
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/combined")
|
||||||
|
async def get_combined_count() -> CombinedOutput:
|
||||||
|
user_count = None
|
||||||
|
quiz_count = None
|
||||||
|
redis_res = await redis.get("global_user_count")
|
||||||
|
if redis_res is None:
|
||||||
|
quiz_res = await User.objects.count()
|
||||||
|
await redis.set("global_user_count", quiz_res, ex=3600)
|
||||||
|
user_count = quiz_res
|
||||||
|
else:
|
||||||
|
user_count = int(redis_res)
|
||||||
|
|
||||||
|
redis_res = await redis.get("global_quiz_count")
|
||||||
|
if redis_res is None:
|
||||||
|
quiz_res = await Quiz.objects.count()
|
||||||
|
await redis.set("global_quiz_count", quiz_res, ex=3600)
|
||||||
|
quiz_count = quiz_res
|
||||||
|
else:
|
||||||
|
quiz_count = int(redis_res)
|
||||||
|
|
||||||
|
return CombinedOutput(quiz_count=quiz_count, user_count=user_count)
|
||||||
@@ -36,6 +36,7 @@ async def create_user(user: route_user, background_task: BackgroundTasks) -> Use
|
|||||||
return JSONResponse({"details": "Username mustn't be 32 characters long"}, 400)
|
return JSONResponse({"details": "Username mustn't be 32 characters long"}, 400)
|
||||||
await user.save()
|
await user.save()
|
||||||
background_task.add_task(send_register_email, email=user.email)
|
background_task.add_task(send_register_email, email=user.email)
|
||||||
|
await redis.delete("global_user_count")
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,49 @@
|
|||||||
<script lang="ts">
|
<script lang='ts'>
|
||||||
import { navbarVisible } from '$lib/stores';
|
import { navbarVisible } from '$lib/stores';
|
||||||
|
|
||||||
navbarVisible.set(true);
|
navbarVisible.set(true);
|
||||||
|
|
||||||
|
interface StatsData {
|
||||||
|
quiz_count: number;
|
||||||
|
user_count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStats = async () => {
|
||||||
|
const response = await fetch('/api/v1/stats/combined');
|
||||||
|
return await response.json();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>ClassQuiz - Home</title>
|
<title>ClassQuiz - Home</title>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name='description'
|
||||||
content="ClassQuiz is a quiz app like KAHOOT! for students, which is open source and free to use."
|
content='ClassQuiz is a quiz app like KAHOOT! for students, which is open source and free to use.'
|
||||||
/>
|
/>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="pt-12 text-center">
|
<div class='pt-12 text-center'>
|
||||||
<h1 class="sm:text-8xl text-6xl mt-6 marck-script">ClassQuiz</h1>
|
<h1 class='sm:text-8xl text-6xl mt-6 marck-script'>ClassQuiz</h1>
|
||||||
<p class="text-xl mt-4">The open-source quiz-platform!</p>
|
<p class='text-xl mt-4'>The open-source quiz-platform!</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section id="features">
|
|
||||||
<div class="text-center pt-48 snap-y">
|
<section id='stats'>
|
||||||
<h1 class="sm:text-6xl text-4xl">Features</h1>
|
<div class='text-center pt-48 snap-y'>
|
||||||
<p class="text-xl pt-4">
|
<h1 class='sm:text-6xl text-4xl'>Stats</h1>
|
||||||
|
<p class='text-xl pt-4'>
|
||||||
|
{#await getStats() then stats}
|
||||||
|
There are already <span class='underline'>{stats.user_count}</span> users and <span class='underline'>{stats.quiz_count}</span> quizzes on ClassQuiz.
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id='features'>
|
||||||
|
<div class='text-center pt-24 snap-y'>
|
||||||
|
<h1 class='sm:text-6xl text-4xl'>Features</h1>
|
||||||
|
<p class='text-xl pt-4'>
|
||||||
ClassQuiz is a quiz-platform that allows you to create and manage quizzes.
|
ClassQuiz is a quiz-platform that allows you to create and manage quizzes.
|
||||||
<br />
|
<br />
|
||||||
The main feature is a KAHOOT!-import function that allows you to import quizzes from KAHOOT!-quizzes.
|
The main feature is a KAHOOT!-import function that allows you to import quizzes from KAHOOT!-quizzes.
|
||||||
|
|||||||
Reference in New Issue
Block a user