def test_determine_end_of_league():
    start_date = dtutil.parse('2017-11-01 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date)
    assert dtutil.dt2ts(end_date) == 1512115199
    start_date = dtutil.parse('2017-10-31 11:59:59.999', '%Y-%m-%d %H:%M:%S.%f', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date)
    assert dtutil.dt2ts(end_date) == 1512115199
예제 #2
0
def next_tournament_info():
    now = dtutil.now(dtutil.GATHERLING_TZ)
    now_ts = dtutil.dt2ts(dtutil.now())
    pdm_time = rrule.rrule(rrule.WEEKLY, byhour=19, byminute=0, bysecond=0, dtstart=now, byweekday=rrule.MO)[0]
    pdt_time = rrule.rrule(rrule.WEEKLY, byhour=19, byminute=0, bysecond=0, dtstart=now, byweekday=rrule.TH)[0]
    pds_time = rrule.rrule(rrule.WEEKLY, byhour=13, byminute=30, bysecond=0, dtstart=now, byweekday=rrule.SU)[0]
    if pdm_time < pdt_time and pdm_time < pds_time:
        next_tournament_name = 'Penny Dreadful Monday'
        next_time = pdm_time
    elif pdt_time < pds_time:
        next_tournament_name = 'Penny Dreadful Thursday'
        next_time = pdt_time
    else:
        next_tournament_name = 'Penny Dreadful Sunday'
        next_time = pds_time
    next_tournament_time_precise = dtutil.dt2ts(next_time) - now_ts
    next_tournament_time = dtutil.display_time(next_tournament_time_precise, granularity=1)
    return {
        'next_tournament_name': next_tournament_name,
        'next_tournament_time': next_tournament_time,
        'next_tournament_time_precise': next_tournament_time_precise,
        'pdm_time': pdm_time,
        'pds_time': pds_time,
        'pdt_time': pdt_time
        }
예제 #3
0
def insert_match(dt: datetime.datetime,
                 left_id: int,
                 left_games: int,
                 right_id: int,
                 right_games: int,
                 round_num: Optional[int] = None,
                 elimination: Optional[int] = None,
                 mtgo_match_id: Optional[int] = None) -> int:
    if left_games == right_games:
        raise InvalidDataException('`insert_match` does not support draws.')
    winner_id = left_id if left_games > right_games else right_id
    loser_id = left_id if left_games < right_games else right_id
    db().begin('insert_match')
    match_id = db().insert(
        'INSERT INTO `match` (`date`, `round`, elimination, mtgo_id) VALUES (%s, %s, %s, %s)',
        [dtutil.dt2ts(dt), round_num, elimination, mtgo_match_id])
    sql = 'UPDATE deck_cache SET wins = IFNULL(wins, 0) + 1, active_date = %s WHERE deck_id = %s'
    db().execute(sql, [dtutil.dt2ts(dt), winner_id])
    sql = 'UPDATE deck_cache SET losses = IFNULL(losses, 0) + 1, active_date = %s WHERE deck_id = %s'
    db().execute(sql, [dtutil.dt2ts(dt), loser_id])
    sql = 'INSERT INTO deck_match (deck_id, match_id, games) VALUES (%s, %s, %s)'
    db().execute(sql, [left_id, match_id, left_games])
    if right_id is not None:  # Don't insert matches or adjust Elo for the bye.
        db().execute(sql, [right_id, match_id, right_games])
        elo.adjust_elo(winner_id, loser_id)
    db().commit('insert_match')
    redis.clear(f'decksite:deck:{left_id}')
    if right_id is not None:
        redis.clear(f'decksite:deck:{right_id}')
    return match_id
예제 #4
0
 def last_switcheroo(self) -> str:
     last_switcheroo = stats.calc_last_switcheroo()
     if last_switcheroo:
         diff = dtutil.dt2ts(dtutil.now()) - dtutil.dt2ts(
             last_switcheroo.start_time_aware())
         return dtutil.display_time(diff)
     return 'unknown'
예제 #5
0
def load_news(start_date: datetime.datetime = None,
              end_date: datetime.datetime = None,
              max_items: int = sys.maxsize) -> List[Container]:
    if start_date is None:
        start_date = dtutil.ts2dt(0)
    if end_date is None:
        end_date = dtutil.now()
    sql = """
        SELECT
            id,
            `date`,
            title,
            url
        FROM
            news_item
        WHERE
            `date` >= %s
        AND
            `date` <= %s
        ORDER BY
            `date` DESC
        LIMIT
            %s
    """
    results = [
        Container(r) for r in db().select(
            sql, [dtutil.dt2ts(start_date),
                  dtutil.dt2ts(end_date), max_items])
    ]
    for result in results:
        result.date = dtutil.ts2dt(result.date)
        result.form_date = dtutil.form_date(result.date, dtutil.WOTC_TZ)
        result.display_date = dtutil.display_date(result.date)
        result.type = 'site-news'
    return results
예제 #6
0
 def last_switcheroo(self) -> str:
     last_switcheroo = stats.calc_last_switcheroo()
     if last_switcheroo:
         start = last_switcheroo.start_time_aware()
         diff = -1
         if start is not None:
             diff = dtutil.dt2ts(dtutil.now()) - dtutil.dt2ts(start)
         return dtutil.display_time(diff)
     return 'unknown'
예제 #7
0
def tournament_info(time_direction: TimeDirection, units: int = 2) -> Dict[str, Any]:
    day, time = get_nearest_tournament(time_direction)
    next_tournament_time_precise = abs(dtutil.dt2ts(time) - dtutil.dt2ts(dtutil.now()))
    near = next_tournament_time_precise < 18000 # Threshold for near: 5 hours in seconds
    next_tournament_time = dtutil.display_time(next_tournament_time_precise, units)
    return {
        'next_tournament_name': 'Penny Dreadful {day}'.format(day=day),
        'next_tournament_time': next_tournament_time,
        'next_tournament_time_precise': next_tournament_time_precise,
        'near': near
    }
예제 #8
0
def tournament_info(time_direction: TimeDirection, units: int = 2) -> Dict[str, Any]:
    tournament_id, name, time = get_nearest_tournament(time_direction)
    next_tournament_time_precise = abs(dtutil.dt2ts(time) - dtutil.dt2ts(dtutil.now()))
    near = next_tournament_time_precise < 18000  # Threshold for near: 5 hours in seconds
    next_tournament_time = dtutil.display_time(next_tournament_time_precise, units)
    info = {
        'next_tournament_name': name,
        'next_tournament_time': next_tournament_time,
        'next_tournament_time_precise': next_tournament_time_precise,
        'near': near,
    }
    info.update(series_info(tournament_id))
    return info
예제 #9
0
def tournament_winners(start_date: datetime.datetime,
                       end_date: datetime.datetime,
                       max_items: int = sys.maxsize) -> List[Container]:
    where = 'd.finish = 1 AND d.created_date > {start_date} AND d.created_date <= {end_date}'.format(
        start_date=sqlescape(dtutil.dt2ts(start_date)),
        end_date=sqlescape(dtutil.dt2ts(end_date)))
    ds = deck.load_decks(where, limit=f'LIMIT {max_items}')
    return [
        Container({
            'date': d.active_date,
            'title': tournament_winner_headline(d),
            'url': url_for('deck', deck_id=d.id),
            'type': 'tournament-winner'
        }) for d in ds
    ]
예제 #10
0
def insert_match(dt: datetime.datetime,
                 left_id: int,
                 left_games: int,
                 right_id: int,
                 right_games: int,
                 round_num: Optional[int] = None,
                 elimination: Optional[int] = None,
                 mtgo_match_id: Optional[int] = None) -> int:
    db().begin('insert_match')
    match_id = db().insert(
        'INSERT INTO `match` (`date`, `round`, elimination, mtgo_id) VALUES (%s, %s, %s, %s)',
        [dtutil.dt2ts(dt), round_num, elimination, mtgo_match_id])
    update_cache(left_id, left_games, right_games, dt=dt)
    update_cache(right_id, right_games, left_games, dt=dt)
    sql = 'INSERT INTO deck_match (deck_id, match_id, games) VALUES (%s, %s, %s)'
    db().execute(sql, [left_id, match_id, left_games])
    if right_id is not None:  # Don't insert matches or adjust Elo for the bye.
        db().execute(sql, [right_id, match_id, right_games])
        if left_games == right_games:  # Don't adjust Elo for a draw. This is not quite right but we have so few it's not important.
            winner_id = left_id if left_games > right_games else right_id
            loser_id = left_id if left_games < right_games else right_id
            elo.adjust_elo(winner_id, loser_id)
    db().commit('insert_match')
    redis.clear(f'decksite:deck:{left_id}')
    if right_id is not None:
        redis.clear(f'decksite:deck:{right_id}')
    return match_id
예제 #11
0
def insert_deck(competition_id: int, date: datetime.datetime,
                d: GatherlingDeck, fs: FinalStandings,
                players: List[Player]) -> deck.Deck:
    finish = fuzzy_get(fs, d.playername)
    if not finish:
        raise InvalidDataException(
            f"I don't have a finish for `{d.playername}`")
    mtgo_username = find_mtgo_username(d.playername, players)
    if not mtgo_username:
        raise InvalidDataException(
            f"I don't have an MTGO username for `{d.playername}`")
    raw: deck.RawDeckDescription = {
        'name': d.name,
        'source': 'Gatherling',
        'competition_id': competition_id,
        'created_date': dtutil.dt2ts(date),
        'mtgo_username': mtgo_username,
        'finish': finish,
        'url': gatherling_url(f'/deck.php?mode=view&id={d.id}'),
        'archetype': d.archetype.value,
        'identifier': str(d.id),
        'cards': {
            'maindeck': d.maindeck,
            'sideboard': d.sideboard
        },
    }
    if len(raw['cards']['maindeck']) + len(raw['cards']['sideboard']) == 0:
        raise InvalidDataException(
            f'Unable to add deck with no cards `{d.id}`')
    decklist.vivify(raw['cards'])
    if deck.get_deck_id(raw['source'], raw['identifier']):
        raise InvalidArgumentException(
            "You asked me to insert a deck that already exists `{raw['source']}`, `{raw['identifier']}`"
        )
    return deck.add_deck(raw)
예제 #12
0
def times_from_location(q: str, twentyfour: bool) -> Dict[str, List[str]]:
    api_key = configuration.get('google_maps_api_key')
    if not api_key:
        raise NotConfiguredException('No value found for google_maps_api_key')
    url = 'https://maps.googleapis.com/maps/api/geocode/json?address={q}&key={api_key}&sensor=false'.format(
        q=fetch_tools.escape(q), api_key=api_key)
    info = fetch_tools.fetch_json(url)
    if 'error_message' in info:
        return info['error_message']
    try:
        location = info['results'][0]['geometry']['location']
    except IndexError as e:
        raise TooFewItemsException(e) from e
    url = 'https://maps.googleapis.com/maps/api/timezone/json?location={lat},{lng}&timestamp={timestamp}&key={api_key}&sensor=false'.format(
        lat=fetch_tools.escape(str(location['lat'])),
        lng=fetch_tools.escape(str(location['lng'])),
        timestamp=fetch_tools.escape(str(dtutil.dt2ts(dtutil.now()))),
        api_key=api_key)
    timezone_info = fetch_tools.fetch_json(url)
    if 'error_message' in timezone_info:
        return timezone_info['error_message']
    if timezone_info['status'] == 'ZERO_RESULTS':
        raise TooFewItemsException(timezone_info['status'])
    try:
        timezone = dtutil.timezone(timezone_info['timeZoneId'])
    except KeyError as e:
        raise TooFewItemsException(
            f'Unable to find a timezone in {timezone_info}') from e
    return {
        current_time(timezone, twentyfour):
        [info['results'][0]['formatted_address']]
    }
예제 #13
0
async def update_database_async(new_date: datetime.datetime) -> None:
    db().begin('update_database')
    db().execute('DELETE FROM scryfall_version')
    db().execute(
        'SET FOREIGN_KEY_CHECKS=0'
    )  # Avoid needing to drop _cache_card (which has an FK relationship with card) so that the database continues to function while we perform the update.
    db().execute("""
        DELETE FROM card_color;
        DELETE FROM card_color_identity;
        DELETE FROM card_legality;
        DELETE FROM card_bug;
        DELETE FROM face;
        DELETE FROM printing;
        DELETE FROM card;
        DELETE FROM `set`;
    """)
    for s in await fetcher.all_sets_async():
        insert_set(s)
    every_card_printing = await fetcher.all_cards_async()
    await insert_cards_async(every_card_printing)
    await update_pd_legality_async()
    db().execute('INSERT INTO scryfall_version (last_updated) VALUES (%s)',
                 [dtutil.dt2ts(new_date)])
    db().execute(
        'SET FOREIGN_KEY_CHECKS=1'
    )  # OK we are done monkeying with the db put the FK checks back in place and recreate _cache_card.
    rebuild_cache()
    db().commit('update_database')
예제 #14
0
def tournament_deck(cells: ResultSet, competition_id: int,
                    date: datetime.datetime,
                    final: Dict[str, int]) -> Optional[deck.Deck]:
    d: deck.RawDeckDescription = {
        'source': 'Gatherling',
        'competition_id': competition_id,
        'created_date': dtutil.dt2ts(date)
    }
    player = cells[2]
    username = aliased(player.a.contents[0].string)
    d['mtgo_username'] = username
    d['finish'] = final.get(username)
    link = cells[4].a
    d['url'] = gatherling_url(link['href'])
    d['name'] = link.string
    if cells[5].find('a'):
        d['archetype'] = cells[5].a.string
    else:
        d['archetype'] = cells[5].string
    gatherling_id = urllib.parse.parse_qs(
        urllib.parse.urlparse(str(d['url'])).query)['id'][0]
    d['identifier'] = gatherling_id
    existing = deck.get_deck_id(d['source'], d['identifier'])
    if existing is not None:
        return deck.load_deck(existing)
    dlist = decklist.parse(
        fetcher.internal.post(gatherling_url('deckdl.php'),
                              {'id': gatherling_id}))
    d['cards'] = dlist
    if len(dlist['maindeck']) + len(dlist['sideboard']) == 0:
        logger.warning(
            'Rejecting deck with id {id} because it has no cards.'.format(
                id=gatherling_id))
        return None
    return deck.add_deck(d)
예제 #15
0
 def prepare_competitions(self):
     for c in getattr(self, 'competitions', []):
         c.competition_url = url_for('competition', competition_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)
예제 #16
0
def fetch() -> None:
    all_prices, timestamps = {}, []
    ch_urls = configuration.get_list('cardhoarder_urls')
    if ch_urls:
        for _, url in enumerate(ch_urls):
            s = fetch_tools.fetch(url)
            s = ftfy.fix_encoding(s)
            timestamps.append(
                dtutil.parse_to_ts(
                    s.split('\n', 1)[0].replace('UPDATED ', ''),
                    '%Y-%m-%dT%H:%M:%S+00:00', dtutil.CARDHOARDER_TZ))
            all_prices[url] = parser.parse_cardhoarder_prices(s)
    url = configuration.get_str('mtgotraders_url')
    if url:
        s = fetch_tools.fetch(url)
        timestamps.append(dtutil.dt2ts(dtutil.now()))
        all_prices['mtgotraders'] = parser.parse_mtgotraders_prices(s)
    if not timestamps:
        raise TooFewItemsException(
            'Did not get any prices when fetching {urls} ({all_prices})'.
            format(urls=itertools.chain(
                configuration.get_list('cardhoarder_urls'),
                [configuration.get_str('mtgotraders_url')]),
                   all_prices=all_prices))
    count = store(min(timestamps), all_prices)
    cleanup(count)
예제 #17
0
def recent_json() -> Response:
    last_week = dtutil.now() - dtutil.ts2dt(7 * 24 * 60 * 60)
    val: Dict[str, Any] = {}
    val['formats'] = {}
    last_f: Dict[str, int] = {}
    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)
