Split frontend model from backend model
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 26s
All checks were successful
Build Formula10 Docker Image / build-docker (push) Successful in 26s
This commit is contained in:
44
formula10/frontend/model/driver.py
Normal file
44
formula10/frontend/model/driver.py
Normal file
@ -0,0 +1,44 @@
|
||||
from urllib.parse import quote
|
||||
|
||||
from formula10.database.model.db_driver import DbDriver
|
||||
from formula10.frontend.model.team import NONE_TEAM, Team
|
||||
|
||||
|
||||
class Driver():
|
||||
@classmethod
|
||||
def from_db_driver(cls, db_driver: DbDriver):
|
||||
driver: Driver = cls()
|
||||
driver.name = db_driver.name
|
||||
driver.abbr = db_driver.abbr
|
||||
driver.country = db_driver.country_code
|
||||
driver.team = Team.from_db_team(db_driver.team)
|
||||
return driver
|
||||
|
||||
def to_db_driver(self) -> DbDriver:
|
||||
db_driver: DbDriver = DbDriver(name=self.name)
|
||||
db_driver.abbr = self.abbr
|
||||
db_driver.country_code = self.country
|
||||
db_driver.team_name = self.team.name
|
||||
return db_driver
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, Driver):
|
||||
return self.name == __value.name
|
||||
|
||||
return NotImplemented
|
||||
|
||||
name: str
|
||||
abbr: str
|
||||
country: str
|
||||
team: Team
|
||||
|
||||
@property
|
||||
def name_sanitized(self) -> str:
|
||||
return quote(self.name)
|
||||
|
||||
|
||||
NONE_DRIVER: Driver = Driver()
|
||||
NONE_DRIVER.name = "None"
|
||||
NONE_DRIVER.abbr = "None"
|
||||
NONE_DRIVER.country = "NO"
|
||||
NONE_DRIVER.team = NONE_TEAM
|
37
formula10/frontend/model/race.py
Normal file
37
formula10/frontend/model/race.py
Normal file
@ -0,0 +1,37 @@
|
||||
from datetime import datetime
|
||||
from urllib.parse import quote
|
||||
|
||||
from formula10.database.model.db_race import DbRace
|
||||
|
||||
|
||||
class Race():
|
||||
@classmethod
|
||||
def from_db_race(cls, db_race: DbRace):
|
||||
race: Race = cls()
|
||||
race.name = db_race.name
|
||||
race.number = db_race.number
|
||||
race.date = db_race.date
|
||||
race.place_to_guess = db_race.pxx
|
||||
return race
|
||||
|
||||
def to_db_race(self) -> DbRace:
|
||||
db_race: DbRace = DbRace(name=self.name,
|
||||
number=self.number,
|
||||
date=self.date,
|
||||
pxx=self.place_to_guess)
|
||||
return db_race
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, Race):
|
||||
return self.name == __value.name
|
||||
|
||||
return NotImplemented
|
||||
|
||||
name: str
|
||||
number: int
|
||||
date: datetime
|
||||
place_to_guess: int
|
||||
|
||||
@property
|
||||
def name_sanitized(self) -> str:
|
||||
return quote(self.name)
|
33
formula10/frontend/model/race_guess.py
Normal file
33
formula10/frontend/model/race_guess.py
Normal file
@ -0,0 +1,33 @@
|
||||
from formula10.database.model.db_race_guess import DbRaceGuess
|
||||
from formula10.frontend.model.driver import Driver
|
||||
from formula10.frontend.model.race import Race
|
||||
from formula10.frontend.model.user import User
|
||||
|
||||
|
||||
class RaceGuess():
|
||||
@classmethod
|
||||
def from_db_race_guess(cls, db_race_guess: DbRaceGuess):
|
||||
race_guess: RaceGuess = cls()
|
||||
race_guess.user = User.from_db_user(db_race_guess.user)
|
||||
race_guess.race = Race.from_db_race(db_race_guess.race)
|
||||
race_guess.pxx_guess = Driver.from_db_driver(db_race_guess.pxx)
|
||||
race_guess.dnf_guess = Driver.from_db_driver(db_race_guess.dnf)
|
||||
return race_guess
|
||||
|
||||
def to_db_race_guess(self) -> DbRaceGuess:
|
||||
db_race_guess: DbRaceGuess = DbRaceGuess(user_name=self.user.name,
|
||||
race_name=self.race.name,
|
||||
pxx_driver_name=self.pxx_guess.name,
|
||||
dnf_driver_name=self.dnf_guess.name)
|
||||
return db_race_guess
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, RaceGuess):
|
||||
return self.user == __value.user and self.race == __value.race
|
||||
|
||||
return NotImplemented
|
||||
|
||||
user: User
|
||||
race: Race
|
||||
pxx_guess: Driver
|
||||
dnf_guess: Driver
|
148
formula10/frontend/model/race_result.py
Normal file
148
formula10/frontend/model/race_result.py
Normal file
@ -0,0 +1,148 @@
|
||||
import json
|
||||
from typing import Dict, List
|
||||
|
||||
from formula10.database.common_queries import find_single_driver_strict
|
||||
from formula10.database.model.db_race_result import DbRaceResult
|
||||
from formula10.frontend.model.driver import NONE_DRIVER, Driver
|
||||
from formula10.frontend.model.race import Race
|
||||
|
||||
|
||||
class RaceResult:
|
||||
@classmethod
|
||||
def from_db_race_result(cls, db_race_result: DbRaceResult):
|
||||
race_result: RaceResult = cls()
|
||||
race_result.race = Race.from_db_race(db_race_result.race)
|
||||
|
||||
# Deserialize from json
|
||||
standing: Dict[str, str] = json.loads(db_race_result.pxx_driver_names_json)
|
||||
initial_dnf: List[str] = json.loads(db_race_result.first_dnf_driver_names_json)
|
||||
all_dnfs: List[str] = json.loads(db_race_result.dnf_driver_names_json)
|
||||
standing_exclusions: List[str] = json.loads(db_race_result.excluded_driver_names_json)
|
||||
|
||||
# Populate relationships
|
||||
race_result.standing = {
|
||||
position: Driver.from_db_driver(find_single_driver_strict(driver_name))
|
||||
for position, driver_name in standing.items()
|
||||
}
|
||||
race_result.initial_dnf = [
|
||||
Driver.from_db_driver(find_single_driver_strict(driver_name))
|
||||
for driver_name in initial_dnf
|
||||
]
|
||||
race_result.all_dnfs = [
|
||||
Driver.from_db_driver(find_single_driver_strict(driver_name))
|
||||
for driver_name in all_dnfs
|
||||
]
|
||||
race_result.standing_exclusions = [
|
||||
Driver.from_db_driver(find_single_driver_strict(driver_name))
|
||||
for driver_name in standing_exclusions
|
||||
]
|
||||
|
||||
return race_result
|
||||
|
||||
def to_db_race_result(self) -> DbRaceResult:
|
||||
# "Unpopulate" relationships, remove none driver
|
||||
standing: Dict[str, str] = {
|
||||
position: driver.name for position, driver in self.standing.items()
|
||||
}
|
||||
initial_dnf: List[str] = [
|
||||
driver.name for driver in self.initial_dnf if driver
|
||||
]
|
||||
all_dnfs: List[str] = [
|
||||
driver.name for driver in self.all_dnfs if driver
|
||||
]
|
||||
standing_exclusions: List[str] = [
|
||||
driver.name for driver in self.standing_exclusions if driver
|
||||
]
|
||||
|
||||
# Serialize to json
|
||||
db_race_result: DbRaceResult = DbRaceResult(race_name=self.race.name,
|
||||
pxx_driver_names_json=json.dumps(standing),
|
||||
first_dnf_driver_names_json=json.dumps(initial_dnf),
|
||||
dnf_driver_names_json=json.dumps(all_dnfs),
|
||||
excluded_driver_names_json=json.dumps(standing_exclusions))
|
||||
|
||||
return db_race_result
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, RaceResult):
|
||||
return self.race == __value.race
|
||||
|
||||
return NotImplemented
|
||||
|
||||
race: Race
|
||||
standing: Dict[str, Driver]
|
||||
initial_dnf: List[Driver]
|
||||
all_dnfs: List[Driver]
|
||||
standing_exclusions: List[Driver]
|
||||
|
||||
def offset_from_place_to_guess(self, offset: int, respect_nc:bool = True) -> Driver:
|
||||
position: str = str(self.race.place_to_guess + offset)
|
||||
|
||||
if position not in self.standing:
|
||||
raise Exception(f"Position {position} not found in RaceResult.standing")
|
||||
|
||||
if self.standing[position] in self.standing_exclusions and respect_nc:
|
||||
return NONE_DRIVER
|
||||
|
||||
return self.standing[position]
|
||||
|
||||
def driver_standing_position_string(self, driver: Driver) -> str:
|
||||
if driver == NONE_DRIVER:
|
||||
return ""
|
||||
|
||||
for position, _driver in self.standing.items():
|
||||
if driver == _driver and driver not in self.standing_exclusions:
|
||||
return f" (P{position})"
|
||||
|
||||
return " (NC)"
|
||||
|
||||
def driver_standing_points_string(self, driver: Driver) -> str:
|
||||
points_strings: Dict[int, str] = {
|
||||
0: "10 Points",
|
||||
1: "6 Points",
|
||||
2: "3 Points",
|
||||
3: "1 Points"
|
||||
}
|
||||
|
||||
if driver == NONE_DRIVER:
|
||||
if self.standing[str(self.race.place_to_guess)] in self.standing_exclusions:
|
||||
return "10 Points"
|
||||
else:
|
||||
return "0 Points"
|
||||
|
||||
for position, _driver in self.standing.items():
|
||||
if driver == _driver and driver not in self.standing_exclusions:
|
||||
position_offset: int = abs(self.race.place_to_guess - int(position))
|
||||
if position_offset in points_strings:
|
||||
return points_strings[position_offset]
|
||||
else:
|
||||
return "0 Points"
|
||||
|
||||
raise Exception(f"Could not get points string for driver {driver.name}")
|
||||
|
||||
def driver_dnf_points_string(self, driver: Driver) -> str:
|
||||
if driver == NONE_DRIVER:
|
||||
if len(self.initial_dnf) == 0:
|
||||
return "10 Points"
|
||||
else:
|
||||
return "0 Points"
|
||||
|
||||
if driver in self.initial_dnf:
|
||||
return "10 Points"
|
||||
else:
|
||||
return "0 Points"
|
||||
|
||||
def ordered_standing_list(self) -> List[Driver]:
|
||||
return [
|
||||
self.standing[str(position)] for position in range(1, 21)
|
||||
]
|
||||
|
||||
def initial_dnf_string(self) -> str:
|
||||
if len(self.initial_dnf) == 0:
|
||||
return NONE_DRIVER.name
|
||||
|
||||
dnf_string: str = ""
|
||||
for driver in self.initial_dnf:
|
||||
dnf_string += f"{driver.abbr} "
|
||||
|
||||
return dnf_string[0:len(dnf_string)-1] # Remove last space
|
73
formula10/frontend/model/season_guess.py
Normal file
73
formula10/frontend/model/season_guess.py
Normal file
@ -0,0 +1,73 @@
|
||||
import json
|
||||
from typing import List
|
||||
from formula10.database.common_queries import find_single_driver_strict
|
||||
from formula10.database.model.db_season_guess import DbSeasonGuess
|
||||
from formula10.frontend.model.driver import Driver
|
||||
from formula10.frontend.model.team import Team
|
||||
from formula10.frontend.model.user import User
|
||||
|
||||
|
||||
class SeasonGuess():
|
||||
@classmethod
|
||||
def from_db_season_guess(cls, db_season_guess: DbSeasonGuess):
|
||||
season_guess: SeasonGuess = cls()
|
||||
season_guess.user = User.from_db_user(db_season_guess.user)
|
||||
season_guess.hot_take = db_season_guess.hot_take if db_season_guess.hot_take is not None else None
|
||||
season_guess.p2_wcc = Team.from_db_team(db_season_guess.p2_team) if db_season_guess.p2_team is not None else None
|
||||
season_guess.most_overtakes = Driver.from_db_driver(db_season_guess.overtake_driver) if db_season_guess.overtake_driver is not None else None
|
||||
season_guess.most_dnfs = Driver.from_db_driver(db_season_guess.dnf_driver) if db_season_guess.dnf_driver is not None else None
|
||||
season_guess.most_wdc_gained = Driver.from_db_driver(db_season_guess.gained_driver) if db_season_guess.gained_driver is not None else None
|
||||
season_guess.most_wdc_lost = Driver.from_db_driver(db_season_guess.lost_driver) if db_season_guess.lost_driver is not None else None
|
||||
|
||||
# Deserialize from json
|
||||
team_winners: List[str | None] = json.loads(db_season_guess.team_winners_driver_names_json)
|
||||
podiums: List[str] = json.loads(db_season_guess.podium_drivers_driver_names_json)
|
||||
|
||||
# Populate relationships
|
||||
season_guess.team_winners = [
|
||||
Driver.from_db_driver(find_single_driver_strict(driver_name)) if driver_name is not None else None
|
||||
for driver_name in team_winners
|
||||
]
|
||||
season_guess.podiums = [
|
||||
Driver.from_db_driver(find_single_driver_strict(driver_name))
|
||||
for driver_name in podiums
|
||||
]
|
||||
|
||||
return season_guess
|
||||
|
||||
def to_db_season_guess(self):
|
||||
# "Unpopulate" relationships
|
||||
team_winners: List[str | None] = [
|
||||
driver.name if driver is not None else None
|
||||
for driver in self.team_winners
|
||||
]
|
||||
podiums: List[str] = [
|
||||
driver.name for driver in self.podiums
|
||||
]
|
||||
|
||||
# Serialize to json
|
||||
db_season_guess: DbSeasonGuess = DbSeasonGuess(user_name=self.user.name,
|
||||
team_winners_driver_names_json=json.dumps(team_winners),
|
||||
podium_drivers_driver_names_json=json.dumps(podiums))
|
||||
db_season_guess.user_name = self.user.name
|
||||
db_season_guess.hot_take = self.hot_take
|
||||
db_season_guess.p2_team_name = self.p2_wcc.name if self.p2_wcc is not None else None
|
||||
db_season_guess.overtake_driver_name = self.most_overtakes.name if self.most_overtakes is not None else None
|
||||
db_season_guess.dnf_driver_name = self.most_dnfs.name if self.most_dnfs is not None else None
|
||||
db_season_guess.gained_driver_name = self.most_wdc_gained.name if self.most_wdc_gained is not None else None
|
||||
db_season_guess.lost_driver_name = self.most_wdc_lost.name if self.most_wdc_lost is not None else None
|
||||
|
||||
return db_season_guess
|
||||
|
||||
user: User
|
||||
hot_take: str | None
|
||||
p2_wcc: Team | None
|
||||
most_overtakes: Driver | None
|
||||
most_dnfs: Driver | None
|
||||
most_wdc_gained: Driver | None
|
||||
most_wdc_lost: Driver | None
|
||||
team_winners: List[Driver | None]
|
||||
podiums: List[Driver]
|
||||
|
||||
def hot_take_string(self) -> str:
|
||||
return self.hot_take if self.hot_take is not None else ""
|
30
formula10/frontend/model/team.py
Normal file
30
formula10/frontend/model/team.py
Normal file
@ -0,0 +1,30 @@
|
||||
from urllib.parse import quote
|
||||
|
||||
from formula10.database.model.db_team import DbTeam
|
||||
|
||||
|
||||
class Team():
|
||||
@classmethod
|
||||
def from_db_team(cls, db_team: DbTeam):
|
||||
team: Team = cls()
|
||||
team.name = db_team.name
|
||||
return team
|
||||
|
||||
def to_db_team(self) -> DbTeam:
|
||||
db_team: DbTeam = DbTeam(name=self.name)
|
||||
return db_team
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, Team):
|
||||
return self.name == __value.name
|
||||
|
||||
return NotImplemented
|
||||
|
||||
name: str
|
||||
|
||||
@property
|
||||
def name_sanitized(self) -> str:
|
||||
return quote(self.name)
|
||||
|
||||
NONE_TEAM: Team = Team()
|
||||
NONE_TEAM.name = "None"
|
29
formula10/frontend/model/user.py
Normal file
29
formula10/frontend/model/user.py
Normal file
@ -0,0 +1,29 @@
|
||||
from urllib.parse import quote
|
||||
|
||||
from formula10.database.model.db_user import DbUser
|
||||
|
||||
|
||||
class User():
|
||||
@classmethod
|
||||
def from_db_user(cls, db_user: DbUser):
|
||||
user: User = cls()
|
||||
user.name = db_user.name
|
||||
user.enabled = db_user.enabled
|
||||
return user
|
||||
|
||||
def to_db_user(self) -> DbUser:
|
||||
db_user: DbUser = DbUser(name=self.name, enabled=self.enabled)
|
||||
return db_user
|
||||
|
||||
def __eq__(self, __value: object) -> bool:
|
||||
if isinstance(__value, User):
|
||||
return self.name == __value.name
|
||||
|
||||
return NotImplemented
|
||||
|
||||
name: str
|
||||
enabled: bool
|
||||
|
||||
@property
|
||||
def name_sanitized(self) -> str:
|
||||
return quote(self.name)
|
@ -1,18 +1,24 @@
|
||||
from typing import List, Callable, Dict, overload
|
||||
from sqlalchemy import desc
|
||||
|
||||
from formula10.database.model.driver import Driver
|
||||
from formula10.database.model.race import Race
|
||||
from formula10.database.model.race_guess import RaceGuess
|
||||
from formula10.database.model.race_result import RaceResult
|
||||
from formula10.database.model.season_guess import SeasonGuess
|
||||
from formula10.database.model.team import Team
|
||||
from formula10.database.model.user import User
|
||||
from formula10.database.validation_util import find_first_or_none, find_multiple, find_single, find_single_or_none
|
||||
from formula10.database.model.db_driver import DbDriver
|
||||
from formula10.database.model.db_race import DbRace
|
||||
from formula10.database.model.db_race_guess import DbRaceGuess
|
||||
from formula10.database.model.db_race_result import DbRaceResult
|
||||
from formula10.database.model.db_season_guess import DbSeasonGuess
|
||||
from formula10.database.model.db_team import DbTeam
|
||||
from formula10.database.model.db_user import DbUser
|
||||
from formula10.frontend.model.driver import NONE_DRIVER, Driver
|
||||
from formula10.frontend.model.race import Race
|
||||
from formula10.frontend.model.race_guess import RaceGuess
|
||||
from formula10.frontend.model.race_result import RaceResult
|
||||
from formula10.frontend.model.season_guess import SeasonGuess
|
||||
from formula10.frontend.model.team import NONE_TEAM, Team
|
||||
from formula10.frontend.model.user import User
|
||||
from formula10.database.validation import find_first_else_none, find_multiple_strict, find_single_strict, find_single_or_none_strict
|
||||
from formula10 import db
|
||||
|
||||
|
||||
# This could also be moved to database_utils (at least partially), but I though the template should cache the database responses
|
||||
class TemplateModel:
|
||||
"""
|
||||
This class bundles all data required from inside a template.
|
||||
@ -26,15 +32,42 @@ class TemplateModel:
|
||||
_all_drivers: List[Driver] | None = None
|
||||
_all_teams: List[Team] | None = None
|
||||
|
||||
active_user: User | None = None
|
||||
active_result: RaceResult | None = None
|
||||
|
||||
_wdc_gained_excluded_abbrs: List[str] = ["RIC"]
|
||||
|
||||
def __init__(self, *, active_user_name: str | None, active_result_race_name: str | None):
|
||||
if active_user_name is not None:
|
||||
self.active_user = self.user_by(user_name=active_user_name, ignore=["Everyone"])
|
||||
|
||||
if active_result_race_name is not None:
|
||||
self.active_result = self.race_result_by(race_name=active_result_race_name)
|
||||
|
||||
def active_user_name_or_everyone(self) -> str:
|
||||
return self.active_user.name if self.active_user is not None else "Everyone"
|
||||
|
||||
def active_user_name_sanitized_or_everyone(self) -> str:
|
||||
return self.active_user.name_sanitized if self.active_user is not None else "Everyone"
|
||||
|
||||
def all_users(self) -> List[User]:
|
||||
"""
|
||||
Returns a list of all users in the database.
|
||||
"""
|
||||
if self._all_users is None:
|
||||
self._all_users = db.session.query(User).all()
|
||||
self._all_users = [
|
||||
User.from_db_user(db_user)
|
||||
for db_user in db.session.query(DbUser).filter_by(enabled=True).all()
|
||||
]
|
||||
|
||||
return self._all_users
|
||||
|
||||
def all_users_or_active_user(self) -> List[User]:
|
||||
if self.active_user is not None:
|
||||
return [self.active_user]
|
||||
|
||||
return self.all_users()
|
||||
|
||||
@overload
|
||||
def user_by(self, *, user_name: str) -> User:
|
||||
"""
|
||||
@ -57,14 +90,17 @@ class TemplateModel:
|
||||
return None
|
||||
|
||||
predicate: Callable[[User], bool] = lambda user: user.name == user_name
|
||||
return find_single(predicate, self.all_users())
|
||||
return find_single_strict(predicate, self.all_users())
|
||||
|
||||
def all_race_results(self) -> List[RaceResult]:
|
||||
"""
|
||||
Returns a list of all race results in the database, in descending order (most recent first).
|
||||
"""
|
||||
if self._all_race_results is None:
|
||||
self._all_race_results = db.session.query(RaceResult).join(RaceResult.race).order_by(desc(Race.number)).all()
|
||||
self._all_race_results = [
|
||||
RaceResult.from_db_race_result(db_race_result)
|
||||
for db_race_result in db.session.query(DbRaceResult).join(DbRaceResult.race).order_by(desc(DbRace.number)).all()
|
||||
]
|
||||
|
||||
return self._all_race_results
|
||||
|
||||
@ -73,14 +109,17 @@ class TemplateModel:
|
||||
Tries to obtain the race result corresponding to a race name.
|
||||
"""
|
||||
predicate: Callable[[RaceResult], bool] = lambda result: result.race.name == race_name
|
||||
return find_single_or_none(predicate, self.all_race_results())
|
||||
return find_single_or_none_strict(predicate, self.all_race_results())
|
||||
|
||||
def all_race_guesses(self) -> List[RaceGuess]:
|
||||
"""
|
||||
Returns a list of all race guesses in the database.
|
||||
"""
|
||||
if self._all_race_guesses is None:
|
||||
self._all_race_guesses = db.session.query(RaceGuess).all()
|
||||
self._all_race_guesses = [
|
||||
RaceGuess.from_db_race_guess(db_race_guess)
|
||||
for db_race_guess in db.session.query(DbRaceGuess).join(DbRaceGuess.user).filter_by(enabled=True).all() # Ignore disabled users
|
||||
]
|
||||
|
||||
return self._all_race_guesses
|
||||
|
||||
@ -115,18 +154,18 @@ class TemplateModel:
|
||||
def race_guesses_by(self, *, user_name: str | None = None, race_name: str | None = None) -> RaceGuess | List[RaceGuess] | Dict[str, Dict[str, RaceGuess]] | None:
|
||||
# List of all guesses by a single user
|
||||
if user_name is not None and race_name is None:
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user_name == user_name
|
||||
return find_multiple(predicate, self.all_race_guesses())
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user.name == user_name
|
||||
return find_multiple_strict(predicate, self.all_race_guesses())
|
||||
|
||||
# List of all guesses for a single race
|
||||
if user_name is None and race_name is not None:
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.race_name == race_name
|
||||
return find_multiple(predicate, self.all_race_guesses())
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.race.name == race_name
|
||||
return find_multiple_strict(predicate, self.all_race_guesses())
|
||||
|
||||
# Guess for a single race by a single user
|
||||
if user_name is not None and race_name is not None:
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user_name == user_name and guess.race_name == race_name
|
||||
return find_single_or_none(predicate, self.all_race_guesses())
|
||||
predicate: Callable[[RaceGuess], bool] = lambda guess: guess.user.name == user_name and guess.race.name == race_name
|
||||
return find_single_or_none_strict(predicate, self.all_race_guesses())
|
||||
|
||||
# Dict with all guesses
|
||||
if user_name is None and race_name is None:
|
||||
@ -134,10 +173,10 @@ class TemplateModel:
|
||||
guess: RaceGuess
|
||||
|
||||
for guess in self.all_race_guesses():
|
||||
if guess.race_name not in guesses_by:
|
||||
guesses_by[guess.race_name] = dict()
|
||||
if guess.race.name not in guesses_by:
|
||||
guesses_by[guess.race.name] = dict()
|
||||
|
||||
guesses_by[guess.race_name][guess.user_name] = guess
|
||||
guesses_by[guess.race.name][guess.user.name] = guess
|
||||
|
||||
return guesses_by
|
||||
|
||||
@ -145,7 +184,10 @@ class TemplateModel:
|
||||
|
||||
def all_season_guesses(self) -> List[SeasonGuess]:
|
||||
if self._all_season_guesses is None:
|
||||
self._all_season_guesses = db.session.query(SeasonGuess).all()
|
||||
self._all_season_guesses = [
|
||||
SeasonGuess.from_db_season_guess(db_season_guess)
|
||||
for db_season_guess in db.session.query(DbSeasonGuess).join(DbSeasonGuess.user).filter_by(enabled=True).all() # Ignore disabled users
|
||||
]
|
||||
|
||||
return self._all_season_guesses
|
||||
|
||||
@ -165,15 +207,15 @@ class TemplateModel:
|
||||
|
||||
def season_guesses_by(self, *, user_name: str | None = None) -> SeasonGuess | Dict[str, SeasonGuess] | None:
|
||||
if user_name is not None:
|
||||
predicate: Callable[[SeasonGuess], bool] = lambda guess: guess.user_name == user_name
|
||||
return find_single_or_none(predicate, self.all_season_guesses())
|
||||
predicate: Callable[[SeasonGuess], bool] = lambda guess: guess.user.name == user_name
|
||||
return find_single_or_none_strict(predicate, self.all_season_guesses())
|
||||
|
||||
if user_name is None:
|
||||
guesses_by: Dict[str, SeasonGuess] = dict()
|
||||
guess: SeasonGuess
|
||||
|
||||
for guess in self.all_season_guesses():
|
||||
guesses_by[guess.user_name] = guess
|
||||
guesses_by[guess.user.name] = guess
|
||||
|
||||
return guesses_by
|
||||
|
||||
@ -184,7 +226,10 @@ class TemplateModel:
|
||||
Returns a list of all races in the database.
|
||||
"""
|
||||
if self._all_races is None:
|
||||
self._all_races = db.session.query(Race).order_by(desc(Race.number)).all()
|
||||
self._all_races = [
|
||||
Race.from_db_race(db_race)
|
||||
for db_race in db.session.query(DbRace).order_by(desc(DbRace.number)).all()
|
||||
]
|
||||
|
||||
return self._all_races
|
||||
|
||||
@ -199,32 +244,72 @@ class TemplateModel:
|
||||
most_recent_result: RaceResult = results[0]
|
||||
predicate: Callable[[Race], bool] = lambda race: race.number == most_recent_result.race.number + 1
|
||||
|
||||
return find_first_or_none(predicate, self.all_races())
|
||||
return find_first_else_none(predicate, self.all_races())
|
||||
|
||||
def all_teams(self) -> List[Team]:
|
||||
@property
|
||||
def current_race(self) -> Race | None:
|
||||
return self.first_race_without_result()
|
||||
|
||||
def active_result_race_name_or_current_race_name(self) -> str:
|
||||
if self.active_result is not None:
|
||||
return self.active_result.race.name
|
||||
elif self.current_race is not None:
|
||||
return self.current_race.name
|
||||
else:
|
||||
return self.all_race_results()[0].race.name
|
||||
|
||||
def active_result_race_name_or_current_race_name_sanitized(self) -> str:
|
||||
if self.active_result is not None:
|
||||
return self.active_result.race.name_sanitized
|
||||
elif self.current_race is not None:
|
||||
return self.current_race.name_sanitized
|
||||
else:
|
||||
return self.all_race_results()[0].race.name_sanitized
|
||||
|
||||
def all_teams(self, *, include_none: bool) -> List[Team]:
|
||||
"""
|
||||
Returns a list of all teams in the database.
|
||||
"""
|
||||
if self._all_teams is None:
|
||||
self._all_teams = db.session.query(Team).all()
|
||||
self._all_teams = [
|
||||
Team.from_db_team(db_team)
|
||||
for db_team in db.session.query(DbTeam).all()
|
||||
]
|
||||
|
||||
return self._all_teams
|
||||
if include_none:
|
||||
return self._all_teams
|
||||
else:
|
||||
predicate: Callable[[Team], bool] = lambda team: team != NONE_TEAM
|
||||
return find_multiple_strict(predicate, self._all_teams)
|
||||
|
||||
def all_drivers(self) -> List[Driver]:
|
||||
def none_team(self) -> Team:
|
||||
return NONE_TEAM
|
||||
|
||||
def all_drivers(self, *, include_none: bool) -> List[Driver]:
|
||||
"""
|
||||
Returns a list of all drivers in the database, including the NONE driver.
|
||||
Returns a list of all drivers in the database.
|
||||
"""
|
||||
if self._all_drivers is None:
|
||||
self._all_drivers = db.session.query(Driver).all()
|
||||
self._all_drivers = [
|
||||
Driver.from_db_driver(db_driver)
|
||||
for db_driver in db.session.query(DbDriver).all()
|
||||
]
|
||||
|
||||
return self._all_drivers
|
||||
if include_none:
|
||||
return self._all_drivers
|
||||
else:
|
||||
predicate: Callable[[Driver], bool] = lambda driver: driver != NONE_DRIVER
|
||||
return find_multiple_strict(predicate, self._all_drivers)
|
||||
|
||||
def all_drivers_except_none(self) -> List[Driver]:
|
||||
"""
|
||||
Returns a list of all drivers in the database, excluding the NONE driver.
|
||||
"""
|
||||
predicate: Callable[[Driver], bool] = lambda driver: driver.name != "None"
|
||||
return find_multiple(predicate, self.all_drivers())
|
||||
def all_drivers_or_active_result_standing_drivers(self) -> List[Driver]:
|
||||
return self.active_result.ordered_standing_list() if self.active_result is not None else self.all_drivers(include_none=False)
|
||||
|
||||
def drivers_for_wdc_gained(self) -> List[Driver]:
|
||||
predicate: Callable[[Driver], bool] = lambda driver: driver.abbr not in self._wdc_gained_excluded_abbrs
|
||||
return find_multiple_strict(predicate, self.all_drivers(include_none=False))
|
||||
|
||||
def none_driver(self) -> Driver:
|
||||
return NONE_DRIVER
|
||||
|
||||
@overload
|
||||
def drivers_by(self, *, team_name: str) -> List[Driver]:
|
||||
@ -243,16 +328,16 @@ class TemplateModel:
|
||||
def drivers_by(self, *, team_name: str | None = None) -> List[Driver] | Dict[str, List[Driver]]:
|
||||
if team_name is not None:
|
||||
predicate: Callable[[Driver], bool] = lambda driver: driver.team.name == team_name
|
||||
return find_multiple(predicate, self.all_drivers_except_none(), 2)
|
||||
return find_multiple_strict(predicate, self.all_drivers(include_none=False), 2)
|
||||
|
||||
if team_name is None:
|
||||
drivers_by: Dict[str, List[Driver]] = dict()
|
||||
driver: Driver
|
||||
team: Team
|
||||
|
||||
for team in self.all_teams():
|
||||
for team in self.all_teams(include_none=False):
|
||||
drivers_by[team.name] = []
|
||||
for driver in self.all_drivers_except_none():
|
||||
for driver in self.all_drivers(include_none=False):
|
||||
drivers_by[driver.team.name] += [driver]
|
||||
|
||||
return drivers_by
|
||||
|
Reference in New Issue
Block a user