Change file structure
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 50s
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 50s
This commit is contained in:
@ -2,9 +2,9 @@ from typing import Dict, List, cast
|
||||
from urllib.parse import quote
|
||||
from flask import redirect
|
||||
from werkzeug import Response
|
||||
from database_utils import race_has_result, user_exists
|
||||
from model import PodiumDrivers, RaceResult, SeasonGuess, TeamWinners, User, db, RaceGuess
|
||||
from validation_utils import any_is_none, positions_are_contiguous
|
||||
from app.database.database_utils import race_has_result, user_exists
|
||||
from app.database.model import PodiumDrivers, RaceResult, SeasonGuess, TeamWinners, User, db, RaceGuess
|
||||
from app.database.validation_utils import any_is_none, positions_are_contiguous
|
||||
|
||||
|
||||
def find_or_create_race_guess(user_name: str, race_name: str) -> RaceGuess:
|
||||
@ -127,13 +127,13 @@ def update_season_guess(user_name: str, guesses: List[str | None], team_winner_g
|
||||
# Pylance marks type errors here, but those are intended. Columns are marked nullable.
|
||||
|
||||
season_guess: SeasonGuess = find_or_create_season_guess(user_name)
|
||||
season_guess.hot_take = guesses[0]
|
||||
season_guess.p2_team_name = guesses[1]
|
||||
season_guess.overtake_driver_name = guesses[2]
|
||||
season_guess.dnf_driver_name = guesses[3]
|
||||
season_guess.gained_driver_name = guesses[4]
|
||||
season_guess.lost_driver_name = guesses[5]
|
||||
season_guess.team_winners.teamwinner_driver_names = team_winner_guesses
|
||||
season_guess.hot_take = guesses[0] # type: ignore
|
||||
season_guess.p2_team_name = guesses[1] # type: ignore
|
||||
season_guess.overtake_driver_name = guesses[2] # type: ignore
|
||||
season_guess.dnf_driver_name = guesses[3] # type: ignore
|
||||
season_guess.gained_driver_name = guesses[4] # type: ignore
|
||||
season_guess.lost_driver_name = guesses[5] # type: ignore
|
||||
season_guess.team_winners.teamwinner_driver_names = team_winner_guesses # type: ignore
|
||||
season_guess.podium_drivers.podium_driver_names = podium_driver_guesses
|
||||
|
||||
db.session.commit()
|
@ -1,4 +1,4 @@
|
||||
from model import User, db, RaceResult
|
||||
from app.database.model import User, db, RaceResult
|
||||
|
||||
|
||||
def race_has_result(race_name: str) -> bool:
|
@ -1,7 +1,7 @@
|
||||
import csv
|
||||
import os.path
|
||||
from typing import List, Any
|
||||
from model import Team, Driver, Race, User, RaceResult, RaceGuess, TeamWinners, PodiumDrivers, SeasonGuess, db
|
||||
from app.database.model import Team, Driver, Race, User, RaceResult, RaceGuess, TeamWinners, PodiumDrivers, SeasonGuess, db
|
||||
|
||||
|
||||
def load_csv(filename: str) -> List[List[str]]:
|
174
app/frontend/controller.py
Normal file
174
app/frontend/controller.py
Normal file
@ -0,0 +1,174 @@
|
||||
from typing import List
|
||||
from urllib.parse import unquote
|
||||
from flask import Flask, render_template, request, redirect
|
||||
from werkzeug import Response
|
||||
from app.database.model import Team, db
|
||||
from app.database.file_utils import reload_static_data, reload_dynamic_data, export_dynamic_data
|
||||
from app.frontend.template_model import TemplateModel
|
||||
from app.database.backend_model import delete_race_guess, update_race_guess, update_race_result, update_season_guess, update_user
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///formula10.db"
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.url_map.strict_slashes = False
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
|
||||
# TODO
|
||||
# General
|
||||
|
||||
# - Choose "place to guess" late before the race? Make a page for this
|
||||
# - Rules page
|
||||
|
||||
# - Make user order changeable using drag'n'drop?
|
||||
# - Show place when entering race result (would require updating the drag'n'drop code...)
|
||||
# - Show cards of previous race results, like with season guesses?
|
||||
# - Make the season card grid left-aligned? So e.g. 2 cards are not spread over the whole screen with large gaps?
|
||||
|
||||
# Statistics
|
||||
# - Auto calculate points
|
||||
# - Order user table by points + display points somewhere
|
||||
# - Show current values for some season guesses (e.g. current most dnfs)
|
||||
# - Generate static diagram using chart.js + templating the js (funny yikes)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def root() -> Response:
|
||||
return redirect("/race/Everyone")
|
||||
|
||||
|
||||
@app.route("/save/all")
|
||||
def save() -> Response:
|
||||
export_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/all")
|
||||
def load() -> Response:
|
||||
reload_static_data()
|
||||
reload_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/static")
|
||||
def load_static() -> Response:
|
||||
reload_static_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/dynamic")
|
||||
def load_dynamic() -> Response:
|
||||
reload_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/race")
|
||||
def race_root() -> Response:
|
||||
return redirect("/race/Everyone")
|
||||
|
||||
|
||||
@app.route("/race/<user_name>")
|
||||
def race_active_user(user_name: str) -> str:
|
||||
user_name = unquote(user_name)
|
||||
model = TemplateModel()
|
||||
return render_template("race.jinja",
|
||||
active_user=model.user_by(user_name=user_name, ignore=["Everyone"]),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/race-guess/<race_name>/<user_name>", methods=["POST"])
|
||||
def race_guess_post(race_name: str, user_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
user_name = unquote(user_name)
|
||||
|
||||
pxx: str | None = request.form.get("pxxselect")
|
||||
dnf: str | None = request.form.get("dnfselect")
|
||||
|
||||
return update_race_guess(race_name, user_name, pxx, dnf)
|
||||
|
||||
|
||||
@app.route("/race-guess-delete/<race_name>/<user_name>", methods=["POST"])
|
||||
def race_guess_delete_post(race_name: str, user_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
user_name = unquote(user_name)
|
||||
|
||||
return delete_race_guess(race_name, user_name)
|
||||
|
||||
|
||||
@app.route("/season")
|
||||
def season_root() -> Response:
|
||||
return redirect("/season/Everyone")
|
||||
|
||||
|
||||
@app.route("/season/<user_name>")
|
||||
def season_active_user(user_name: str) -> str:
|
||||
user_name = unquote(user_name)
|
||||
model = TemplateModel()
|
||||
return render_template("season.jinja",
|
||||
active_user=model.user_by(user_name=user_name, ignore=["Everyone"]),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/season-guess/<user_name>", methods=["POST"])
|
||||
def season_guess_post(user_name: str) -> Response:
|
||||
user_name = unquote(user_name)
|
||||
guesses: List[str | None] = [
|
||||
request.form.get("hottakeselect"),
|
||||
request.form.get("p2select"),
|
||||
request.form.get("overtakeselect"),
|
||||
request.form.get("dnfselect"),
|
||||
request.form.get("gainedselect"),
|
||||
request.form.get("lostselect")
|
||||
]
|
||||
team_winner_guesses: List[str | None] = [
|
||||
request.form.get(f"teamwinner-{team.name}") for team in db.session.query(Team).all()
|
||||
]
|
||||
podium_driver_guesses: List[str] = request.form.getlist("podiumdrivers")
|
||||
|
||||
return update_season_guess(user_name, guesses, team_winner_guesses, podium_driver_guesses)
|
||||
|
||||
|
||||
@app.route("/result")
|
||||
def result_root() -> Response:
|
||||
return redirect("/result/Current")
|
||||
|
||||
|
||||
@app.route("/result/<race_name>")
|
||||
def result_active_race(race_name: str) -> str:
|
||||
race_name = unquote(race_name)
|
||||
model = TemplateModel()
|
||||
return render_template("enter.jinja",
|
||||
active_result=model.race_result_by(race_name=race_name),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/result-enter/<race_name>", methods=["POST"])
|
||||
def result_enter_post(race_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
pxxs: List[str] = request.form.getlist("pxx-drivers")
|
||||
first_dnfs: List[str] = request.form.getlist("first-dnf-drivers")
|
||||
dnfs: List[str] = request.form.getlist("dnf-drivers")
|
||||
excluded: List[str] = request.form.getlist("excluded-drivers")
|
||||
|
||||
return update_race_result(race_name, pxxs, first_dnfs, dnfs, excluded)
|
||||
|
||||
|
||||
@app.route("/user")
|
||||
def user_root() -> str:
|
||||
model = TemplateModel()
|
||||
return render_template("users.jinja",
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/user-add", methods=["POST"])
|
||||
def user_add_post() -> Response:
|
||||
username: str | None = request.form.get("select-add-user")
|
||||
return update_user(username, add=True)
|
||||
|
||||
|
||||
@app.route("/user-delete", methods=["POST"])
|
||||
def user_delete_post() -> Response:
|
||||
username: str | None = request.form.get("select-delete-user")
|
||||
return update_user(username, delete=True)
|
@ -1,7 +1,7 @@
|
||||
from typing import List, Callable, Dict, overload
|
||||
from sqlalchemy import desc
|
||||
from model import User, RaceResult, RaceGuess, Race, Driver, Team, SeasonGuess, db
|
||||
from validation_utils import find_first_or_none, find_multiple, find_single, find_single_or_none
|
||||
from app.database.model import User, RaceResult, RaceGuess, Race, Driver, Team, SeasonGuess, db
|
||||
from app.database.validation_utils import find_first_or_none, find_multiple, find_single, find_single_or_none
|
||||
|
||||
|
||||
# This could also be moved to database_utils (at least partially), but I though the template should cache the database responses
|
0
app/logic/points_model.py
Normal file
0
app/logic/points_model.py
Normal file
179
formula10.py
179
formula10.py
@ -1,179 +1,4 @@
|
||||
from typing import List
|
||||
from urllib.parse import unquote
|
||||
from flask import Flask, render_template, request, redirect
|
||||
from werkzeug import Response
|
||||
from model import Team, db
|
||||
from file_utils import reload_static_data, reload_dynamic_data, export_dynamic_data
|
||||
from template_model import TemplateModel
|
||||
from backend_model import delete_race_guess, update_race_guess, update_race_result, update_season_guess, update_user
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///formula10.db"
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.url_map.strict_slashes = False
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
|
||||
# TODO
|
||||
# General
|
||||
|
||||
# - Choose "place to guess" late before the race? Make a page for this
|
||||
# - Make user order changeable using drag'n'drop?
|
||||
|
||||
# - Show place when entering race result (would require updating the drag'n'drop code...)
|
||||
# - Show cards of previous race results, like with season guesses?
|
||||
# - Make the season card grid left-aligned? So e.g. 2 cards are not spread over the whole screen with large gaps?
|
||||
|
||||
# Statistics
|
||||
# - Auto calculate points
|
||||
# - Order user table by points + display points somewhere
|
||||
# - Show current values for some season guesses (e.g. current most dnfs)
|
||||
# - Generate static diagram using chart.js + templating the js (funny yikes)
|
||||
|
||||
# Rules page
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def root() -> Response:
|
||||
return redirect("/race/Everyone")
|
||||
|
||||
|
||||
@app.route("/save/all")
|
||||
def save() -> Response:
|
||||
export_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/all")
|
||||
def load() -> Response:
|
||||
reload_static_data()
|
||||
reload_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/static")
|
||||
def load_static() -> Response:
|
||||
reload_static_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/load/dynamic")
|
||||
def load_dynamic() -> Response:
|
||||
reload_dynamic_data()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/race")
|
||||
def race_root() -> Response:
|
||||
return redirect("/race/Everyone")
|
||||
|
||||
|
||||
@app.route("/race/<user_name>")
|
||||
def race_active_user(user_name: str) -> str:
|
||||
user_name = unquote(user_name)
|
||||
model = TemplateModel()
|
||||
return render_template("race.jinja",
|
||||
active_user=model.user_by(user_name=user_name, ignore=["Everyone"]),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/race-guess/<race_name>/<user_name>", methods=["POST"])
|
||||
def race_guess_post(race_name: str, user_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
user_name = unquote(user_name)
|
||||
|
||||
pxx: str | None = request.form.get("pxxselect")
|
||||
dnf: str | None = request.form.get("dnfselect")
|
||||
|
||||
return update_race_guess(race_name, user_name, pxx, dnf)
|
||||
|
||||
|
||||
@app.route("/race-guess-delete/<race_name>/<user_name>", methods=["POST"])
|
||||
def race_guess_delete_post(race_name: str, user_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
user_name = unquote(user_name)
|
||||
|
||||
return delete_race_guess(race_name, user_name)
|
||||
|
||||
|
||||
@app.route("/season")
|
||||
def season_root() -> Response:
|
||||
return redirect("/season/Everyone")
|
||||
|
||||
|
||||
@app.route("/season/<user_name>")
|
||||
def season_active_user(user_name: str) -> str:
|
||||
user_name = unquote(user_name)
|
||||
model = TemplateModel()
|
||||
return render_template("season.jinja",
|
||||
active_user=model.user_by(user_name=user_name, ignore=["Everyone"]),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/season-guess/<user_name>", methods=["POST"])
|
||||
def season_guess_post(user_name: str) -> Response:
|
||||
user_name = unquote(user_name)
|
||||
guesses: List[str | None] = [
|
||||
request.form.get("hottakeselect"),
|
||||
request.form.get("p2select"),
|
||||
request.form.get("overtakeselect"),
|
||||
request.form.get("dnfselect"),
|
||||
request.form.get("gainedselect"),
|
||||
request.form.get("lostselect")
|
||||
]
|
||||
team_winner_guesses: List[str | None] = [
|
||||
request.form.get(f"teamwinner-{team.name}") for team in db.session.query(Team).all()
|
||||
]
|
||||
podium_driver_guesses: List[str] = request.form.getlist("podiumdrivers")
|
||||
|
||||
return update_season_guess(user_name, guesses, team_winner_guesses, podium_driver_guesses)
|
||||
|
||||
|
||||
@app.route("/result")
|
||||
def result_root() -> Response:
|
||||
return redirect("/result/Current")
|
||||
|
||||
|
||||
@app.route("/result/<race_name>")
|
||||
def result_active_race(race_name: str) -> str:
|
||||
race_name = unquote(race_name)
|
||||
model = TemplateModel()
|
||||
return render_template("enter.jinja",
|
||||
active_result=model.race_result_by(race_name=race_name),
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/result-enter/<race_name>", methods=["POST"])
|
||||
def result_enter_post(race_name: str) -> Response:
|
||||
race_name = unquote(race_name)
|
||||
pxxs: List[str] = request.form.getlist("pxx-drivers")
|
||||
first_dnfs: List[str] = request.form.getlist("first-dnf-drivers")
|
||||
dnfs: List[str] = request.form.getlist("dnf-drivers")
|
||||
excluded: List[str] = request.form.getlist("excluded-drivers")
|
||||
|
||||
return update_race_result(race_name, pxxs, first_dnfs, dnfs, excluded)
|
||||
|
||||
|
||||
@app.route("/user")
|
||||
def user_root() -> str:
|
||||
model = TemplateModel()
|
||||
return render_template("users.jinja",
|
||||
model=model)
|
||||
|
||||
|
||||
@app.route("/user-add", methods=["POST"])
|
||||
def user_add_post() -> Response:
|
||||
username: str | None = request.form.get("select-add-user")
|
||||
return update_user(username, add=True)
|
||||
|
||||
|
||||
@app.route("/user-delete", methods=["POST"])
|
||||
def user_delete_post() -> Response:
|
||||
username: str | None = request.form.get("select-delete-user")
|
||||
return update_user(username, delete=True)
|
||||
|
||||
from app.frontend.controller import app
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True, host="0.0.0.0")
|
||||
app.run(debug=True, host="0.0.0.0")
|
Reference in New Issue
Block a user