Compare commits
2 Commits
97161c96a9
...
516fa107e5
| Author | SHA1 | Date | |
|---|---|---|---|
| 516fa107e5 | |||
| 26acc22e84 |
60
formula10.py
60
formula10.py
@ -17,10 +17,11 @@ db.init_app(app)
|
|||||||
# - Sortable list to enter full race results (need 7 positions to calculate points),
|
# - Sortable list to enter full race results (need 7 positions to calculate points),
|
||||||
# don't enter race result on guess page
|
# don't enter race result on guess page
|
||||||
# - Move guessed place to leftmost column and display actual finishing position of driver instead
|
# - Move guessed place to leftmost column and display actual finishing position of driver instead
|
||||||
# - Display selector to choose a single user on race guessing page
|
# - Choose "place to guess" late before the race?
|
||||||
# - Display selector to choose a single user on season guessing page?
|
|
||||||
# - Choose place to guess late before the race?
|
|
||||||
# - Already show coming race in table, to give better feedback once a user has locked in a guess
|
# - Already show coming race in table, to give better feedback once a user has locked in a guess
|
||||||
|
# - Set fixed sizes for left- and rightmost column in races table
|
||||||
|
# - Fix the weird sizing everywhere when selecting only a single user...
|
||||||
|
# - Replace ALL absolute pixel values inside the templates
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@ -28,6 +29,12 @@ def index():
|
|||||||
return redirect("/race")
|
return redirect("/race")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/saveall")
|
||||||
|
def savedynamic():
|
||||||
|
export_dynamic_data()
|
||||||
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/loadall")
|
@app.route("/loadall")
|
||||||
def load():
|
def load():
|
||||||
reload_static_data(db)
|
reload_static_data(db)
|
||||||
@ -35,38 +42,34 @@ def load():
|
|||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/reloadall")
|
@app.route("/loadstatic")
|
||||||
def reload():
|
|
||||||
export_dynamic_data()
|
|
||||||
reload_static_data(db)
|
|
||||||
reload_dynamic_data(db)
|
|
||||||
return redirect("/")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/reloadstatic")
|
|
||||||
def reloadstatic():
|
def reloadstatic():
|
||||||
reload_static_data(db)
|
reload_static_data(db)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/reloaddynamic")
|
@app.route("/loaddynamic")
|
||||||
def reloaddynamic():
|
def reloaddynamic():
|
||||||
reload_dynamic_data(db)
|
reload_dynamic_data(db)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/savedynamic")
|
|
||||||
def savedynamic():
|
|
||||||
export_dynamic_data()
|
|
||||||
return redirect("/")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/race")
|
@app.route("/race")
|
||||||
def guessraceresults():
|
def guessraceresult():
|
||||||
|
return redirect("/race/Everyone")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/race/<username>")
|
||||||
|
def guessuserraceresults(username):
|
||||||
users: List[User] = User.query.all()
|
users: List[User] = User.query.all()
|
||||||
raceresults: List[RaceResult] = RaceResult.query.all()[::-1]
|
raceresults: List[RaceResult] = RaceResult.query.all()[::-1]
|
||||||
drivers: List[Driver] = Driver.query.all()
|
drivers: List[Driver] = Driver.query.all()
|
||||||
|
|
||||||
|
# Select User
|
||||||
|
chosenusers = users
|
||||||
|
if username != "Everyone":
|
||||||
|
chosenusers = [user for user in users if user.name == username]
|
||||||
|
|
||||||
pastguesses = dict() # The guesses for which raceresults exist
|
pastguesses = dict() # The guesses for which raceresults exist
|
||||||
nextguesses = dict() # The guesses that are still open for modification
|
nextguesses = dict() # The guesses that are still open for modification
|
||||||
raceresult: RaceResult
|
raceresult: RaceResult
|
||||||
@ -89,7 +92,9 @@ def guessraceresults():
|
|||||||
raceresults=raceresults,
|
raceresults=raceresults,
|
||||||
pastguesses=pastguesses,
|
pastguesses=pastguesses,
|
||||||
currentselection=nextguesses,
|
currentselection=nextguesses,
|
||||||
nextrace=nextrace)
|
nextrace=nextrace,
|
||||||
|
chosenusername=username,
|
||||||
|
chosenusers=chosenusers)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/guessrace/<raceid>/<username>", methods=["POST"])
|
@app.route("/guessrace/<raceid>/<username>", methods=["POST"])
|
||||||
@ -145,12 +150,21 @@ def enterresult(raceid):
|
|||||||
|
|
||||||
@app.route("/season")
|
@app.route("/season")
|
||||||
def guessseasonresults():
|
def guessseasonresults():
|
||||||
|
return redirect("/season/Everyone")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/season/<username>")
|
||||||
|
def guessuserseasonresults(username):
|
||||||
users: List[User] = User.query.all()
|
users: List[User] = User.query.all()
|
||||||
teams: List[Team] = Team.query.all()
|
teams: List[Team] = Team.query.all()
|
||||||
drivers: List[Driver] = Driver.query.all()
|
drivers: List[Driver] = Driver.query.all()
|
||||||
|
|
||||||
# Remove NONE driver
|
# Remove NONE driver
|
||||||
drivers = [driver for driver in drivers if driver.name != "NONE"]
|
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()
|
seasonguesses = dict()
|
||||||
guess: SeasonGuess
|
guess: SeasonGuess
|
||||||
@ -170,7 +184,9 @@ def guessseasonresults():
|
|||||||
teams=teams,
|
teams=teams,
|
||||||
drivers=drivers,
|
drivers=drivers,
|
||||||
driverpairs=driverpairs,
|
driverpairs=driverpairs,
|
||||||
currentselection=seasonguesses)
|
currentselection=seasonguesses,
|
||||||
|
chosenusername=username,
|
||||||
|
chosenusers=chosenusers)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/guessseason/<username>", methods=["POST"])
|
@app.route("/guessseason/<username>", methods=["POST"])
|
||||||
|
|||||||
12
model.py
12
model.py
@ -8,9 +8,9 @@ import json
|
|||||||
|
|
||||||
db = SQLAlchemy()
|
db = SQLAlchemy()
|
||||||
|
|
||||||
#
|
####################################
|
||||||
# Static Data (Defined in Backend)
|
# Static Data (Defined in Backend) #
|
||||||
#
|
####################################
|
||||||
|
|
||||||
|
|
||||||
class Race(db.Model):
|
class Race(db.Model):
|
||||||
@ -60,9 +60,9 @@ class Driver(db.Model):
|
|||||||
team: Mapped["Team"] = relationship("Team", foreign_keys=[team_id])
|
team: Mapped["Team"] = relationship("Team", foreign_keys=[team_id])
|
||||||
|
|
||||||
|
|
||||||
#
|
######################################
|
||||||
# Dynamic Data (Defined in Frontend)
|
# Dynamic Data (Defined in Frontend) #
|
||||||
#
|
######################################
|
||||||
|
|
||||||
|
|
||||||
class User(db.Model):
|
class User(db.Model):
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
{# Easy nav-bar entries. When a page sets the active_page variable, the current entry will be underlined #}
|
{# Easy nav-bar entries. When a page sets the active_page variable, the current entry will be underlined #}
|
||||||
{% macro nav_selector(page='', text='') %}
|
{% macro nav_selector(page='', text='') %}
|
||||||
<a class="nav-link" href="/{{ page }}">{% if active_page == page %}<u>{% endif %} {{ text }}
|
<a class="nav-link text-nowrap" href="/{{ page }}">{% if active_page == page %}<u>{% endif %} {{ text }}
|
||||||
{% if active_page == page %}</u>{% endif %}</a>
|
{% if active_page == page %}</u>{% endif %}</a>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
@ -110,18 +110,28 @@
|
|||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="/">
|
||||||
<img src="../static/image/f1_logo.svg" alt="Logo" width="120" height="30"
|
<img src="../static/image/f1_logo.svg" alt="Logo" width="120" height="30"
|
||||||
class="d-inline-block align-text-top">
|
class="d-inline-block align-text-top">
|
||||||
Formula <i>10</i> - 2024
|
Formula <i>10</i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbarCollapse">
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbarCollapse">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||||
<div class="navbar-nav">
|
<div class="navbar-nav me-2">
|
||||||
{{ nav_selector("race", "Guess Race") }}
|
{{ nav_selector("race", "Guess Race") }}
|
||||||
{{ nav_selector("season", "Guess Season") }}
|
{{ nav_selector("season", "Guess Season") }}
|
||||||
{{ nav_selector("graphs", "Statistics") }}
|
{{ nav_selector("graphs", "Statistics") }}
|
||||||
{{ nav_selector("rules", "Rules") }}
|
{{ nav_selector("rules", "Rules") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% block navbar_center %}{% endblock navbar_center %}
|
||||||
|
<div class="flex-grow-1"></div>
|
||||||
|
|
||||||
|
<div class="navbar-nav">
|
||||||
|
{{ nav_selector("enter", "Enter Race Result") }}
|
||||||
|
{{ nav_selector("users", "Manage Users") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -2,7 +2,22 @@
|
|||||||
|
|
||||||
{% set active_page = "race" %}
|
{% set active_page = "race" %}
|
||||||
|
|
||||||
{% block title %}Formula 10{% endblock title %}
|
{% block title %}Formula 10 - Race{% 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>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="/race/Everyone">Everyone</a></li>
|
||||||
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
{% for user in users %}
|
||||||
|
<li><a class="dropdown-item" href="/race/{{ user.name }}">{{ user.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock navbar_center %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
@ -10,7 +25,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" rowspan="2" class="text-center">Race</th>
|
<th scope="col" rowspan="2" class="text-center">Race</th>
|
||||||
<th scope="col" colspan="{{ users | length }}" class="text-center">Call</th>
|
<th scope="col" colspan="{{ chosenusers | length }}" class="text-center">Call</th>
|
||||||
<th scope="col" rowspan="2" class="text-center">Result</th>
|
<th scope="col" rowspan="2" class="text-center">Result</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -21,7 +36,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in chosenusers %}
|
||||||
<td class="text-center text-nowrap">{{ user.name }}</td>
|
<td class="text-center text-nowrap">{{ user.name }}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
@ -33,7 +48,7 @@
|
|||||||
<tr class="table-light">
|
<tr class="table-light">
|
||||||
<td class="text-nowrap"><span class="fw-bold">{{ nextrace.id }}:</span> {{ nextrace.grandprix }}</td>
|
<td class="text-nowrap"><span class="fw-bold">{{ nextrace.id }}:</span> {{ nextrace.grandprix }}</td>
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in chosenusers %}
|
||||||
<td>
|
<td>
|
||||||
<form action="/guessrace/{{ nextrace.id }}/{{ user.name }}" method="post">
|
<form action="/guessrace/{{ nextrace.id }}/{{ user.name }}" method="post">
|
||||||
{# Driver PXX Select #}
|
{# Driver PXX Select #}
|
||||||
@ -73,7 +88,7 @@
|
|||||||
<td class="text-nowrap"><span
|
<td class="text-nowrap"><span
|
||||||
class="fw-bold">{{ raceresult.race.id }}:</span> {{ raceresult.race.grandprix }}</td>
|
class="fw-bold">{{ raceresult.race.id }}:</span> {{ raceresult.race.grandprix }}</td>
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in chosenusers %}
|
||||||
<td class="text-center text-nowrap">
|
<td class="text-center text-nowrap">
|
||||||
{% if (raceresult.race_id in pastguesses) and (user.name in pastguesses.get(raceresult.race_id)) %}
|
{% 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 pxx = pastguesses.get(raceresult.race_id).get(user.name).pxx.abbr %}
|
||||||
|
|||||||
@ -2,13 +2,30 @@
|
|||||||
|
|
||||||
{% set active_page = "season" %}
|
{% set active_page = "season" %}
|
||||||
|
|
||||||
{% block title %}Formula 10{% endblock title %}
|
{% 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>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="/season/Everyone">Everyone</a></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 %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock navbar_center %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
|
<h4 class="heading-text text-danger text-center">All fields (of a single user, excluding podiums) must be set or your inputs won't be saved!</h4>
|
||||||
|
|
||||||
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));">
|
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));">
|
||||||
{% for user in users %}
|
{% for user in chosenusers %}
|
||||||
<div class="card mb-2 shadow-sm">
|
<div class="card mb-2 shadow-sm" style="width: 450px;">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">{{ user.name }}</h5>
|
<h5 class="card-title">{{ user.name }}</h5>
|
||||||
<form action="/guessseason/{{ user.name }}" method="post">
|
<form action="/guessseason/{{ user.name }}" method="post">
|
||||||
@ -24,31 +41,31 @@
|
|||||||
{# P2 Constructor #}
|
{# P2 Constructor #}
|
||||||
<div class="mt-2">
|
<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(currentselection.get(user.name).p2_constructor.name if user.name in currentselection else "",
|
||||||
"p2select", "P2 Constructor:") }}
|
"p2select", "P2 Constructor:") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Most Overtakes #}
|
{# Most Overtakes #}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{{ driver_select_with_preselect(currentselection.get(user.name).most_overtakes.abbr if user.name in currentselection else "",
|
{{ driver_select_with_preselect(currentselection.get(user.name).most_overtakes.abbr if user.name in currentselection else "",
|
||||||
"overtakeselect", "Most Overtakes:") }}
|
"overtakeselect", "Most Overtakes:") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Most DNFs #}
|
{# Most DNFs #}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{{ driver_select_with_preselect(currentselection.get(user.name).most_dnfs.abbr if user.name in currentselection else "",
|
{{ driver_select_with_preselect(currentselection.get(user.name).most_dnfs.abbr if user.name in currentselection else "",
|
||||||
"dnfselect", "Most DNFs:") }}
|
"dnfselect", "Most DNFs:") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Most Gained #}
|
{# Most Gained #}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{{ driver_select_with_preselect(currentselection.get(user.name).most_gained.abbr if user.name in currentselection else "",
|
{{ driver_select_with_preselect(currentselection.get(user.name).most_gained.abbr if user.name in currentselection else "",
|
||||||
"gainedselect", "Most Championship Positions gained:") }}
|
"gainedselect", "Most Championship Positions gained:") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Most Lost #}
|
{# Most Lost #}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{{ driver_select_with_preselect(currentselection.get(user.name).most_lost.abbr if user.name in currentselection else "",
|
{{ driver_select_with_preselect(currentselection.get(user.name).most_lost.abbr if user.name in currentselection else "",
|
||||||
"lostselect", "Most Championship Positions lost:") }}
|
"lostselect", "Most Championship Positions lost:") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Team-internal Winners #}
|
{# Team-internal Winners #}
|
||||||
|
|||||||
Reference in New Issue
Block a user