added basic functionality
This commit is contained in:
@@ -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:
|
||||
@@ -86,10 +101,10 @@ def inject_confused_button(response):
|
||||
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>')
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 []
|
||||
|
||||
Reference in New Issue
Block a user