예제 #18
0
 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
예제 #19
0
def add_or_update_news(news_item_id: int, date: datetime.datetime, title: str,
                       url: str) -> None:
    ts = dtutil.dt2ts(date)
    if news_item_id is not None:
        update_news(news_item_id, ts, title, url)
        return
    add_news(ts, title, url)
예제 #20
0
def perfect_league_runs(start_date: datetime.datetime,
                        end_date: datetime.datetime,
                        max_items: int = sys.maxsize) -> List[Container]:
    where = "ct.name = 'League' AND d.created_date > {start_date} AND d.created_date <= {end_date}".format(
        start_date=sqlescape(dtutil.dt2ts(start_date)),
        end_date=sqlescape(dtutil.dt2ts(end_date)))
    having = 'wins >= 5 AND losses = 0'
    ds = deck.load_decks(where, having=having, limit=f'LIMIT {max_items}')
    return [
        Container({
            'date': d.active_date,
            'title': perfect_league_run_headline(d),
            'url': url_for('deck', deck_id=d.id),
            'type': 'perfect-league-run'
        }) for d in ds
    ]
예제 #21
0
 def __init__(self, notes: Iterable[Container],
              people: Iterable[Person]) -> None:
     super().__init__()
     for n in notes:
         n.date_sort = dtutil.dt2ts(n.created_date)
         n.display_date = dtutil.display_date(n.created_date)
     self.notes = notes
     self.people = people
