def get_selected_league() -> Tuple[str, int]: """ :return: The league currently selected by the user by means of cookies """ league = str(request.cookies.get("league", Config.OPENLIGADB_LEAGUE)) try: season = int(request.cookies.get("season", Config.season())) except ValueError: season = Config.season() return league, season
def validate_matchday( league: Optional[str], season: Optional[int], matchday: Optional[int] ) -> Optional[Tuple[str, int, int]]: """ Performs checks that a league/season/matchday combination is valid. Can also fill these values with default values :param league: The league to check :param season: The season to check :param matchday: The matchday to check :return: league, season, matchday if valid, None if invalid """ try: default_league, default_season = get_selected_league() except RuntimeError: default_league, default_season = \ Config.OPENLIGADB_LEAGUE, Config.season() if league is None: league = default_league if season is None: season = default_season current_matchday, max_matchday = get_matchday_info(league, season) if matchday is None: matchday = current_matchday if not 1 <= matchday <= max_matchday: return None else: return league, season, matchday
def load_season_events() -> List[SeasonEvent]: """ Loads all event states from the database :return: The event states """ existing = { x.event_type: x for x in SeasonEvent.query.filter_by( season=Config.season(), league=Config.OPENLIGADB_LEAGUE).all() } for event_type in SeasonEventType: if event_type not in existing: new = SeasonEvent(event_type=event_type, executed=False, season=Config.season(), league=Config.OPENLIGADB_LEAGUE) db.session.add(new) existing[event_type] = new db.session.commit() return list(existing.values())
def get_due_matches(self) -> List[Match]: """ Checks if the reminder is due and returns a list of matches that the user still needs to bet on. :return: The matches for which the reminder is due """ now = datetime.utcnow() start = max(now, self.last_reminder_datetime) start_str = start.strftime("%Y-%m-%d:%H-%M-%S") then = now + self.reminder_time_delta then_str = then.strftime("%Y-%m-%d:%H-%M-%S") due_matches: List[Match] = [ x for x in Match.query.filter_by( season=Config.season(), league=Config.OPENLIGADB_LEAGUE ).all() if start_str < x.kickoff < then_str ] user_bet_matches = [ (bet.match.home_team_abbreviation, bet.match.away_team_abbreviation, bet.match.season) for bet in Bet.query.filter_by( user_id=self.user_id, season=Config.season(), league=Config.OPENLIGADB_LEAGUE ).options(db.joinedload(Bet.match)).all() ] to_remind = [] for match in due_matches: identifier = (match.home_team_abbreviation, match.away_team_abbreviation, match.season) if identifier not in user_bet_matches: to_remind.append(match) return to_remind
def update_openligadb(): """ Updates all OpenLigaDB leagues in the configuration :return: None """ start = time.time() app.logger.debug("Updating OpenLigaDB data") for league, season in Config.all_leagues(): update_required = UpdateTracker.update_required(league, season) if update_required: UpdateTracker.UPDATES[(league, season)] = int(time.time()) update_match_data(league, str(season)) app.logger.debug( f"Finished OpenLigaDB update in {time.time() - start:.2f}s")
def update_required(league: str, season: int) -> bool: """ Checks if a league requires updating :param league: The league to check :param season: The season to check :return: True if update required, False otherwise """ league_tuple = (league, season) last_update = UpdateTracker.UPDATES.get(league_tuple, 0) if last_update == 0: return True # Update on startup now = datetime.utcnow() delta = time.time() - last_update matches: List[Match] = Match.query.filter_by(season=season, league=league).all() unfinished_matches = [x for x in matches if not x.finished] if len(matches) == 0: # Initial filling of DB return True unfinished_matches.sort(key=lambda x: x.kickoff) # Don't update after the season ends if len(unfinished_matches) == 0: return False started_matches = [ match for match in unfinished_matches if match.has_started ] is_primary = \ league_tuple == (Config.OPENLIGADB_LEAGUE, Config.season()) if delta > 60 * 60 * 24: # Once a day minimum update return True elif is_primary and delta > 60 * 60: # Update Primary league once an hour return True elif len(started_matches) > 0: last_started_match = started_matches[-1] last_started_delta = last_started_match.kickoff_datetime - now last_started_seconds_delta = last_started_delta.seconds # Increase update frequency during and after matches if last_started_seconds_delta < 60 * 180: return True else: return False else: return False
def __handle_reminder(matchday: int, delta: timedelta, message_file: str, before: bool) -> bool: """ Handles sending out a reminder after/before a specified time :param matchday: The matchday that acts as an anchor :param delta: The time delta relative to the matchday :param message_file: The HTML template containing the message :param before: Whether or not the email should be sent before the event :return: True if the message was sent, False if it was not yet due """ kickoff_times = [ x.kickoff_datetime for x in Match.query.filter_by(matchday=matchday, season=Config.season(), league=Config.OPENLIGADB_LEAGUE).all() ] if len(kickoff_times) == 0: return False elif before: kickoff = min(kickoff_times) else: kickoff = max(kickoff_times) now = datetime.utcnow() if before and kickoff - delta > now: return False elif not before and kickoff + delta > now: return False else: for user in User.query.filter_by(confirmed=True).all(): message = render_template(message_file, user=user) send_email(user.email, f"Fußball Tippspiel Saison {Config.season_string()}", message, Config.SMTP_HOST, Config.SMTP_ADDRESS, Config.SMTP_PASSWORD, Config.SMTP_PORT) telegram = user.telegram_chat_id if telegram is not None: message = BeautifulSoup(message, "html.parser").text message = "\n".join([x.strip() for x in message.split("\n")]) telegram.send_message(message) return True
def api_get_leagues(): """ Retrieves a list of available leagues :return: The list of available leagues """ return {"leagues": Config.all_leagues()}
def season_string(self) -> str: """ :return: The season string, e.g. Bundesliga 2019/20 """ return Config.league_string(self.league, self.season)