added basic functionality

This commit is contained in:
2025-04-29 18:57:59 +02:00
parent daa64e62ac
commit 7f5d64b45b
3 changed files with 89 additions and 8 deletions

View File

@@ -30,14 +30,29 @@ from .utils import (
get_token,
get_unlocked_decks,
is_deck_unlocked,
retrieve_token,
serialize_token,
update_token,
)
main = Blueprint('main', __name__)
slidev_deck_pattern = re.compile(r"^\/slides\/[^\/]+\/\d*(?:\?.*)?$")
slidev_all_pattern = re.compile(r"^\/slides\/[^\/]+(?:\/presenter)?\/\d+(?:\?.*)?$")
@main.before_request
def ensure_cookie():
token = get_token()
if token:
return
else:
token = generate_token()
resp = make_response(redirect(request.url))
resp.set_cookie('access_token', serialize_token(token), httponly=True)
return resp
@main.after_request
def inject_confused_button(response):
if True:
@@ -81,15 +96,15 @@ def inject_confused_button(response):
response.set_data(body)
return response
@main.route('/')
def index():
token = get_token()
if not token:
token = generate_token()
resp = make_response(render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name))
resp.set_cookie('access_token', serialize_token(token), httponly=True)
return resp
abort(500)
else:
return render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name)
@main.route('/login', methods=['POST', 'GET'])
def login():
@@ -127,12 +142,34 @@ def access():
return redirect('/')
return render_template('index.html', error="Invalid password.", decks=get_unlocked_decks(token))
@main.route('/confused', methods=['POST'])
@main.route('/access/<access_code>', methods=['GET'])
def access_link(access_code: str):
password = db.session.execute(db.select(Password).where(Password.value == access_code)).scalar()
assert isinstance(password, Password|None)
token = get_token()
if password is not None and not password.is_expired():
update_token(password.decks)
return redirect('/')
return render_template('index.html', error="Invalid password.", decks=get_unlocked_decks(token))
@main.route('/confused', methods=['POST'])
def confused():
resp = jsonify(success=True)
return resp
@main.route('/retrieve-token', methods=['POST'])
def set_username_token():
new_username : str = request.form.get("user_name", "").strip()
resp = make_response(redirect('/'))
if new_username:
token = retrieve_token(new_username)
if token:
resp.set_cookie('access_token', serialize_token(token), httponly=True)
return resp
@main.route('/slides/<deck>/')
@main.route('/slides/<deck>/<path:path>')

View File

@@ -36,7 +36,32 @@
<!-- 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-sm text-muted font-medium">{{ user_name }}</div>
<!-- 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"
readonly
id="usernameInput"
/>
<button
type="button"
onclick="enableUsernameEdit()"
class="text-sm text-primary hover:underline"
id="editBtn"
>
Edit
</button>
<button
type="submit"
class="hidden text-sm text-white bg-primary px-3 py-1 rounded-md hover:bg-blue-700"
id="saveBtn"
>
Save
</button>
</form>
<div class="text-lg font-semibold">GRNVS Tutorium</div>
<a href="/admin">
<button class="bg-primary hover:bg-blue-700 text-white px-4 py-2 rounded-md transition">
@@ -104,5 +129,19 @@
</main>
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
<script>
function enableUsernameEdit() {
const input = document.getElementById('usernameInput');
const editBtn = document.getElementById('editBtn');
const saveBtn = document.getElementById('saveBtn');
input.removeAttribute('readonly');
input.classList.add('border-border');
input.focus();
editBtn.classList.add('hidden');
saveBtn.classList.remove('hidden');
}
</script>
</body>
</html>

View File

@@ -1,6 +1,6 @@
import os
from flask import Flask, request
from flask import Flask, request, session
from typing import cast
from itsdangerous import BadSignature, URLSafeSerializer
from xkcdpass import xkcd_password
@@ -28,6 +28,7 @@ def get_available_decks(app: Flask):
def generate_username() -> str:
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=3, delimiter="-"))
def generate_password() -> str:
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=5, delimiter="-"))
@@ -60,6 +61,10 @@ def get_token() -> (Token | None):
except BadSignature:
return None
def retrieve_token(username : str):
return db.session.execute(db.select(Token).filter_by(name=username)).scalar_one_or_none()
def get_unlocked_decks(token: (Token|None)):
if token is None:
return []