Beispiel #1
0
 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)
Beispiel #2
0
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}&timestamp={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'])])
Beispiel #4
0
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))
Beispiel #5
0
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))
Beispiel #6
0
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
Beispiel #7
0
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)
Beispiel #8
0
 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
Beispiel #11
0
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'
        })
    ]
Beispiel #14
0
 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
Beispiel #15
0
 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)
Beispiel #16
0
 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',
        }),
    ]
Beispiel #24
0
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)
Beispiel #25
0
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)])
Beispiel #26
0
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)
Beispiel #27
0
def message() -> str:
    diff = next_rotation() - dtutil.now()
    s = dtutil.display_time(int(diff.total_seconds()))
    return f'The next rotation is in {s}'
Beispiel #28
0
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
Beispiel #30
0
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)