diff options
| -rw-r--r-- | app/config.py | 4 | ||||
| -rw-r--r-- | app/controller.py | 24 | ||||
| -rw-r--r-- | app/forms.py | 3 | ||||
| -rw-r--r-- | app/model.py | 44 | ||||
| -rw-r--r-- | app/routes.py | 29 | ||||
| -rw-r--r-- | app/utilities.py | 14 |
6 files changed, 84 insertions, 34 deletions
diff --git a/app/config.py b/app/config.py index a6a60be..fa16e1f 100644 --- a/app/config.py +++ b/app/config.py @@ -5,9 +5,9 @@ from os.path import abspath, dirname, join class Config: SECRET_KEY = environ.get("SECRET_KEY") or None DATABASE_CSV = environ.get("DATABASE_CSV") or None - COURT_COUNT = environ.get("COURT_COUNT") or None SQLALCHEMY_DATABASE_URI = "sqlite:///" + join(abspath(dirname(__file__)), "app.db") + COURT_COUNT = 12 PLAYERS_PER_COURT = 4 GUEST_LEVELS = [1, 3, 5] MIN_PLAYER_LEVEL = 1 - MAX_PLAYER_LEVEL = 10
\ No newline at end of file + MAX_PLAYER_LEVEL = 10 diff --git a/app/controller.py b/app/controller.py index 5bdeba7..d8a178f 100644 --- a/app/controller.py +++ b/app/controller.py @@ -2,7 +2,7 @@ from math import floor from app import app, db from datetime import date from operator import attrgetter -from sqlalchemy import select, func, Date +from sqlalchemy import func, Date from app.model import ( Player, Players, @@ -29,6 +29,7 @@ class Session: def __init__(self): with app.app_context(): + games = db.session.query(Game) db.session.query(Game).delete() id = self.players.default_id() player_data = {f"player_{i+1}": id for i in range(4)} @@ -38,9 +39,10 @@ class Session: db.session.commit() def round(self) -> int: - games = db.session.query(Game).filter(func.date(Game.date) == date.today()).all() + games = ( + db.session.query(Game).filter(func.date(Game.date) == date.today()).all() + ) round_id = max([game.round_id for game in games]) - print(round_id) if round_id is None: raise ValueError(f"Database isn't initialized") return round_id @@ -60,7 +62,7 @@ class Session: p = db.session.get(Player, getattr(game, f"player_{i+1}")) if p is None: raise ValueError(f"Player id mismatch.") - dp.append(p) + dp.append(p) t1 = DisplayTeam(DisplayPlayer(dp[0]), DisplayPlayer(dp[1])) t2 = DisplayTeam(DisplayPlayer(dp[2]), DisplayPlayer(dp[3])) db.session.get(Player, game.player_2) @@ -72,8 +74,6 @@ class Session: reserved_games = get_placeholder_games(reserved_courts, "RESERVED") active_courts = self.courts.active() active_players = self.players.active() - for player in active_players: - print(player) game_count = floor(len(active_players) / app.config["PLAYERS_PER_COURT"]) game_count = min(len(active_courts), game_count) used_courts = active_courts[:game_count] @@ -93,8 +93,18 @@ class Session: def confirm(self) -> list[DisplayGame]: if len(self.proposal) == 0: return self.all() + round_number = self.round() + 1 for game in self.proposal: - db.session.add(game) + db.session.add( + Game( + round_number, + game.court_id, + game.team_1.player_1.id, + game.team_1.player_2.id, + game.team_2.player_1.id, + game.team_2.player_2.id, + ) + ) db.session.commit() self.proposal = [] return self.all() diff --git a/app/forms.py b/app/forms.py index 504824a..2e0929a 100644 --- a/app/forms.py +++ b/app/forms.py @@ -2,8 +2,9 @@ from flask_wtf import FlaskForm from wtforms.validators import DataRequired from wtforms import StringField, PasswordField, BooleanField, SubmitField + class LoginForm(FlaskForm): username = StringField("Username", validators=[DataRequired()]) password = PasswordField("Password", validators=[DataRequired()]) remember_me = BooleanField("Remember Me") - submit = SubmitField("Sign In")
\ No newline at end of file + submit = SubmitField("Sign In") diff --git a/app/model.py b/app/model.py index 56921f4..2f8c609 100644 --- a/app/model.py +++ b/app/model.py @@ -74,7 +74,15 @@ class Player(db.Model): status: Mapped[bool] = mc(Boolean) level: Mapped[int] = mc(Integer) - def __init__(self, id, first_name, last_name, team = 0, status = False, level = int(app.config["MIN_PLAYER_LEVEL"])): + def __init__( + self, + id, + first_name, + last_name, + team=0, + status=False, + level=int(app.config["MIN_PLAYER_LEVEL"]), + ): self.id = id self.first_name = first_name self.last_name = last_name @@ -124,11 +132,15 @@ class Players: if app.config["DATABASE_CSV"] is not None: data = read_csv(app.config["DATABASE_CSV"]) db.session.query(Player).delete() - db.session.add(Player(**{"id": 0, "first_name": "---", "last_name": ""})) - db.session.add(Player(**{"id": 1, "first_name": "RESERVED", "last_name": ""})) + db.session.add( + Player(**{"id": 0, "first_name": "---", "last_name": ""}) + ) + db.session.add( + Player(**{"id": 1, "first_name": "RESERVED", "last_name": ""}) + ) for entry in data.to_dict("records"): args = entry | {"status": False} - db.session.add(Player(**args)) + db.session.add(Player(**args)) # type: ignore db.session.commit() else: if len(self.all()) == 0: @@ -163,12 +175,13 @@ class Players: return player def all(self) -> Tuple[list[Player], list[Player]]: - regulars = [ - p for p in db.session.query(Player).where(Player.first_name != "Guest") - ] - guests = [ - p for p in db.session.query(Player).where(Player.first_name == "Guest") - ] + players = ( + db.session.query(Player) + .where(Player.id > 1) + .order_by(Player.first_name, Player.last_name) + ) + regulars = [p for p in players if p.first_name != "Guest"] + guests = [p for p in players if p.first_name == "Guest"] guests.sort(key=lambda x: int(x.last_name)) return regulars, guests @@ -196,7 +209,15 @@ class Game(db.Model): player_4: Mapped[int] = mc(ForeignKey(Player.id), index=True) date: Mapped[datetime] = mc(index=True, default=lambda: date.today()) - def __init__(self, round_id: int, court_id: int, player_1: int, player_2: int, player_3: int, player_4: int): + def __init__( + self, + round_id: int, + court_id: int, + player_1: int, + player_2: int, + player_3: int, + player_4: int, + ): self.round_id = round_id self.court_id = court_id self.player_1 = player_1 @@ -205,7 +226,6 @@ class Game(db.Model): self.player_4 = player_4 - class DisplayPlayer: def __init__(self, player: Player): diff --git a/app/routes.py b/app/routes.py index bc85e48..cffbae9 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,14 +1,25 @@ from app import app from app.forms import LoginForm from app.controller import Session -from flask import render_template, request, url_for, Response, flash, redirect, get_template_attribute, render_template_string +from flask import ( + render_template, + request, + url_for, + Response, + flash, + redirect, + get_template_attribute, +) +from flask import render_template_string as render_string g = Session() + @app.route("/", methods=["GET"]) def home(): return render_template("index.j2", url_for=url_for) + @app.route("/login", methods=["GET", "POST"]) def login(): form = LoginForm() @@ -17,6 +28,7 @@ def login(): return redirect("/") return render_template("login.j2", form=form) + @app.route("/control", methods=["GET"]) def get_controls(): return render_template("controls.j2", courts=g.courts.all()) @@ -26,9 +38,7 @@ def get_controls(): def get_random_games(): g.levels = int(request.form["levels"].split()[0]) g.teams = request.form["team"] == "Teams" - return render_template( - "games.j2", games=g.propose(), title="Proposal" - ) + return render_template("games.j2", games=g.propose(), title="Proposal") @app.route("/confirm", methods=["POST"]) @@ -51,14 +61,15 @@ def toggle_player(player_request): id = int(player_request) player = g.players.toggle(id) button = get_template_attribute("macros.j2", "player_button") - t = '{% from "macros.j2" import player_button %}' - return render_template_string("{{player_button(player)}}", player=player, player_button=button) + return render_string("{{button(player)}}", player=player, button=button) @app.route("/players", methods=["GET"]) def get_list_of_players(): regulars, guests = g.players.all() - return render_template("players.j2", regulars=regulars, guests=guests, url_for=url_for) + return render_template( + "players.j2", regulars=regulars, guests=guests, url_for=url_for + ) @app.route("/reset_players", methods=["POST"]) @@ -73,8 +84,8 @@ def reset_all_players(): def toggle_court(court_number): id = int(court_number) status = g.courts.toggle(id) - t = '{% from "macros.j2" import court_button %}{{ court_button(id, status) }}' - return render_template(t, id=id, status=status) + button = get_template_attribute("macros.j2", "court_button") + return render_string("{{button(id, status)}}", id=id, status=status, button=button) @app.route("/courts", methods=["GET"]) diff --git a/app/utilities.py b/app/utilities.py index c84e1bf..133f9e1 100644 --- a/app/utilities.py +++ b/app/utilities.py @@ -1,7 +1,9 @@ from app import app, db +from datetime import date +from sqlalchemy import func from typing import Tuple, Sequence from random import shuffle, sample -from app.model import Player, DisplayPlayer, Court, DisplayGame, DisplayTeam +from app.model import Player, DisplayPlayer, Court, Game, DisplayGame, DisplayTeam def _shuffle_two_lists(a: list, b: list) -> Tuple[list, list]: @@ -26,13 +28,19 @@ def sample_list(indices: list, cost: list[int], count=None) -> list: def _normalize_skill(level: int, new_max: int) -> int: - new_level = round((new_max - 1) * (level / app.config["MAX_PLAYER_LEVEL"])) + 1 + scaling = (new_max - 1) / int(app.config["MAX_PLAYER_LEVEL"]) + new_level = round(scaling * level) + 1 return new_level def select_players(players: Sequence[Player], count: int) -> list[Player]: + games = db.session.query(Game).filter(func.date(Game.date) == date.today()).all() + player_identifiers = [] + for game in games: + for i in range(4): + player_identifiers.append(getattr(game, f"player_{i+1}")) identifiers = [player.id for player in players] - play_count = [int(player.id) for player in players] + play_count = [player_identifiers.count(player.id) for player in players] ids = sample_list(identifiers, play_count, count) selected_players = [player for player in players if player.id in ids] return selected_players |
