fixed website
This commit is contained in:
@@ -45,7 +45,7 @@ class Password(db.Model):
|
||||
value : Mapped[str] = mapped_column(String(60))
|
||||
expires_at: Mapped[Optional[datetime]] = mapped_column(UTCDateTime()) # Optional expiration
|
||||
|
||||
decks : Mapped[List[Deck]] = relationship("Deck", secondary=deck_password, back_populates='passwords', cascade="all")
|
||||
decks : Mapped[List[Deck]] = relationship("Deck", secondary=deck_password, back_populates='passwords')
|
||||
|
||||
def __init__(self, value: str, expires_at: datetime|None) -> None:
|
||||
self.value = value
|
||||
@@ -67,8 +67,8 @@ class Deck(db.Model):
|
||||
deck : Mapped[str] = mapped_column(String(60), unique=True, nullable=False)
|
||||
description : Mapped[str] = mapped_column(String(60))
|
||||
|
||||
passwords : Mapped[List[Password]] = relationship("Password", secondary=deck_password, back_populates='decks', cascade="all")
|
||||
tokens : Mapped[List[Token]] = relationship("Token", secondary=deck_token, back_populates='decks', cascade="all")
|
||||
passwords : Mapped[List[Password]] = relationship("Password", secondary=deck_password, back_populates='decks')
|
||||
tokens : Mapped[List[Token]] = relationship("Token", secondary=deck_token, back_populates='decks')
|
||||
|
||||
def __init__(self, name: str, deck: str, description: str = "") -> None:
|
||||
self.name = name
|
||||
@@ -82,7 +82,7 @@ class Token(db.Model):
|
||||
__tablename__ = "token"
|
||||
id : Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(60), unique=True, nullable=False)
|
||||
decks : Mapped[List[Deck]]= relationship("Deck", secondary=deck_token, back_populates='tokens', cascade="all")
|
||||
decks : Mapped[List[Deck]]= relationship("Deck", secondary=deck_token, back_populates='tokens')
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
@@ -215,7 +215,8 @@ def serve_deck(deck, path='index.html'):
|
||||
def admin():
|
||||
deck_form = DeckForm()
|
||||
password_form = PasswordForm()
|
||||
password_form.value.data = generate_password()
|
||||
if request.method == 'GET':
|
||||
password_form.value.data = generate_password()
|
||||
deck_form.deck.choices = get_available_decks(current_app)
|
||||
decks = db.session.scalars(db.select(Deck).order_by(Deck.name)).all()
|
||||
passwords = db.session.scalars(db.select(Password)).all()
|
||||
|
||||
@@ -33,12 +33,29 @@
|
||||
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-background text-text min-h-screen font-sans">
|
||||
|
||||
<div class="container mx-auto px-6 py-10 space-y-12">
|
||||
|
||||
<!-- Admin Title -->
|
||||
<h1 class="text-3xl font-bold text-center mb-8">Deck & Password Admin</h1>
|
||||
|
||||
<nav class="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center x-auto p-4">
|
||||
<a href="{{url_for('main.index')}}" class="flex items-center space-x-3 rtl:space-x-reverse">
|
||||
<span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Tutortool</span>
|
||||
</a>
|
||||
<div class="w-auto" id="navbar-default">
|
||||
<ul class="font-medium p-0 py-2 border border-gray-100 rounded-lg bg-gray-50 flex flex-row space-x-8 rtl:space-x-reverse mt-0 border-0 bg-white dark:bg-gray-800 dark:bg-gray-900 dark:border-gray-700 justify-between">
|
||||
<li>
|
||||
<a href="{{url_for('main.admin')}}" class="rounded-sm bg-transparent text-blue-700 p-0 dark:text-blue-500" aria-current="page">Deck Admin</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.banner')}}" class="text-grey-900 dark:hover:text-blue-500 hover:text-blue-700 rounded-sm bg-transparent dark:text-white">Banner</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.confused_notifications')}}" class="text-grey-900 dark:hover:text-blue-500 hover:text-blue-700 rounded-sm bg-transparent p-0 dark:text-white">Confused</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mx-auto px-6 py-10 space-y-12">
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-10">
|
||||
|
||||
<!-- Deck Form + Decks -->
|
||||
|
||||
@@ -32,12 +32,36 @@
|
||||
|
||||
<body class="bg-background text-text min-h-screen font-sans">
|
||||
|
||||
<!-- Header -->
|
||||
<header class="bg-surface border-b border-border shadow-sm">
|
||||
<div class="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||
<div class="text-lg font-semibold">Info Banner</div>
|
||||
<nav class="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
<a href="{{url_for('main.index')}}" class="flex items-center space-x-3 rtl:space-x-reverse">
|
||||
<span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Tutortool</span>
|
||||
</a>
|
||||
<div class="hidden w-full md:block md:w-auto" id="navbar-default">
|
||||
<ul class="font-medium flex flex-col justify-between md:justify-evenly p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
|
||||
<li>
|
||||
<a href="{{url_for('main.admin')}}"
|
||||
class="block py-2 px-3 text-gray-900 rounded-sm hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">
|
||||
Deck Admin
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.banner')}}"
|
||||
class="block py-2 px-3 text-white bg-blue-700 rounded-sm md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500"
|
||||
aria-current="page">
|
||||
Banner
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.confused_notifications')}}"
|
||||
class="block py-2 px-3 text-gray-900 rounded-sm hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">
|
||||
Confused
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="max-w-5xl mx-auto px-6 py-10 space-y-12">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Live Confusion Alerts</title>
|
||||
@@ -8,11 +8,61 @@
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.1/socket.io.min.js"></script>
|
||||
|
||||
<!-- Tailwind Config (Dark Mode + Theme Colors) -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: '#121418', // dark slate with blue/gray tone
|
||||
surface: '#1e2127', // a bit lighter for containers/cards
|
||||
border: '#2a2d34', // visible but subtle borders
|
||||
primary: '#4f8cff', // soft blue that pops but is not neon
|
||||
text: '#e4e4e7', // light gray for high contrast
|
||||
muted: '#a0a0ad', // for subdued text
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-100 min-h-screen">
|
||||
<body class="bg-background min-h-screen">
|
||||
<nav class="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
<a href="{{url_for('main.index')}}" class="flex items-center space-x-3 rtl:space-x-reverse">
|
||||
<span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Tutortool</span>
|
||||
</a>
|
||||
<div class="hidden w-full md:block md:w-auto" id="navbar-default">
|
||||
<ul class="font-medium flex flex-col justify-between md:justify-evenly p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
|
||||
<li>
|
||||
<a href="{{url_for('main.admin')}}"
|
||||
class="block py-2 px-3 text-gray-900 rounded-sm hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">
|
||||
Deck Admin
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.banner')}}"
|
||||
class="block py-2 px-3 text-gray-900 rounded-sm hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">
|
||||
Banner
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{url_for('main.confused_notifications')}}"
|
||||
class="block py-2 px-3 text-white bg-blue-700 rounded-sm md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500"
|
||||
aria-current="page">
|
||||
Confused
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="max-w-3xl mx-auto mt-12 px-4">
|
||||
<h1 class="text-3xl font-bold mb-6">Live Confusion Alerts</h1>
|
||||
<h1 class="text-3xl font-bold mb-6 dark:text-white">Live Confusion Alerts</h1>
|
||||
<div id="notif-list" class="space-y-4 text-gray-700">
|
||||
<p class="italic text-gray-500">Waiting for students to click “I’m confused…”</p>
|
||||
</div>
|
||||
|
||||
@@ -41,25 +41,34 @@
|
||||
|
||||
<!-- Header -->
|
||||
<header class="bg-surface border-b border-border shadow-sm">
|
||||
<div class="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between relative">
|
||||
<!-- Editable Username Form -->
|
||||
<form method="POST" action="/retrieve-token" class="flex items-center space-x-2">
|
||||
<input
|
||||
type="text"
|
||||
name="user_name"
|
||||
value="{{ user_name }}"
|
||||
class="bg-transparent text-muted text-sm font-medium px-2 py-1 rounded-md border border-transparent focus:border-primary focus:outline-none focus:bg-background"
|
||||
size = "{{ user_name|length }}"
|
||||
disabled
|
||||
id="usernameInput"
|
||||
/>
|
||||
<div
|
||||
class="max-w-7xl mx-auto px-6 py-4
|
||||
grid grid-cols-2 items-center gap-4"
|
||||
>
|
||||
<!-- 1) form in column 1 -->
|
||||
<form
|
||||
method="POST"
|
||||
action="/retrieve-token"
|
||||
class="relative z-10 flex flex-col space-y-2"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
name="user_name"
|
||||
value="{{ user_name }}"
|
||||
class="bg-transparent text-muted text-sm font-medium w-auto min-w-max whitespace-nowrap px-2 py-1 rounded-md border border-transparent focus:border-primary focus:outline-none focus:bg-background"
|
||||
size="{{ user_name|length }}"
|
||||
disabled
|
||||
id="usernameInput"
|
||||
/>
|
||||
|
||||
<div class="w-auto min-w-max whitespace-nowrap">
|
||||
<button
|
||||
type="button"
|
||||
onclick="enableUsernameEdit()"
|
||||
class="text-sm text-white bg-primary px-3 py-1 rounded-md hover:bg-blue-700"
|
||||
id="editBtn"
|
||||
>
|
||||
Username ändern
|
||||
Username ändern
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
@@ -68,18 +77,24 @@
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</form>
|
||||
<div class="absolute inset-0 flex items-center justify-center pointer-events-none">GRNVS Tutorium</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 2) admin button in column 2 -->
|
||||
<div class="flex justify-end">
|
||||
<a href="/admin">
|
||||
<button class="bg-primary hover:bg-blue-700 text-white px-3 py-1 rounded-md transition">
|
||||
Admin
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="max-w-5xl mx-auto px-6 py-10 space-y-12">
|
||||
<h3 class="text-3xl font-bold text-center mb-8">GRNVS Tutorium SS 25</h3>
|
||||
|
||||
|
||||
{% if active_banner %}
|
||||
<section class="flex justify-center">
|
||||
|
||||
@@ -30,7 +30,7 @@ def generate_username() -> str:
|
||||
|
||||
|
||||
def generate_password() -> str:
|
||||
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=5, delimiter="-"))
|
||||
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=2, delimiter="-"))
|
||||
|
||||
def generate_token() -> Token:
|
||||
max_tries = 100
|
||||
|
||||
Reference in New Issue
Block a user