Refactor handling of active user

This commit is contained in:
2024-02-16 17:59:43 +01:00
parent ab8def6b4f
commit ea34413b3c
5 changed files with 163 additions and 148 deletions

View File

@ -18,11 +18,13 @@ db.init_app(app)
# - Move guessed place to leftmost column and display actual finishing position of driver instead
# - Show coming race in table, to give better feedback once a user has locked in a guess
# - Only allow guess entering in user-specific page
# - Persist chosen user across race/season pages
# - Remove whitespace from usernames
# - Sortable list to enter full race results (need 7 positions to calculate points) => remove from race page
# - Make the season card grid left-aligned? So e.g. 2 cards are not spread over the whole screen with large gaps?
# - Choose "place to guess" late before the race?
# - Timer until season picks lock + next race timer
# - A lot of validation (esp. in the model), each input should be checked...
# Statistics page
# - Auto calculate points
@ -69,39 +71,31 @@ def guessraceresult():
@app.route("/race/<username>")
def guessuserraceresults(username):
users: List[User] = User.query.all()
activeuser: User | None = User.query.filter_by(name=username).first() # "Everyone" should yield None
raceresults: List[RaceResult] = RaceResult.query.all()[::-1]
drivers: List[Driver] = Driver.query.all()
# Select User
chosenusers = users
if username != "Everyone":
chosenusers = [user for user in users if user.name == username]
# chosenusers = users
# if username != "Everyone":
# chosenusers = [user for user in users if user.name == username]
pastguesses = dict() # The guesses for which raceresults exist
nextguesses = dict() # The guesses that are still open for modification
raceresult: RaceResult
for raceresult in raceresults:
pastguesses[raceresult.race_id] = dict()
guess: RaceGuess
guesses = dict()
for guess in RaceGuess.query.all():
if guess.race_id in pastguesses:
pastguesses[guess.race_id][guess.user_id] = guess
else:
nextguesses[guess.user_id] = guess
if guess.race_id not in guesses:
guesses[guess.race_id] = dict()
# TODO: Getting by ID might be stupid, get by date instead?
nextid = raceresults[0].race_id + 1 if len(raceresults) > 0 else 1
nextrace: Race = Race.query.filter_by(id=nextid).first()
guesses[guess.race_id][guess.user_id] = guess
# nextid = raceresults[0].race_id + 1 if len(raceresults) > 0 else 1
# nextrace: Race = Race.query.filter_by(id=nextid).first()
return render_template("race.jinja",
users=users,
drivers=drivers,
raceresults=raceresults,
pastguesses=pastguesses,
currentselection=nextguesses,
nextrace=nextrace,
chosenusername=username,
chosenusers=chosenusers)
guesses=guesses,
activeuser=activeuser)
@app.route("/guessrace/<raceid>/<username>", methods=["POST"])
@ -131,28 +125,28 @@ def guessrace(raceid, username):
return redirect("/race")
@app.route("/enterresult/<raceid>", methods=["POST"])
def enterresult(raceid):
pxx = request.form.get("pxxselect")
dnf = request.form.get("dnfselect")
if pxx is None or dnf is None:
return redirect("/race")
raceresult: RaceResult | None = RaceResult.query.filter_by(race_id=raceid).first()
if raceresult is not None:
print("RaceResult already exists!")
return redirect("/race")
raceresult = RaceResult()
raceresult.race_id = raceid
raceresult.pxx_id = pxx
raceresult.dnf_id = dnf
db.session.add(raceresult)
db.session.commit()
return redirect("/race")
# @app.route("/enterresult/<raceid>", methods=["POST"])
# def enterresult(raceid):
# pxx = request.form.get("pxxselect")
# dnf = request.form.get("dnfselect")
#
# if pxx is None or dnf is None:
# return redirect("/race")
#
# raceresult: RaceResult | None = RaceResult.query.filter_by(race_id=raceid).first()
#
# if raceresult is not None:
# print("RaceResult already exists!")
# return redirect("/race")
#
# raceresult = RaceResult()
# raceresult.race_id = raceid
# raceresult.pxx_id = pxx
# raceresult.dnf_id = dnf
# db.session.add(raceresult)
# db.session.commit()
#
# return redirect("/race")
@app.route("/season")
@ -163,20 +157,17 @@ def guessseasonresults():
@app.route("/season/<username>")
def guessuserseasonresults(username):
users: List[User] = User.query.all()
activeuser: User | None = User.query.filter_by(name=username).first()
teams: List[Team] = Team.query.all()
drivers: List[Driver] = Driver.query.all()
# Remove NONE driver
drivers = [driver for driver in drivers if driver.name != "NONE"]
# Select User
chosenusers = users
if username != "Everyone":
chosenusers = [user for user in users if user.name == username]
seasonguesses = dict()
guesses = dict()
guess: SeasonGuess
for guess in SeasonGuess.query.all():
seasonguesses[guess.user_id] = guess
guesses[guess.user_id] = guess
driverpairs = dict()
team: Team
@ -191,9 +182,8 @@ def guessuserseasonresults(username):
teams=teams,
drivers=drivers,
driverpairs=driverpairs,
currentselection=seasonguesses,
chosenusername=username,
chosenusers=chosenusers)
guesses=guesses,
activeuser=activeuser)
@app.route("/guessseason/<username>", methods=["POST"])
@ -257,6 +247,11 @@ def guessseason(username):
return redirect("/season")
@app.route("/enter")
def enterraceresult():
return render_template("enter.jinja")
@app.route("/users")
def manageusers():
users = User.query.all()

