added basic functionality
This commit is contained in:
@@ -30,14 +30,29 @@ from .utils import (
|
|||||||
get_token,
|
get_token,
|
||||||
get_unlocked_decks,
|
get_unlocked_decks,
|
||||||
is_deck_unlocked,
|
is_deck_unlocked,
|
||||||
|
retrieve_token,
|
||||||
serialize_token,
|
serialize_token,
|
||||||
update_token,
|
update_token,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
main = Blueprint('main', __name__)
|
main = Blueprint('main', __name__)
|
||||||
slidev_deck_pattern = re.compile(r"^\/slides\/[^\/]+\/\d*(?:\?.*)?$")
|
slidev_deck_pattern = re.compile(r"^\/slides\/[^\/]+\/\d*(?:\?.*)?$")
|
||||||
slidev_all_pattern = re.compile(r"^\/slides\/[^\/]+(?:\/presenter)?\/\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
|
@main.after_request
|
||||||
def inject_confused_button(response):
|
def inject_confused_button(response):
|
||||||
if True:
|
if True:
|
||||||
@@ -81,15 +96,15 @@ def inject_confused_button(response):
|
|||||||
response.set_data(body)
|
response.set_data(body)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@main.route('/')
|
@main.route('/')
|
||||||
def index():
|
def index():
|
||||||
token = get_token()
|
token = get_token()
|
||||||
if not token:
|
if not token:
|
||||||
token = generate_token()
|
abort(500)
|
||||||
resp = make_response(render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name))
|
else:
|
||||||
resp.set_cookie('access_token', serialize_token(token), httponly=True)
|
return render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name)
|
||||||
return resp
|
|
||||||
|
|
||||||
@main.route('/login', methods=['POST', 'GET'])
|
@main.route('/login', methods=['POST', 'GET'])
|
||||||
def login():
|
def login():
|
||||||
@@ -127,12 +142,34 @@ def access():
|
|||||||
return redirect('/')
|
return redirect('/')
|
||||||
return render_template('index.html', error="Invalid password.", decks=get_unlocked_decks(token))
|
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():
|
def confused():
|
||||||
resp = jsonify(success=True)
|
resp = jsonify(success=True)
|
||||||
return resp
|
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>/')
|
||||||
@main.route('/slides/<deck>/<path:path>')
|
@main.route('/slides/<deck>/<path:path>')
|
||||||
|
|||||||
@@ -36,7 +36,32 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="bg-surface border-b border-border shadow-sm">
|
<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="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>
|
<div class="text-lg font-semibold">GRNVS Tutorium</div>
|
||||||
<a href="/admin">
|
<a href="/admin">
|
||||||
<button class="bg-primary hover:bg-blue-700 text-white px-4 py-2 rounded-md transition">
|
<button class="bg-primary hover:bg-blue-700 text-white px-4 py-2 rounded-md transition">
|
||||||
@@ -104,5 +129,19 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import Flask, request
|
from flask import Flask, request, session
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from itsdangerous import BadSignature, URLSafeSerializer
|
from itsdangerous import BadSignature, URLSafeSerializer
|
||||||
from xkcdpass import xkcd_password
|
from xkcdpass import xkcd_password
|
||||||
@@ -28,6 +28,7 @@ def get_available_decks(app: Flask):
|
|||||||
def generate_username() -> str:
|
def generate_username() -> str:
|
||||||
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=3, delimiter="-"))
|
return cast(str, xkcd_password.generate_xkcdpassword(wordlist=words, numwords=3, delimiter="-"))
|
||||||
|
|
||||||
|
|
||||||
def generate_password() -> 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=5, delimiter="-"))
|
||||||
|
|
||||||
@@ -60,6 +61,10 @@ def get_token() -> (Token | None):
|
|||||||
except BadSignature:
|
except BadSignature:
|
||||||
return None
|
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)):
|
def get_unlocked_decks(token: (Token|None)):
|
||||||
if token is None:
|
if token is None:
|
||||||
return []
|
return []
|
||||||
|
|||||||
Reference in New Issue
Block a user