예제 #22
0
 def prepare_deck(self, d):
     set_stars_and_top8(d)
     if d.get('colors') is not None:
         d.colors_safe = colors_html(d.colors, d.colored_symbols)
     d.person_url = '/people/{id}/'.format(id=d.person_id)
     d.date_sort = dtutil.dt2ts(d.date)
     d.display_date = dtutil.display_date(d.date)
     d.show_record = d.wins or d.losses or d.draws
     if d.competition_id:
         d.competition_url = '/competitions/{id}/'.format(
             id=d.competition_id)
     d.url = '/decks/{id}/'.format(id=d.id)
     d.export_url = '/export/{id}/'.format(id=d.id)
     d.cmc_chart_url = '/charts/cmc/{id}-cmc.png'.format(id=d.id)
     if d.is_in_current_run():
         d.active_safe = '<span class="active" title="Active in the current league">⊕</span>'
         d.stars_safe = '{active} {stars}'.format(
             active=d.active_safe, stars=d.stars_safe).strip()
         d.source_sort = '1'
     d.source_is_external = False if d.source_name == 'League' else True
     d.comp_row_len = len("{comp_name} (Piloted by {person}".format(
         comp_name=d.competition_name, person=d.person))
     if d.get('archetype_id', None):
         d.archetype_url = '/archetypes/{id}/'.format(id=d.archetype_id)
     if d.get('omw') is not None:
         d.omw = str(int(d.omw)) + '%'
     else:
         d.omw = ''
     d.has_legal_format = len(d.legal_formats) > 0
     d.pd_legal = 'Penny Dreadful' in d.legal_formats
     d.legal_icons = ''
     sets = multiverse.SEASONS
     if 'Penny Dreadful' in d.legal_formats:
         icon = rotation.last_rotation_ex()['code'].lower()
         n = sets.index(icon.upper()) + 1
         d.legal_icons += '<a href="{url}"><i class="ss ss-{code} ss-rare ss-grad">S{n}</i></a>'.format(
             url='/seasons/{id}/'.format(id=n), code=icon, n=n)
     past_pd_formats = [
         fmt.replace('Penny Dreadful ', '') for fmt in d.legal_formats
         if 'Penny Dreadful ' in fmt
     ]
     past_pd_formats.sort(key=lambda code: -sets.index(code))
     for code in past_pd_formats:
         n = sets.index(code.upper()) + 1
         d.legal_icons += '<a href="{url}"><i class="ss ss-{set} ss-common ss-grad">S{n}</i></a>'.format(
             url='/seasons/{id}/'.format(id=n), set=code.lower(), n=n)
     if 'Commander' in d.legal_formats:  # I think C16 looks the nicest.
         d.legal_icons += '<i class="ss ss-c16 ss-uncommon ss-grad">CMDR</i>'
     if session.get('admin') or not d.is_in_current_run():
         d.decklist = str(d).replace('\n', '<br>')
     else:
         d.decklist = ''
     total, num_cards = 0, 0
     for c in d.maindeck:
         if 'Land' not in c['card'].type:
             num_cards += c['n']
             total += c['n'] * c['card'].cmc
     d.average_cmc = round(total / max(1, num_cards), 2)
