def prepare_competitions(self): for c in getattr(self, 'competitions', []): c.competition_url = '/competitions/{id}/'.format(id=c.id) c.display_date = dtutil.display_date(c.start_date) c.ends = '' if c.end_date < dtutil.now() else dtutil.display_date( c.end_date) c.date_sort = dtutil.dt2ts(c.start_date) c.league = True if c.type == 'League' else False title_safe = '' try: for k, v in c.base_archetypes_data().items(): if v > 0: title_safe += '{v} {k}<br>'.format(v=v, k=html.escape(k)) except KeyError: archetype.rebuild_archetypes() c.archetypes_sparkline_chart_title_safe = title_safe c.archetypes_sparkline_chart_url = url_for( 'archetype_sparkline_chart', competition_id=c.id)
def time(q: str) -> str: if len(q) > 3: url = 'http://maps.googleapis.com/maps/api/geocode/json?address={q}&sensor=false'.format(q=internal.escape(q)) info = internal.fetch_json(url) try: location = info['results'][0]['geometry']['location'] except IndexError as e: raise TooFewItemsException(e) url = 'https://maps.googleapis.com/maps/api/timezone/json?location={lat},{lng}×tamp={timestamp}&sensor=false'.format(lat=internal.escape(str(location['lat'])), lng=internal.escape(str(location['lng'])), timestamp=internal.escape(str(dtutil.dt2ts(dtutil.now())))) timezone_info = internal.fetch_json(url) if timezone_info['status'] == 'ZERO_RESULTS': raise TooFewItemsException(timezone_info['status']) timezone = dtutil.timezone(timezone_info['timeZoneId']) else: try: timezone = dtutil.timezone(q.upper()) except pytz.exceptions.UnknownTimeZoneError: # type: ignore raise TooFewItemsException('Not a recognized timezone: {q}'.format(q=q)) return dtutil.now(timezone).strftime('%l:%M %p')
def run() -> None: existing = list( map(lambda s: s['number'], db().select('SELECT `number` FROM `season`;'))) for season, setcode in enumerate(rotation.SEASONS, start=1): if not season in existing: try: info = rotation.get_set_info(setcode) except DoesNotExistException as e: print( f'Unable to get info for set with code `{setcode}` as it does not exist in rotatation data. Not inserting. {e}' ) continue if info['enter_date_dt'] < dtutil.now(): print('Inserting {} into season table.'.format(setcode)) db().execute( 'INSERT INTO season (`number`, code, start_date) VALUES (%s, %s, %s);', [season, setcode, dtutil.dt2ts(info['enter_date_dt'])])
def report(form): try: if db().supports_lock(): db().get_lock('deck_id:{id}'.format(id=form.entry)) db().get_lock('deck_id:{id}'.format(id=form.opponent)) for m in match.get_matches(form): if int(form.opponent) == m.opponent_deck_id: form.errors['result'] = 'This match was reported as You {game_wins}–{game_losses} {opponent} {date}'.format(game_wins=m.game_wins, game_losses=m.game_losses, opponent=m.opponent, date=dtutil.display_date(m.date)) return False counts = deck.count_matches(form.entry, form.opponent) if counts[int(form.entry)] >= 5: form.errors['entry'] = "You already have 5 matches reported" return False if counts[int(form.opponent)] >= 5: form.errors['opponent'] = "Your opponent already has 5 matches reported" return False pdbot = form.get('api_token', None) == configuration.get('pdbot_api_token') if pdbot: mtgo_match_id = form.get('matchID', None) else: mtgo_match_id = None entry_name = deck.load_deck(int(form.entry)).person.decode('utf-8') opp_name = deck.load_deck(int(form.opponent)).person.decode('utf-8') fetcher.post_discord_webhook( configuration.get("league_webhook_id"), configuration.get("league_webhook_token"), "{entry} reported {f.entry_games}-{f.opponent_games} vs {opponent}".format(f=form, entry=entry_name, opponent=opp_name) ) db().begin() match.insert_match(dtutil.now(), form.entry, form.entry_games, form.opponent, form.opponent_games, None, None, mtgo_match_id) db().commit() return True except LockNotAcquiredException: form.errors['entry'] = "Cannot report right now, somebody else is reporting a match for you or your opponent. Try again a bit later" return False finally: if db().supports_lock(): db().release_lock('deck_id:{id}'.format(id=form.opponent)) db().release_lock('deck_id:{id}'.format(id=form.entry))
def report(form: ReportForm) -> bool: try: db().get_lock('deck_id:{id}'.format(id=form.entry)) db().get_lock('deck_id:{id}'.format(id=form.opponent)) for m in match.get_matches(form): if int(form.opponent) == m.opponent_deck_id: form.errors['result'] = 'This match was reported as You {game_wins}–{game_losses} {opponent} {date}'.format(game_wins=m.game_wins, game_losses=m.game_losses, opponent=m.opponent, date=dtutil.display_date(m.date)) return False counts = deck.count_matches(form.entry, form.opponent) if counts[int(form.entry)] >= 5: form.errors['entry'] = 'You already have 5 matches reported' return False if counts[int(form.opponent)] >= 5: form.errors['opponent'] = 'Your opponent already has 5 matches reported' return False pdbot = form.get('api_token', None) == configuration.get('pdbot_api_token') if pdbot: mtgo_match_id = form.get('matchID', None) else: mtgo_match_id = None entry_name = deck.load_deck(int(form.entry)).person opp_name = deck.load_deck(int(form.opponent)).person if configuration.get('league_webhook_id') and configuration.get('league_webhook_token'): fetcher.post_discord_webhook( configuration.get_str('league_webhook_id'), configuration.get_str('league_webhook_token'), '{entry} reported {f.entry_games}-{f.opponent_games} vs {opponent}'.format(f=form, entry=entry_name, opponent=opp_name) ) else: logger.warning('Not posting manual report to discord because not configured.') db().begin() match.insert_match(dtutil.now(), form.entry, form.entry_games, form.opponent, form.opponent_games, None, None, mtgo_match_id) db().commit() return True except LockNotAcquiredException: form.errors['entry'] = 'Cannot report right now, somebody else is reporting a match for you or your opponent. Try again a bit later' return False finally: db().release_lock('deck_id:{id}'.format(id=form.opponent)) db().release_lock('deck_id:{id}'.format(id=form.entry))
def next_rotation_ex() -> SetInfo: try: return min([ s for s in sets() if (s.enter_date_dt + ROTATION_OFFSET) > dtutil.now() ], key=lambda s: s.enter_date_dt + ROTATION_OFFSET) except ValueError: fake_enter_date_dt = last_rotation() + datetime.timedelta(days=90) fake_exit_date_dt = last_rotation() + datetime.timedelta(days=90 + 365 + 365) fake_exit_year = fake_exit_date_dt.year fake_enter_date = DateType( fake_enter_date_dt.strftime(WIS_DATE_FORMAT), 'Unknown') fake_exit_date = DateType(fake_exit_date_dt.strftime(WIS_DATE_FORMAT), f'Q4 {fake_exit_year}') fake = SetInfo('Unannounced Set', '???', '???', 'Unannounced', fake_enter_date, fake_exit_date, fake_enter_date_dt) return fake
def recent_json(): last_week = dtutil.now() - dtutil.ts2dt(7 * 24 * 60 * 60) val = {} val['formats'] = {} last_f = {} for m in match.Match.query.filter(match.Match.start_time > last_week).all(): f = m.format if val['formats'].get(f.name, None) is None: val['formats'][f.name] = {} time = dtutil.dt2ts(m.start_time_aware().replace(microsecond=0, second=0, minute=0)) last = last_f.get(f.name, None) if last is not None: while last < time: last = last + 3600 val['formats'][f.name][last] = val['formats'][f.name].get(last, 0) else: last = time last_f[f.name] = last val['formats'][f.name][time] = val['formats'][f.name].get(time, 0) + 1 return return_json(val)
def __init__(self, tournament_winning_decks: List[Deck]) -> None: super().__init__() people = set(d.person for d in tournament_winning_decks) self.people_with_byes = [{ 'person': person, 'url': url_for('.person', mtgo_username=person) } for person in people] self.people_with_byes = sorted(self.people_with_byes, key=lambda k: k['person']) pd500_date = tournaments.pd500_date() if dtutil.now() > pd500_date: self.date_info = 'The Penny Dreadful 500 is on the second-last Saturday of the season' else: self.date_info = 'The next Penny Dreadful 500 is on ' + dtutil.display_date_with_date_and_year( pd500_date) self.faqs_url = url_for('faqs') self.cardhoarder_loan_url = 'https://www.cardhoarder.com/free-loan-program-faq' self.tournaments_url = url_for('tournaments') self.discord_url = url_for('discord')
def ad_hoc() -> None: try: event_loop = asyncio.get_event_loop() except RuntimeError: event_loop = asyncio.new_event_loop() asyncio.set_event_loop(event_loop) league.set_status(league.Status.CLOSED) multiverse.init() # New Cards? event_loop.run_until_complete(multiverse.set_legal_cards_async()) # PD current list event_loop.run_until_complete(multiverse.update_pd_legality_async()) # PD previous lists insert_seasons.run() # Make sure Season table is up to date if redis.REDIS: # Clear the redis cache redis.REDIS.flushdb() league_end = league.active_league().end_date diff = league_end - dtutil.now() if diff.days > 0: league.set_status(league.Status.OPEN) print('Open the gates here') reprime_cache.run() # Update deck legalities if redis.REDIS: # Clear the redis cache redis.REDIS.flushdb()
def price_info(c: Card) -> str: try: p = fetcher.card_price(c.name) except FetchException: return 'Price unavailable' if p is None: return 'Not available online' # Currently disabled s = '{price}'.format(price=format_price(p['price'])) try: if float(p['low']) <= 0.05: s += ' (low {low}, high {high}'.format(low=format_price(p['low']), high=format_price(p['high'])) if float(p['low']) <= MAX_PRICE_TIX and not short: s += ', {week}% this week, {month}% this month, {season}% this season'.format(week=round(float(p['week']) * 100.0), month=round(float(p['month']) * 100.0), season=round(float(p['season']) * 100.0)) s += ')' age = dtutil.dt2ts(dtutil.now()) - p['time'] if age > 60 * 60 * 2: s += '\nWARNING: price information is {display} old'.format(display=dtutil.display_time(age, 1)) except TypeError as e: print(f'Unable to get price info string from {p} because of {e}') return 'Price information is incomplete' return s
def all_series_info() -> List[Container]: info = get_all_next_tournament_dates(dtutil.now(dtutil.GATHERLING_TZ)) return [ Container({ 'name': 'Penny Dreadful Saturdays', 'hosts': ['j_meka', 'crazybaloth'], 'display_time': '1:30pm Eastern', 'time': info[0][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'APAC Penny Dreadful Sundays', 'hosts': ['jgabrielygalan', 'silasary'], 'display_time': '4pm Japan Standard Time', 'time': info[1][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Sundays', 'hosts': ['cody_', 'bakert99'], 'display_time': '1:30pm Eastern', 'time': info[2][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Mondays', 'hosts': ['briar_moss', 'j_meka'], 'display_time': '7pm Eastern', 'time': info[3][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Thursdays', 'hosts': ['flac0', 'j_meka'], 'display_time': '7pm Eastern', 'time': info[4][1], 'sponsor_name': 'Cardhoarder' }) ]
def all_series_info() -> List[Container]: info = get_all_next_tournament_dates(dtutil.now(dtutil.GATHERLING_TZ)) return [ Container({ 'name': 'Penny Dreadful Saturdays', 'hosts': ['back_alley_g', 'bigm'], 'display_time': '1:30pm Eastern', 'time': info[0][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'APAC Penny Dreadful Sundays', 'hosts': ['stash86', 'silasary'], 'display_time': '4pm Japan Standard Time', 'time': info[1][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Sundays', 'hosts': ['bakert99', 'littlefield', 'mrsad'], 'display_time': '1:30pm Eastern', 'time': info[2][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Mondays', 'hosts': ['stash86', 'silasary'], 'display_time': '7pm Eastern', 'time': info[3][1], 'sponsor_name': 'Cardhoarder' }), Container({ 'name': 'Penny Dreadful Thursdays', 'hosts': ['silasary', 'stash86'], 'display_time': '7pm Eastern', 'time': info[4][1], 'sponsor_name': 'Cardhoarder' }) ]
def all_series_info(): info = get_all_next_tournament_dates(dtutil.now(dtutil.GATHERLING_TZ)) return [ Container({ 'name': 'Penny Dreadful Saturdays', 'hosts': ['back_alley_g', 'bigm'], 'display_time': '1:30pm Eastern', 'time': info[0][1], 'chat_room': '#PDS' }), Container({ 'name': 'APAC Penny Dreadful Sundays', 'hosts': ['stash86', 'silasary'], 'display_time': '6pm Australian Eastern', 'time': info[1][1], 'chat_room': '#PDS' }), Container({ 'name': 'Penny Dreadful Sundays', 'hosts': ['bakert99', 'littlefield'], 'display_time': '1:30pm Eastern', 'time': info[2][1], 'chat_room': '#PDS' }), Container({ 'name': 'Penny Dreadful Mondays', 'hosts': ['stash86', 'silasary'], 'display_time': '7pm Eastern', 'time': info[3][1], 'chat_room': '#PDM' }), Container({ 'name': 'Penny Dreadful Thursdays', 'hosts': ['silasary', 'stash86'], 'display_time': '7pm Eastern', 'time': info[4][1], 'chat_room': '#PDT' }) ]
def price_info(c): try: p = fetcher.card_price(c.name) except fetcher.FetchException: return "Price unavailable" if p is None: return "Not available online" # Currently disabled s = '{price}'.format(price=format_price(p['price'])) if float(p['low']) <= 0.05: s += ' (low {low}, high {high}'.format( low=format_price(p['low']), high=format_price(p['high'])) if float(p['low']) <= 0.01: s += ', {week}% this week, {month}% this month, {season}% this season'.format( week=round(float(p['week']) * 100.0), month=round(float(p['month']) * 100.0), season=round(float(p['season']) * 100.0)) s += ')' age = dtutil.dt2ts(dtutil.now()) - p['time'] if age > 60 * 60 * 2: s += '\nWARNING: price information is {display} old'.format( display=dtutil.display_time(age, 1)) return s
def __init__(self, competitions: List[Competition], first_runs: List[Person]) -> None: super().__init__() self.weeks: List[Container] = [] weeks = split_by_week(competitions) for week in weeks: prizes: Dict[str, int] = {} if week.end_date > dtutil.now(dtutil.WOTC_TZ): pass for c in week.get('competitions', []): for d in c.decks: prizes[d.person] = prizes.get(d.person, 0) + tournaments.prize(d) subject = 'Penny Dreadful Prizes for Week Ending {date:%b} {date.day}'.format( date=week.end_date) body = '\n'.join([c.name for c in week.get('competitions', [])]) + '\n\n' body += '\n'.join([ '{username} {prize}'.format(username=k, prize=prizes[k]) for k in sorted(prizes) if prizes[k] > 0 ]) self.weeks.append( Container({ 'subject': subject, 'body': body, 'n': len(week.get('competitions', [])) })) self.months: List[Dict[str, Any]] = [] current_competition_id = None for p in first_runs: if current_competition_id != p.competition_id: self.months.append({ 'competition_name': p.competition_name, 'people': [] }) current_competition_id = p.competition_id self.months[-1]['people'].append(p)
def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None: super().__init__() until_rotation = rotation.next_rotation() - dtutil.now() in_rotation = configuration.get_bool('always_show_rotation') if until_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Totation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2) else: self.rotation_msg = 'Rotation is ' + dtutil.display_date(rotation.next_rotation(), 2) if in_rotation: self.in_rotation = in_rotation self.show_interestingness_filter = True self.runs, self.runs_percent, self.cards = rotation.read_rotation_files() # Now add interestingness to the cards, which only decksite knows not magic.rotation. playability = card.playability() c: Card for c in self.cards: c.interestingness = rotation.interesting(playability, c) else: self.cards = [] self.show_interesting = True if interestingness: self.cards = [c for c in self.cards if c.get('interestingness') == interestingness] self.num_cards = len(self.cards) self.query = query self.show_filters_toggle = True if session.get('admin'): return self.cards = [c for c in self.cards if c.status != 'Legal'] for c in self.cards: if c.status != 'Undecided': continue c.hits = redact(c.hits) c.hits_needed = redact(c.hits_needed) c.percent = redact(c.percent) c.percent_needed = redact(c.percent_needed)
def in_rotation() -> bool: if configuration.get_bool('always_show_rotation'): return True until_rotation = seasons.next_rotation() - dtutil.now() return until_rotation < datetime.timedelta(7)
def next_supplemental() -> datetime.datetime: last = last_rotation() + datetime.timedelta(weeks=3) if last > dtutil.now(): return last return next_rotation() + datetime.timedelta(weeks=3)
def last_rotation_ex() -> SetInfoType: return max([s for s in sets() if s['enter_date_dt'] < dtutil.now()], key=lambda s: s['enter_date_dt'])
def test_now() -> None: then = dtutil.parse('2016-01-01', '%Y-%m-%d', dtutil.WOTC_TZ) now = dtutil.now() assert (now - then).total_seconds() > 0
def build_menu() -> List[Dict[str, Union[str, Dict[str, str]]]]: current_template = (request.endpoint or '').replace('seasons.', '') archetypes_badge = { 'url': url_for('edit_archetypes'), 'text': '', 'badge_class': 'edit_archetypes' } resources_submenu: List[Dict[str, str]] = [] if (seasons.next_rotation() - dtutil.now()) < datetime.timedelta(7): resources_submenu.append({ 'name': gettext('Rotation Tracking'), 'endpoint': 'rotation' }) resources_submenu += [ { 'name': gettext('Rotation Changes'), 'endpoint': 'rotation_changes' }, { 'name': gettext('Deck Check'), 'endpoint': 'deck_check' }, { 'name': gettext('Discord Chat'), 'url': 'https://discord.gg/H6EHdHu' }, { 'name': gettext('External Links'), 'endpoint': 'resources' }, { 'name': gettext('Link Accounts'), 'endpoint': 'link' }, { 'name': gettext('Bugs'), 'endpoint': 'bugs' }, ] menu = [ { 'name': gettext('Metagame'), 'endpoint': 'home', 'badge': archetypes_badge, 'submenu': [ { 'name': gettext('Decks'), 'endpoint': '.decks' }, { 'name': gettext('Archetypes'), 'endpoint': 'archetypes', 'badge': archetypes_badge }, { 'name': gettext('People'), 'endpoint': 'people' }, { 'name': gettext('Cards'), 'endpoint': 'cards' }, { 'name': gettext('Past Seasons'), 'endpoint': 'seasons' }, { 'name': gettext('Matchups'), 'endpoint': 'matchups' }, ] }, { 'name': gettext('League'), 'endpoint': 'league', 'submenu': [ { 'name': gettext('League Info'), 'endpoint': 'league' }, { 'name': gettext('Sign Up'), 'endpoint': 'signup' }, { 'name': gettext('Report'), 'endpoint': 'report' }, { 'name': gettext('Records'), 'endpoint': 'current_league' }, { 'name': gettext('Retire'), 'endpoint': 'retire' }, ] }, { 'name': gettext('Competitions'), 'endpoint': 'competitions', 'submenu': [ { 'name': gettext('Competition Results'), 'endpoint': 'competitions' }, { 'name': gettext('Tournament Info'), 'endpoint': 'tournaments' }, { 'name': gettext('Leaderboards'), 'endpoint': 'tournament_leaderboards' }, { 'name': gettext('Gatherling'), 'url': 'https://gatherling.com/' }, { 'name': gettext('Achievements'), 'endpoint': 'achievements' }, { 'name': gettext('Hosting'), 'endpoint': 'hosting' }, ] }, { 'name': gettext('Resources'), 'endpoint': 'resources', 'submenu': resources_submenu }, { 'name': gettext('About'), 'endpoint': 'about', 'submenu': [ { 'name': gettext('What is Penny Dreadful?'), 'endpoint': 'about' }, { 'name': gettext('About pennydreadfulmagic.com'), 'endpoint': 'about_pdm' }, { 'name': gettext('FAQs'), 'endpoint': 'faqs' }, { 'name': gettext('Community Guidelines'), 'endpoint': 'community_guidelines' }, ] }, { 'name': gettext('Admin'), 'admin_only': True, 'endpoint': 'admin_home', 'submenu': admin.admin_menu() }, ] setup_links(menu) for item in menu: item['current'] = item.get('endpoint', '').replace( 'seasons', '').replace('.', '') == current_template or current_template in [ entry.get('endpoint', '') for entry in item.get('submenu', []) ] item['has_submenu'] = item.get('submenu') is not None return menu
def build_menu() -> List[Dict[str, Union[str, Dict[str, str]]]]: archetypes_badge = None archetypes_badge = { 'url': url_for('edit_archetypes'), 'text': '', 'badge_class': 'edit_archetypes' } resources_submenu: List[Dict[str, str]] = [] if (rotation.next_rotation() - dtutil.now()) < datetime.timedelta(7) or ( rotation.next_supplemental() - dtutil.now()) < datetime.timedelta(7): resources_submenu += [{ 'name': gettext('Rotation Tracking'), 'url': url_for('rotation') }] resources_submenu += [{ 'name': gettext('Rotation Changes'), 'url': url_for('rotation_changes') }, { 'name': gettext('Rotation Speculation'), 'url': url_for('rotation_speculation') }, { 'name': gettext('Deck Check'), 'url': url_for('deck_check') }, { 'name': gettext('Discord Chat'), 'url': 'https://discord.gg/H6EHdHu' }, { 'name': gettext('External Links'), 'url': url_for('resources') }, { 'name': gettext('Link Accounts'), 'url': url_for('link') }, { 'name': gettext('Bugs'), 'url': url_for('bugs') }] menu = [{ 'name': gettext('Metagame'), 'url': url_for('home'), 'badge': archetypes_badge, 'submenu': [{ 'name': gettext('Latest Decks'), 'url': url_for('.decks') }, { 'name': gettext('Archetypes'), 'url': url_for('archetypes'), 'badge': archetypes_badge }, { 'name': gettext('People'), 'url': url_for('people') }, { 'name': gettext('Cards'), 'url': url_for('cards') }, { 'name': gettext('Past Seasons'), 'url': url_for('seasons') }] }, { 'name': gettext('League'), 'url': url_for('league'), 'submenu': [ { 'name': gettext('League Info'), 'url': url_for('league') }, { 'name': gettext('Sign Up'), 'url': url_for('signup') }, { 'name': gettext('Report'), 'url': url_for('report') }, { 'name': gettext('Records'), 'url': url_for('current_league') }, { 'name': gettext('Retire'), 'url': url_for('retire') }, ] }, { 'name': gettext('Competitions'), 'url': url_for('competitions'), 'submenu': [{ 'name': gettext('Competition Results'), 'url': url_for('competitions') }, { 'name': gettext('Tournament Info'), 'url': url_for('tournaments') }, { 'name': gettext('Leaderboards'), 'url': url_for('tournament_leaderboards') }, { 'name': gettext('Gatherling'), 'url': 'https://gatherling.com/' }, { 'name': gettext('Hosting'), 'url': url_for('hosting') }] }, { 'name': gettext('Resources'), 'url': url_for('resources'), 'submenu': resources_submenu }, { 'name': gettext('About'), 'url': url_for('about'), 'submenu': [{ 'name': gettext('What is Penny Dreadful?'), 'url': url_for('about') }, { 'name': gettext('About pennydreadfulmagic.com'), 'url': url_for('about_pdm') }, { 'name': gettext('FAQs'), 'url': url_for('faqs') }, { 'name': gettext('Community Guidelines'), 'url': url_for('community_guidelines') }] }, { 'name': gettext('Admin'), 'admin_only': True, 'url': url_for('admin_home'), 'submenu': admin.admin_menu() }] for item in menu: item['has_submenu'] = item.get('submenu') is not None item['is_external'] = item.get('url', '').startswith( 'http') and '://pennydreadfulmagic.com/' not in item['url'] for subitem in item.get('submenu', []): subitem['is_external'] = subitem.get('url', '').startswith( 'http') and '://pennydreadfulmagic.com/' not in subitem['url'] return menu
def all_series_info() -> List[Container]: info = get_all_next_tournament_dates(dtutil.now(dtutil.GATHERLING_TZ)) return [ Container({ 'tournament_id': info[0][0], 'name': info[0][1], 'hosts': ['flac0', 'j_meka'], 'display_time': '7pm Eastern', 'time': info[0][2], 'sponsor_name': 'Cardhoarder', }), Container({ 'tournament_id': info[1][0], 'name': info[1][1], 'hosts': ['j_meka', 'crazybaloth'], 'display_time': '1:30pm Eastern', 'time': info[1][2], 'sponsor_name': 'Cardhoarder', }), Container({ 'tournament_id': info[2][0], 'name': info[2][1], 'hosts': ['jgabrielygalan', 'silasary'], 'display_time': '4pm Japan Standard Time', 'time': info[2][2], 'sponsor_name': 'Cardhoarder', }), Container({ 'tournament_id': info[3][0], 'name': info[3][1], 'hosts': ['cody_', 'bakert99'], 'display_time': '1:30pm Eastern', 'time': info[3][2], 'sponsor_name': 'Cardhoarder', }), Container({ 'tournament_id': info[4][0], 'name': info[4][1], 'hosts': ['briar_moss', 'j_meka'], 'display_time': '7pm Eastern', 'time': info[4][2], 'sponsor_name': 'Cardhoarder', }), Container({ 'tournament_id': info[5][0], 'name': info[5][1], 'hosts': ['swiftwarkite2', 'bakert99'], 'display_time': '7pm Eastern', 'time': info[5][2], 'sponsor_name': 'Player-supported', }), Container({ 'tournament_id': info[6][0], 'name': info[6][1], 'hosts': ['flac0', 'j_meka'], 'display_time': '7pm Eastern', 'time': info[6][2], 'sponsor_name': 'Cardhoarder', }), ]
def last_rotation_ex() -> SetInfo: return max([ s for s in sets() if (s.enter_date_dt + ROTATION_OFFSET) < dtutil.now() ], key=lambda s: s.enter_date_dt + ROTATION_OFFSET)
def cleanup() -> None: beginning_of_season = rotation.last_rotation() one_month_ago = dtutil.now(dtutil.WOTC_TZ) - datetime.timedelta(31) oldest_needed = min(beginning_of_season, one_month_ago) execute('DELETE FROM low_price WHERE `time` < %s', [dtutil.dt2ts(oldest_needed)])
def stats(): val = {} last_switcheroo = match.Match.query.filter(match.Match.has_unexpected_third_game).order_by(match.Match.id.desc()).first() if last_switcheroo: val['last_switcheroo'] = dtutil.dt2ts(last_switcheroo.start_time_aware()) val['formats'] = {} base_query = db.DB.session.query(match.Match.format_id, Format.name, func.count(match.Match.format_id)).join(match.Match.format).group_by(match.Match.format_id) for m in base_query.order_by(func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name] = {} val['formats'][format_name]['name'] = format_name val['formats'][format_name]['num_matches'] = num_matches last_week = dtutil.now() - dtutil.ts2dt(7 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time > last_week).order_by(func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_week'] = {} val['formats'][format_name]['last_week']['num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query(db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_week']['recent_players'] = [p.name for p in players] last_last_week = dtutil.now() - dtutil.ts2dt(2 * 7 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time < last_week).filter(match.Match.start_time > last_last_week).order_by(func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_last_week'] = {} val['formats'][format_name]['last_last_week']['num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 14 DAY) AND `match`.start_time < DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query(db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_last_week']['recent_players'] = [p.name for p in players] last_month = dtutil.now() - dtutil.ts2dt(30 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time > last_month).order_by(func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_month'] = {} val['formats'][format_name]['last_month']['num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query(db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_month']['recent_players'] = [p.name for p in players] return return_json(val)
def message() -> str: diff = next_rotation() - dtutil.now() s = dtutil.display_time(int(diff.total_seconds())) return f'The next rotation is in {s}'
def next_rotation_ex() -> SetInfoType: return min([s for s in sets() if s['enter_date_dt'] > dtutil.now()], key=lambda s: s['enter_date_dt'])
def hide_intro() -> Response: r = Response(response='') r.set_cookie('hide_intro', value=str(True), expires=dtutil.dt2ts(dtutil.now()) + 60 * 60 * 24 * 365 * 10) return r
def stats() -> Response: val: Dict[str, Any] = {} try: last_switcheroo = calc_last_switcheroo() if last_switcheroo: start = last_switcheroo.start_time_aware() if start: val['last_switcheroo'] = dtutil.dt2ts(start) except AttributeError as e: logger.warning(f'Unable to calculate last_switcheroo: {e}') val['formats'] = {} base_query = db.DB.session.query(match.Match.format_id, Format.name, func.count(match.Match.format_id)).join( match.Match.format).group_by( match.Match.format_id) for m in base_query.order_by(func.count( match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name] = {} val['formats'][format_name]['name'] = format_name val['formats'][format_name]['num_matches'] = num_matches last_week = dtutil.now() - dtutil.ts2dt(7 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time > last_week).order_by( func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_week'] = {} val['formats'][format_name]['last_week']['num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query( db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_week']['recent_players'] = [ p.name for p in players ] last_last_week = dtutil.now() - dtutil.ts2dt(2 * 7 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time < last_week).filter( match.Match.start_time > last_last_week).order_by( func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_last_week'] = {} val['formats'][format_name]['last_last_week'][ 'num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 14 DAY) AND `match`.start_time < DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query( db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_last_week']['recent_players'] = [ p.name for p in players ] last_month = dtutil.now() - dtutil.ts2dt(30 * 24 * 60 * 60) for m in base_query.filter(match.Match.start_time > last_month).order_by( func.count(match.Match.format_id).desc()).all(): (format_id, format_name, num_matches) = m val['formats'][format_name]['last_month'] = {} val['formats'][format_name]['last_month']['num_matches'] = num_matches stmt = text(""" SELECT b.* FROM user AS b INNER JOIN ( SELECT user.id FROM user LEFT JOIN match_players ON match_players.user_id = user.id LEFT JOIN `match` ON `match`.id = match_players.match_id WHERE `match`.format_id = :fid AND `match`.start_time IS NOT NULL AND `match`.start_time > DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY user.id ) AS a ON a.id = b.id """) players = db.DB.session.query( db.User).from_statement(stmt).params(fid=format_id).all() val['formats'][format_name]['last_month']['recent_players'] = [ p.name for p in players ] return return_json(val)