View File

@ -1,12 +1,6 @@
<!DOCTYPE html>
<html lang="en">
{# Easy nav-bar entries. When a page sets the active_page variable, the current entry will be underlined #}
{% macro nav_selector(page='', text='') %}
<a class="nav-link text-nowrap" href="{{ page }}">{% if active_page == page %}<u>{% endif %} {{ text }}
{% if active_page == page %}</u>{% endif %}</a>
{% endmacro %}
{# Simple driver dropdown. Requires list of drivers. #}
{% macro driver_select(name='', label='') %}
<div class="form-floating">
@ -83,6 +77,12 @@
</div>
{% endmacro %}
{# Easy nav-bar entries. When a page sets the active_page variable, the current entry will be underlined #}
{% macro nav_selector(page='', text='') %}
<a class="nav-link text-nowrap" href="{{ page }}">{% if active_page == page %}<u>{% endif %} {{ text }}
{% if active_page == page %}</u>{% endif %}</a>
{% endmacro %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -119,8 +119,8 @@
<div class="collapse navbar-collapse" id="navbarCollapse">
<div class="navbar-nav me-2">
{{ nav_selector("/race/" ~ active_user, "Race Picks") }}
{{ nav_selector("/season/" ~ active_user, "Season Picks") }}
{{ nav_selector("/race/" ~ active_user.name | default("Everyone"), "Race Picks") }}
{{ nav_selector("/season/" ~ active_user.name | default("Everyone"), "Season Picks") }}
{{ nav_selector("/graphs", "Statistics") }}
{{ nav_selector("/rules", "Rules") }}
</div>

View File

@ -1,7 +1,7 @@
{% extends 'base.jinja' %}
{% set active_page = "/race/" ~ chosenusername %}
{% set active_user = chosenusername %}
{% set active_page = "/race/" ~ activeuser.name | default("Everyone") %}
{% set active_user = activeuser %}
{% block title %}Formula 10 - Race{% endblock title %}
@ -9,7 +9,7 @@
<div class="dropdown">
<button class="btn btn-outline-danger dropdown-toggle" type="button" data-bs-toggle="dropdown"
aria-expanded="false">
{{ chosenusername }}
{% if activeuser is not none %}{{ activeuser.name }}{% else %}Everyone{% endif %}
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/race/Everyone">Everyone</a></li>
@ -30,8 +30,10 @@
<tr>
<th scope="col" rowspan="2" class="text-center" style="width: 200px;">Race</th>
{% if chosenusers | length > 0 %}
<th scope="col" colspan="{{ chosenusers | length }}" class="text-center">Call</th>
{% if activeuser is none %}
<th scope="col" colspan="{{ users | length }}" class="text-center">Call</th>
{% else %}
<th scope="col" class="text-center">Call</th>
{% endif %}
<th scope="col" rowspan="2" class="text-center" style="width: 200px;">Result</th>
@ -44,83 +46,95 @@
<tr>
<td>&nbsp;</td>
{% for user in chosenusers %}
<td class="text-center text-nowrap" style="min-width: 100px;">{{ user.name }}</td>
{% endfor %}
{% if activeuser is none %}
{% for user in users %}
<td class="text-center text-nowrap" style="min-width: 100px;">{{ user.name }}</td>
{% endfor %}
{% else %}
<td class="text-center text-nowrap" style="min-width: 100px;">{{ activeuser.name }}</td>
{% endif %}
<td>&nbsp;</td>
</tr>
{# Next Race Guess #}
{% if nextrace is not none %}
<tr class="table-light">
<td class="text-nowrap"><span class="fw-bold">{{ nextrace.id }}:</span> {{ nextrace.grandprix }}</td>
{# {% if nextrace is not none %}#}
{# <tr class="table-light">#}
{# <td class="text-nowrap">#}
{# <span class="fw-bold">{{ nextrace.id }}:</span> {{ nextrace.grandprix }}<br>#}
{# <small><span class="fw-bold">Guess:</span> P{{ nextrace.pxx }}</small>#}
{# </td>#}
{##}
{# {% for user in users %}#}
{# <td>#}
{# <form action="/guessrace/{{ nextrace.id }}/{{ user.name }}" method="post">#}
{# Driver PXX Select #}
{# {{ driver_select_with_preselect(currentselection.get(user.name).pxx.abbr if user.name in currentselection else "",#}
{# "pxxselect", "P" ~ nextrace.pxx ~ ":") }}#}
{##}
{# Driver DNF Select #}
{# <div class="mt-2">#}
{# {{ driver_select_with_preselect(currentselection.get(user.name).dnf.abbr if user.name in currentselection else "",#}
{# "dnfselect", "DNF:") }}#}
{# </div>#}
{##}
{# <input type="submit" class="btn btn-danger mt-2 w-100" value="Save">#}
{# </form>#}
{# </td>#}
{# {% endfor %}#}
{##}
{# Enter Race Result #}
{# <td>&nbsp;</td>#}
{# <td>#}
{# <form action="/enterresult/{{ nextrace.id }}" method="post">#}
{# Driver PXX Select#}
{# {{ driver_select("pxxselect", "P" ~ nextrace.pxx ~ ":") }}#}
{##}
{# Driver DNF Select#}
{# <div class="mt-2">#}
{# {{ driver_select("dnfselect", "DNF:") }}#}
{# </div>#}
{##}
{# <input type="submit" class="btn btn-danger mt-2 w-100" value="Save">#}
{# </form>#}
{# </td>#}
{# </tr>#}
{# {% endif %}#}
{% for user in chosenusers %}
<td>
<form action="/guessrace/{{ nextrace.id }}/{{ user.name }}" method="post">
{# Driver PXX Select #}
{{ driver_select_with_preselect(currentselection.get(user.name).pxx.abbr if user.name in currentselection else "",
"pxxselect", "P" ~ nextrace.pxx ~ ":") }}
{# Race Results #}
{% for raceresult in raceresults %}
<tr>
<td class="text-nowrap">
<span class="fw-bold">{{ raceresult.race.id }}:</span> {{ raceresult.race.grandprix }}<br>
<small><span class="fw-bold">Guessed:</span> P{{ raceresult.race.pxx }}</small>
</td>
{# Driver DNF Select #}
<div class="mt-2">
{{ driver_select_with_preselect(currentselection.get(user.name).dnf.abbr if user.name in currentselection else "",
"dnfselect", "DNF:") }}
</div>
{% if activeuser is not none %}{% set users = [activeuser] %}{% endif %}
{% for user in users %}
<td class="text-center text-nowrap">
{% if (raceresult.race_id in guesses) and (user.name in guesses.get(raceresult.race_id)) %}
{% set pxx = guesses.get(raceresult.race_id).get(user.name).pxx.abbr %}
{% set dnf = guesses.get(raceresult.race_id).get(user.name).dnf.abbr %}
<input type="submit" class="btn btn-danger mt-2 w-100" value="Save">
</form>
<ul class="list-group list-group-flush">
<li class="list-group-item {% if pxx == raceresult.pxx.abbr %}text-success fw-bold{% endif %}">
P{{ raceresult.race.pxx }}: {{ pxx }}</li>
<li class="list-group-item {% if dnf == raceresult.dnf.abbr %}text-success fw-bold{% endif %}">
DNF: {{ dnf }}</li>
</ul>
{% endif %}
</td>
{% endfor %}
{# Enter Race Result #}
<td>
<form action="/enterresult/{{ nextrace.id }}" method="post">
{# Driver PXX Select #}
{{ driver_select("pxxselect", "P" ~ nextrace.pxx ~ ":") }}
{# Driver DNF Select #}
<div class="mt-2">
{{ driver_select("dnfselect", "DNF:") }}
</div>
<input type="submit" class="btn btn-danger mt-2 w-100" value="Save">
</form>
<td class="text-center text-nowrap">
<ul class="list-group list-group-flush">
<li class="list-group-item">P{{ raceresult.race.pxx }}: {{ raceresult.pxx.abbr }}</li>
<li class="list-group-item {% if raceresult.dnf.abbr == 'NON' %}text-muted{% endif %}">
DNF: {{ raceresult.dnf.abbr }}</li>
</ul>
</td>
</tr>
{# Race Results #}
{% for raceresult in raceresults %}
<tr>
<td class="text-nowrap"><span
class="fw-bold">{{ raceresult.race.id }}:</span> {{ raceresult.race.grandprix }}</td>
{% for user in chosenusers %}
<td class="text-center text-nowrap">
{% if (raceresult.race_id in pastguesses) and (user.name in pastguesses.get(raceresult.race_id)) %}
{% set pxx = pastguesses.get(raceresult.race_id).get(user.name).pxx.abbr %}
{% set dnf = pastguesses.get(raceresult.race_id).get(user.name).dnf.abbr %}
<ul class="list-group list-group-flush">
<li class="list-group-item {% if pxx == raceresult.pxx.abbr %}text-success fw-bold{% endif %}">
P{{ raceresult.race.pxx }}: {{ pxx }}</li>
<li class="list-group-item {% if dnf == raceresult.dnf.abbr %}text-success fw-bold{% endif %}">
DNF: {{ dnf }}</li>
</ul>
{% endif %}
</td>
{% endfor %}
<td class="text-center text-nowrap">
<ul class="list-group list-group-flush">
<li class="list-group-item">P{{ raceresult.race.pxx }}: {{ raceresult.pxx.abbr }}</li>
<li class="list-group-item {% if raceresult.dnf.abbr == 'NON' %}text-muted{% endif %}">
DNF: {{ raceresult.dnf.abbr }}</li>
</ul>
</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>

View File

@ -1,18 +1,21 @@
{% extends 'base.jinja' %}
{% set active_page = "/season/" ~ chosenusername %}
{% set active_user = chosenusername %}
{% set active_page = "/season/" ~ activeuser.name | default("Everyone") %}
{% set active_user = activeuser %}
{% block title %}Formula 10 - Season{% endblock title %}
{% block navbar_center %}
<div class="dropdown">
<button class="btn btn-outline-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ chosenusername }}
<button class="btn btn-outline-danger dropdown-toggle" type="button" data-bs-toggle="dropdown"
aria-expanded="false">
{% if activeuser is not none %}{{ activeuser.name }}{% else %}Everyone{% endif %}
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/season/Everyone">Everyone</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<hr class="dropdown-divider">
</li>
{% for user in users %}
<li><a class="dropdown-item" href="/season/{{ user.name }}">{{ user.name }}</a></li>
{% endfor %}
@ -24,7 +27,10 @@
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));">
{% for user in chosenusers %}
{% if activeuser is not none %}{% set users = [activeuser] %}{% endif %}
{% for user in users %}
<div class="card mb-2 shadow-sm" style="width: 450px;">
<div class="card-body">
<h5 class="card-title">{{ user.name }}</h5>
@ -33,30 +39,30 @@
{# Hot Take #}
<div class="form-floating">
<textarea class="form-control" id="hot-take-input-{{ user.name }}" name="hottakeselect"
style="height: 50px">{%- if (user.name in currentselection) -%}
{{- currentselection.get(user.name).hot_take -}}{%- endif -%}</textarea>
style="height: 50px">{%- if (user.name in guesses) -%}
{{- guesses.get(user.name).hot_take -}}{%- endif -%}</textarea>
<label for="hot-take-input-{{ user.name }}" class="text-primary">Hot Take:</label>
</div>
{# P2 Constructor #}
<div class="mt-2">
{{ team_select_with_preselect(currentselection.get(user.name).p2_constructor.name if user.name in currentselection else "",
{{ team_select_with_preselect(guesses.get(user.name).p2_constructor.name if user.name in guesses else "",
"p2select", "P2 in WCC:") }}
</div>
{# Most Overtakes + DNFs #}
<div class="input-group mt-2">
{{ driver_select_with_preselect(currentselection.get(user.name).most_overtakes.abbr if user.name in currentselection else "",
{{ driver_select_with_preselect(guesses.get(user.name).most_overtakes.abbr if user.name in guesses else "",
"overtakeselect", "Most overtakes:") }}
{{ driver_select_with_preselect(currentselection.get(user.name).most_dnfs.abbr if user.name in currentselection else "",
{{ driver_select_with_preselect(guesses.get(user.name).most_dnfs.abbr if user.name in guesses else "",
"dnfselect", "Most DNFs:") }}
</div>
{# Most Gained + Lost #}
<div class="input-group mt-2">
{{ driver_select_with_preselect(currentselection.get(user.name).most_gained.abbr if user.name in currentselection else "",
{{ driver_select_with_preselect(guesses.get(user.name).most_gained.abbr if user.name in guesses else "",
"gainedselect", "Most WDC places gained:") }}
{{ driver_select_with_preselect(currentselection.get(user.name).most_lost.abbr if user.name in currentselection else "",
{{ driver_select_with_preselect(guesses.get(user.name).most_lost.abbr if user.name in guesses else "",
"lostselect", "Most WDC places lost:") }}
</div>
@ -73,7 +79,7 @@
name="teamwinner-{{ team.name }}"
id="teamwinner-{{ team.name }}-1-{{ user.name }}"
value="{{ driver_a_name }}"
{% if (user.name in currentselection) and (driver_a_name in currentselection.get(user.name).team_winners.winner_ids) %}checked="checked"{% endif %}>
{% if (user.name in guesses) and (driver_a_name in guesses.get(user.name).team_winners.winner_ids) %}checked="checked"{% endif %}>
<label class="form-check-label"
for="teamwinner-{{ team.name }}-1-{{ user.name }}">{{ driver_a_name }}</label>
</div>
@ -85,7 +91,7 @@
name="teamwinner-{{ team.name }}"
id="teamwinner-{{ team.name }}-2-{{ user.name }}"
value="{{ driver_b_name }}"
{% if (user.name in currentselection) and (driver_b_name in currentselection.get(user.name).team_winners.winner_ids) %}checked="checked"{% endif %}>
{% if (user.name in guesses) and (driver_b_name in guesses.get(user.name).team_winners.winner_ids) %}checked="checked"{% endif %}>
<label class="form-check-label"
for="teamwinner-{{ team.name }}-2-{{ user.name }}">{{ driver_b_name }}</label>
</div>
@ -106,7 +112,7 @@
name="podiumdrivers"
id="podium-{{ driver_a_name }}-{{ user.name }}"
value="{{ driver_a_name }}"
{% if (user.name in currentselection) and (driver_a_name in currentselection.get(user.name).podium_drivers.podium_ids) %}checked="checked"{% endif %}>
{% if (user.name in guesses) and (driver_a_name in guesses.get(user.name).podium_drivers.podium_ids) %}checked="checked"{% endif %}>
<label class="form-check-label"
for="podium-{{ driver_a_name }}-{{ user.name }}">{{ driver_a_name }}</label>
</div>
@ -118,7 +124,7 @@
name="podiumdrivers"
id="podium-{{ driver_b_name }}-{{ user.name }}"
value="{{ driver_b_name }}"
{% if (user.name in currentselection) and (driver_b_name in currentselection.get(user.name).podium_drivers.podium_ids) %}checked="checked"{% endif %}>
{% if (user.name in guesses) and (driver_b_name in guesses.get(user.name).podium_drivers.podium_ids) %}checked="checked"{% endif %}>
<label class="form-check-label"
for="podium-{{ driver_b_name }}-{{ user.name }}">{{ driver_b_name }}</label>
</div>
@ -131,6 +137,7 @@
</form>
</div>
</div>
{% endfor %}
</div>

View File

@ -1,7 +1,6 @@
{% extends 'base.jinja' %}
{% set active_page = "/users" %}
{% set active_user = "Everyone" %}
{% block title %}Formula 10 - Users{% endblock title %}