예제 #23
0
def cleanup(count: int = 0) -> 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)
    limit = ''
    if count > 0:
        limit = f'LIMIT {count * 2}'
    execute('DELETE FROM low_price WHERE `time` < %s ' + limit,
            [dtutil.dt2ts(oldest_needed)])
예제 #24
0
def test_determine_end_of_league() -> None:
    next_rotation = dtutil.parse('2018-02-01 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    start_date = dtutil.parse('2017-11-01 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date, next_rotation)
    assert dtutil.dt2ts(end_date) == 1512115199
    start_date = dtutil.parse('2017-10-31 11:59:59.999', '%Y-%m-%d %H:%M:%S.%f', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date, next_rotation)
    assert dtutil.dt2ts(end_date) == 1512115199
    next_rotation = dtutil.parse('2018-07-13 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    start_date = dtutil.parse('2018-05-31 11:04:15', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date, next_rotation)
    assert dtutil.dt2ts(end_date) == dtutil.dt2ts(next_rotation) - 1
    start_date = dtutil.parse('2018-07-13 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date, next_rotation)
    assert end_date == dtutil.parse('2018-07-31 23:59:59', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    start_date = dtutil.parse('2018-08-01 00:00:00', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
    end_date = league.determine_end_of_league(start_date, next_rotation)
    assert end_date == dtutil.parse('2018-08-31 23:59:59', '%Y-%m-%d %H:%M:%S', dtutil.WOTC_TZ)
예제 #25
0
def active_competition_id_query():
    return """
        SELECT id FROM competition
        WHERE
            start_date < {now}
        AND
            end_date > {now}
        AND
            id IN ({competition_ids_by_type_select})
        """.format(now=dtutil.dt2ts(dtutil.now()), competition_ids_by_type_select=query.competition_ids_by_type_select('League'))
예제 #26
0
def after_request(response: Response) -> Response:
    requests_until_no_intro = 20  # Typically ten page views because of async requests for the status bar.
    views = int(request.cookies.get('views', 0)) + 1
    response.set_cookie('views', str(views))
    if views >= requests_until_no_intro:
        response.set_cookie('hide_intro',
                            value=str(True),
                            expires=dtutil.dt2ts(dtutil.now()) +
                            60 * 60 * 24 * 365 * 10)
    return response
예제 #27
0
    async def post_cards(self, cards, channel, replying_to=None, additional_text=''):
        await self.client.send_typing(channel)

        not_pd = configuration.get('not_pd').split(',')
        disable_emoji = False
        if channel.id in not_pd: # or (channel.server and channel.server.id in not_pd):
            disable_emoji = True

        if len(cards) == 0:
            if replying_to is not None:
                text = '{author}: No matches.'.format(author=replying_to.mention)
            else:
                text = 'No matches.'
            await self.client.send_message(channel, text)
            return
        cards = command.uniqify_cards(cards)
        more_text = ''
        if len(cards) > 10:
            more_text = ' and ' + str(len(cards) - 4) + ' more.'
            cards = cards[:4]
        if len(cards) == 1:
            card = cards[0]
            mana = emoji.replace_emoji(''.join(card.mana_cost or []), self.client)
            legal = ' — ' + emoji.legal_emoji(card, True)
            if disable_emoji:
                legal = ''
            text = '{name} {mana} — {type}{legal}'.format(name=card.name, mana=mana, type=card.type, legal=legal)
            if card.bug_desc is not None:
                text += '\n:beetle:{rank} bug: {bug}'.format(bug=card.bug_desc, rank=card.bug_class)
                now_ts = dtutil.dt2ts(dtutil.now())
                if card.bug_last_confirmed < now_ts - 60 * 60 * 24 * 60:
                    text += ' (Last confirmed {time} ago.)'.format(time=dtutil.display_time(now_ts - card.bug_last_confirmed, 1))
        else:
            text = ', '.join('{name} {legal}'.format(name=card.name, legal=(emoji.legal_emoji(card)) if not disable_emoji else '') for card in cards)
            text += more_text
        if len(cards) > 10:
            image_file = None
        else:
            image_file = image_fetcher.download_image(cards)
        if image_file is None:
            text += '\n\n'
            if len(cards) == 1:
                text += emoji.replace_emoji(cards[0].text, self.client)
            else:
                text += 'No image available.'
        text += '\n' + additional_text
        if image_file is None:
            await self.client.send_message(channel, text)
        else:
            message = await self.client.send_file(channel, image_file, content=text)
            if message and message.attachments and message.attachments[0]['size'] == 0:
                print('Message size is zero so resending')
                await self.client.delete_message(message)
                await self.client.send_file(channel, image_file, content=text)
예제 #28
0
 def prepare_deck(self, d: Deck) -> None:
     set_stars_and_top8(d)
     if d.get('colors') is not None:
         d.colors_safe = colors_html(d.colors, d.colored_symbols)
     d.person_url = '/people/{id}/'.format(id=d.person_id)
     d.date_sort = dtutil.dt2ts(d.active_date)
     d.display_date = dtutil.display_date(d.active_date)
     d.show_record = d.wins or d.losses or d.draws
     if d.competition_id:
         d.competition_url = '/competitions/{id}/'.format(id=d.competition_id)
     d.url = '/decks/{id}/'.format(id=d.id)
     d.export_url = '/export/{id}/'.format(id=d.id)
     d.cmc_chart_url = '/charts/cmc/{id}-cmc.png'.format(id=d.id)
     if d.is_in_current_run():
         d.active_safe = '<span class="active" title="Active in the current league">⊕</span>'
         d.stars_safe = '{active} {stars}'.format(active=d.active_safe, stars=d.stars_safe).strip()
         d.source_sort = '1'
     d.source_is_external = not d.source_name == 'League'
     d.comp_row_len = len('{comp_name} (Piloted by {person}'.format(comp_name=d.competition_name, person=d.person))
     if d.get('archetype_id', None):
         d.archetype_url = '/archetypes/{id}/'.format(id=d.archetype_id)
     # We might be getting '43%'/'' from cache or '43'/None from the db. Cope with all possibilities.
     # It might be better to use display_omw and omw as separate properties rather than overwriting the numeric value.
     if d.get('omw') is None or d.omw == '':
         d.omw = ''
     elif '%' not in str(d.omw):
         d.omw = str(int(d.omw)) + '%'
     d.has_legal_format = len(d.legal_formats) > 0
     d.pd_legal = 'Penny Dreadful' in d.legal_formats
     d.legal_icons = ''
     sets = rotation.SEASONS
     if 'Penny Dreadful' in d.legal_formats:
         icon = rotation.current_season_code().lower()
         n = sets.index(icon.upper()) + 1
         d.legal_icons += '<a href="{url}"><i class="ss ss-{code} ss-rare ss-grad">S{n}</i></a>'.format(url='/seasons/{id}/'.format(id=n), code=icon, n=n)
     past_pd_formats = [fmt.replace('Penny Dreadful ', '') for fmt in d.legal_formats if 'Penny Dreadful ' in fmt]
     past_pd_formats.sort(key=lambda code: -sets.index(code))
     for code in past_pd_formats:
         n = sets.index(code.upper()) + 1
         d.legal_icons += '<a href="{url}"><i class="ss ss-{set} ss-common ss-grad">S{n}</i></a>'.format(url='/seasons/{id}/'.format(id=n), set=code.lower(), n=n)
     if 'Commander' in d.legal_formats: # I think C16 looks the nicest.
         d.legal_icons += '<i class="ss ss-c16 ss-uncommon ss-grad">CMDR</i>'
     if session.get('admin') or session.get('demimod') or not d.is_in_current_run():
         d.decklist = str(d).replace('\n', '<br>')
     else:
         d.decklist = ''
     total, num_cards = 0, 0
     for c in d.maindeck:
         if c.card.cmc is None:
             c.card.cmc = 0
         if 'Land' not in c.card.type_line:
             num_cards += c['n']
             total += c['n'] * c.card.cmc
     d.average_cmc = round(total / max(1, num_cards), 2)
예제 #29
0
 def prepare_matches(self) -> None:
     for m in getattr(self, 'matches', []):
         if m.get('date'):
             m.display_date = dtutil.display_date(m.date)
             m.date_sort = dtutil.dt2ts(m.date)
         if m.get('deck_id'):
             m.deck_url = url_for('deck', deck_id=m.deck_id)
         if m.get('opponent'):
             m.opponent_url = url_for('person', person_id=m.opponent)
         if m.get('opponent_deck_id'):
             m.opponent_deck_url = url_for('deck', deck_id=m.opponent_deck_id)
예제 #30
0
def stats() -> Dict[str, int]:
    sql = """
        SELECT
            SUM(CASE WHEN FROM_UNIXTIME(`date`) >= NOW() - INTERVAL 1 DAY THEN 1 ELSE 0 END) AS num_matches_today,
            SUM(CASE WHEN FROM_UNIXTIME(`date`) >= NOW() - INTERVAL 7 DAY THEN 1 ELSE 0 END) AS num_matches_this_week,
            SUM(CASE WHEN FROM_UNIXTIME(`date`) >= NOW() - INTERVAL 30 DAY THEN 1 ELSE 0 END) AS num_matches_this_month,
            SUM(CASE WHEN `date` >= %s THEN 1 ELSE 0 END) AS num_matches_this_season,
            COUNT(*) AS num_matches_all_time
        FROM
            `match`
    """
    return db().select(sql, [dtutil.dt2ts(rotation.last_rotation())])[0]