def __init__(self, stats: Dict[int, Dict[str, Union[int, datetime.datetime]]]) -> None: super().__init__() seasons = self.all_seasons() seasons.pop() # Don't show "all time" on this page as it is not fully supported yet. cards_count: Dict[str, int] = {} for c in oracle.CARDS_BY_NAME.values(): for f, is_legal in c.legalities.items(): if is_legal and 'Penny Dreadful' in f: cards_count[f] = cards_count.get(f, 0) + 1 self.seasons: List[Dict[str, Any]] = [] for season_info in seasons: season: Dict[str, Any] = {} season.update(season_info) season_stats = stats.get(cast(int, season['num']), {}) season.update(season_stats) if season.get('start_date') is None: continue season['num_legal_cards'] = cards_count[str(season_info['legality_name'])] for k, v in season.items(): if isinstance(v, int): season[k] = '{:,}'.format(v) # Human-friendly number formatting like "29,000". season['start_date_display'] = dtutil.display_date(season['start_date']) season['length_in_days'] = season['length_in_days'] + ' days' if season.get('end_date'): season['end_date_display'] = dtutil.display_date(season['end_date']) else: season['end_date_display'] = 'Now' season['length_in_days'] += ' so far' self.seasons.append(season)
def __init__( self, stats: Dict[int, Dict[str, Union[int, datetime.datetime]]]) -> None: super().__init__() seasons = self.all_seasons() seasons.pop( ) # Don't show "all time" on this page as it is not fully supported yet. self.seasons: List[Dict[str, Any]] = [] for season_info in seasons: season: Dict[str, Any] = {} season.update(season_info) season_stats = stats.get(cast(int, season['num']), {}) season.update(season_stats) if season.get('start_date') is None: continue for k, v in season.items(): if isinstance(v, int): season[k] = '{:,}'.format( v) # Human-friendly number formatting like "29,000". season['start_date_display'] = dtutil.display_date( season['start_date']) season['length_in_days'] = season['length_in_days'] + ' days' if season.get('end_date'): season['end_date_display'] = dtutil.display_date( season['end_date']) else: season['end_date_display'] = 'Now' season['length_in_days'] += ' so far' self.seasons.append(season)
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)
def __init__(self, interestingness: Optional[str] = None, rotation_query: Optional[str] = None, only_these: Optional[List[str]] = None) -> None: super().__init__() self.playability = card.playability() until_full_rotation = rotation.next_rotation() - dtutil.now() until_supplemental_rotation = rotation.next_supplemental() - dtutil.now() in_rotation = configuration.get_bool('always_show_rotation') if until_full_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2) elif until_supplemental_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2) elif until_full_rotation < until_supplemental_rotation: self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2) else: self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2) self.cards: List[Card] = [] if in_rotation: self.read_rotation_files() self.show_interesting = True if interestingness: self.cards = [c for c in self.cards if c.get('interestingness') == interestingness] if only_these: self.cards = [c for c in self.cards if c.name in only_these] self.num_cards = len(self.cards) self.rotation_query = rotation_query or ''
def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None: super().__init__() until_rotation = seasons.next_rotation() - dtutil.now() in_rotation = configuration.get_bool('always_show_rotation') if until_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Rotation is in progress, ends ' + dtutil.display_date(seasons.next_rotation(), 2) else: self.rotation_msg = 'Rotation is ' + dtutil.display_date(seasons.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 self.cards = [c for c in self.cards if visible(c)]
def __init__(self) -> None: super().__init__() self.playability = card.playability() until_full_rotation = rotation.next_rotation() - dtutil.now() until_supplemental_rotation = rotation.next_supplemental( ) - dtutil.now() in_rotation = False if until_full_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date( rotation.next_rotation(), 2) elif until_supplemental_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date( rotation.next_supplemental(), 2) elif until_full_rotation < until_supplemental_rotation: self.rotation_msg = 'Full rotation is ' + dtutil.display_date( rotation.next_rotation(), 2) else: self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date( rotation.next_supplemental(), 2) self.cards: List[Card] = [] if in_rotation: self.read_rotation_files() self.show_interesting = True
def setup_rotation(self) -> None: self.season_start_display = dtutil.display_date(seasons.last_rotation()) self.season_end_display = dtutil.display_date(seasons.next_rotation()) self.scryfall_url = 'https://scryfall.com/search?q=f%3Apd' self.legal_cards_url = 'http://pdmtgo.com/legal_cards.txt' self.in_rotation = rotation.in_rotation() self.rotation_msg = 'Rotation is in progress.' self.rotation_url = url_for('rotation')
def prepare_competitions(self) -> None: 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.competition_ends = '' if c.end_date < dtutil.now() else dtutil.display_date(c.end_date) c.date_sort = dtutil.dt2ts(c.start_date) c.league = c.type == 'League' 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()
def load_notes(person_id: int = None) -> List[Container]: where = f'subject_id = {person_id}' if person_id else 'TRUE' sql = """ SELECT pn.created_date, pn.creator_id, {creator_query} AS creator, pn.subject_id, {subject_query} AS subject, note FROM person_note AS pn INNER JOIN person AS c ON pn.creator_id = c.id INNER JOIN person AS s ON pn.subject_id = s.id WHERE {where} ORDER BY s.id, pn.created_date DESC """.format(creator_query=query.person_query('c'), subject_query=query.person_query('s'), where=where) notes = [Container(r) for r in db().select(sql)] for n in notes: n.created_date = dtutil.ts2dt(n.created_date) n.display_date = dtutil.display_date(n.created_date) return notes
def all_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() news: List[Container] = [] news += load_news(start_date, end_date, max_items) news += tournament_winners(start_date, end_date, max_items) news += perfect_league_runs(start_date, end_date, max_items) news += code_merges(start_date, end_date, max_items) news += subreddit(start_date, end_date, max_items) news = sorted(news, key=lambda item: item.date, reverse=True) results = [] for item in news: if item.date > end_date: continue if item.date < start_date: break item.display_date = dtutil.display_date(item.date) results.append(item) if len(results) >= max_items: break return results
def load_news(start_date=0, end_date=sys.maxsize, max_items=sys.maxsize): sql = """ SELECT id, `date`, title, body FROM news_item WHERE `date` >= %s AND `date` <= %s ORDER BY `date` DESC LIMIT %s """ results = [ Container(r) for r in db().execute(sql, [start_date, 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) return results
def __init__(self, d): self._deck = d self.prepare_deck(self._deck) self.cards = d.all_cards() # This is called 'decks' and not something more sane because of limitations of Mustache and our desire to use a partial for decktable. self.decks = deck.get_similar_decks(d) self.has_similar = len(self.decks) > 0 self.matches = deck.get_matches(d, True) for m in self.matches: m.display_date = dtutil.display_date(m.date) if m.opponent: m.opponent_url = url_for('person', person_id=m.opponent) else: m.opponent = 'BYE' m.opponent_url = False if m.opponent_deck_id: m.opponent_deck_url = url_for('decks', deck_id=m.opponent_deck_id) else: m.opponent_deck_url = False if m.opponent_deck: m.opponent_deck_name = deck_name.normalize(m.opponent_deck) else: m.opponent_deck_name = '-' if self.has_rounds(): m.display_round = display_round(m) self._deck['maindeck'].sort(key=lambda x: oracle.deck_sort(x['card'])) self._deck['sideboard'].sort(key=lambda x: oracle.deck_sort(x['card'])) self.admin = session.get('admin', False) if self.admin: self.archetypes = archetype.load_archetypes_deckless( order_by='a.name') self.edit_archetype_url = url_for('edit_archetypes') self.cardhoarder_url = fetcher.cardhoarder_url(d)
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
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
def __init__(self): until_full_rotation = rotation.next_rotation() - dtutil.now() until_supplemental_rotation = rotation.next_supplemental() - dtutil.now() in_rotation = False if until_full_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2) elif until_supplemental_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2) elif until_full_rotation < until_supplemental_rotation: self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2) else: self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2) if in_rotation: self.read_rotation_files() self.show_interesting = True
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)
def __init__(self) -> None: super().__init__() until_rotation = seasons.next_rotation() - dtutil.now() in_rotation = configuration.get_bool('always_show_rotation') if until_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Rotation is in progress, ends ' + dtutil.display_date( seasons.next_rotation(), 2) else: self.rotation_msg = 'Rotation is ' + dtutil.display_date( seasons.next_rotation(), 2) if in_rotation: self.in_rotation = in_rotation self.runs, self.runs_percent, self.cards = rotation.read_rotation_files( ) else: self.cards = [] self.num_cards = len(self.cards)
def test_display_date() -> None: dt = dtutil.parse('2008-03-29', '%Y-%m-%d', dtutil.WOTC_TZ) assert dtutil.display_date(dt) == 'Mar 2008' dt = dtutil.parse('2008-03-29 02:00', '%Y-%m-%d %H:%M', timezone('UTC')) assert dtutil.display_date(dt) == 'Mar 2008' dt = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(seconds=10) assert dtutil.display_date(dt).find('seconds ago') >= 0 dt = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=72) assert dtutil.display_date(dt).find('days') >= 0 assert dtutil.display_date(dt).find('from now') >= 0 assert dtutil.display_date(dt).find('ago') == -1 dt = datetime.datetime.now(datetime.timezone.utc) assert dtutil.display_date(dt).find('just now') >= 0 assert dtutil.display_date(dt).find('from now') == -1 dt = datetime.datetime.now(dtutil.WOTC_TZ) + datetime.timedelta(days=28, hours=15, minutes=35) assert dtutil.display_date(dt) == '4 weeks from now'
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)
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)
def prepare_deck(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) if d.get('mtgo_username'): d.person_url = f'/people/{d.mtgo_username}/' else: d.person_url = f'/people/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.non_pd_legal_formats = { f for f in d.legal_formats if 'Penny Dreadful' not in f } set_legal_icons(d) if session.get('admin') or session.get( 'demimod') or not d.is_in_current_run(): d.decklist = str(d) 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)
def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None: super().__init__() until_full_rotation = rotation.next_rotation() - dtutil.now() until_supplemental_rotation = rotation.next_supplemental() - dtutil.now() in_rotation = configuration.get_bool('always_show_rotation') if until_full_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2) elif until_supplemental_rotation < datetime.timedelta(7): in_rotation = True self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2) elif until_full_rotation < until_supplemental_rotation: self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2) else: self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 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 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) self.show_filters_toggle = True
def __init__(self, competition: Comp) -> None: super().__init__() self.competition = competition self.competitions = [self.competition] self.decks = competition.decks self.hide_source = True self.has_external_source = competition.type != 'League' if competition.type == 'League': self.skinny_leaderboard = True # Try and bunch it up on the right of decks table if at all possible. self.show_omw = True self.hide_top8 = True self.has_leaderboard = True self.date = dtutil.display_date(competition.start_date) self.sponsor_name = competition.sponsor_name
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 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)) 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 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.name = deck_name.normalize(d) d.person_url = url_for('person', person_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 = url_for('competition', competition_id=d.competition_id) d.url = url_for('decks', deck_id=d.id) d.export_url = url_for('export', deck_id=d.id) d.cmc_chart_url = url_for('cmc_chart', deck_id=d.id) if d.source_name == 'League' and d.wins + d.losses < 5 and d.competition_end_date > dtutil.now( ) and not d.get('retired', False): d.stars_safe = '<span title="Active in the current league">⊕</span> {stars}'.format( stars=d.stars_safe).strip() d.source_sort = '1' 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 = url_for('archetype', archetype_id=d.archetype_id) if d.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 = legality.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=url_for('season', season_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=url_for('season', season_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>' d.decklist = str(d).replace('\n', '<br>')
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) if m.get('mtgo_id'): m.log_url = fetcher.logsite_url( '/match/{id}/'.format(id=m.get('mtgo_id')))
def __init__(self, matches) -> None: super().__init__() self.matches = matches if matches: deck_ids = [m.left_id for m in self.matches] + [m.right_id for m in self.matches if m.right_id is not None] decks_by_id = {int(d.id): d for d in deck.load_decks('d.id IN ({deck_ids})'.format(deck_ids=', '.join(deck_ids)))} for m in self.matches: m.display_date = dtutil.display_date(m.date) m.left_deck = decks_by_id.get(int(m.left_id)) m.right_deck = decks_by_id.get(int(m.right_id)) m.left_url = url_for('deck', deck_id=m.left_id) if m.get('right_url'): m.right_url = url_for('deck', deck_id=m.right_id) else: m.right_url = None
def __init__(self, decks: List[Deck], matches: List[Container]) -> None: super().__init__() self.matches = matches self.hide_active_runs = False self.decks = sorted(decks, key=lambda d: d.person + str(d.created_date)) decks_by_id = {d.id: d for d in decks} for m in self.matches: m.display_date = dtutil.display_date(m.date) m.left_deck = decks_by_id.get(int(m.left_id)) m.right_deck = decks_by_id.get(int(m.right_id)) m.left_url = url_for('deck', deck_id=m.left_id) if m.get('right_id'): m.right_url = url_for('deck', deck_id=m.right_id) else: m.right_url = None
def prepare_matches(ms: Sequence[Container]) -> None: for m in ms: if m.get('date'): m.display_date = dtutil.display_date(m.date) m.date_sort = dtutil.dt2ts(m.date) if m.get('person'): m.person_url = url_for('person', mtgo_username=m.person) 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', mtgo_username=m.opponent) if m.get('opponent_deck_id'): m.opponent_deck_url = url_for('deck', deck_id=m.opponent_deck_id) if m.get('mtgo_id'): m.log_url = fetcher.logsite_url( '/match/{id}/'.format(id=m.get('mtgo_id')))
def __init__(self, d: deck.Deck, person_id: Optional[int] = None, discord_id: Optional[int] = None) -> None: super().__init__() self.deck = d self.prepare_deck(self.deck) self.cards = d.all_cards() if not self.deck.is_in_current_run(): deck.load_similar_decks([d]) # This is called 'decks' and not something more sane because of limitations of Mustache and our desire to use a partial for decktable. self.decks = [ sd for sd in d.similar_decks if not sd.is_in_current_run() ] else: self.decks = [] self.has_similar = len(self.decks) > 0 self.matches = match.get_matches(d, True) for m in self.matches: m.display_date = dtutil.display_date(m.date) if m.opponent: m.opponent_url = url_for('person', person_id=m.opponent) else: m.opponent = 'BYE' m.opponent_url = False if m.opponent_deck_id: m.opponent_deck_url = url_for('deck', deck_id=m.opponent_deck_id) else: m.opponent_deck_url = False if m.opponent_deck and m.opponent_deck.is_in_current_run(): m.opponent_deck_name = '(Active League Run)' elif m.opponent_deck: m.opponent_deck_name = m.opponent_deck.name else: m.opponent_deck_name = '-' if self.has_rounds(): m.display_round = display_round(m) self.deck['maindeck'].sort(key=lambda x: oracle.deck_sort(x['card'])) self.deck['sideboard'].sort(key=lambda x: oracle.deck_sort(x['card'])) self.archetypes = archetype.load_archetypes_deckless(order_by='a.name') self.edit_archetype_url = url_for('edit_archetypes') self.legal_formats = list( sorted(d.legal_formats, key=legality.order_score)) self.is_in_current_run = d.is_in_current_run() self.person_id = person_id self.discord_id = discord_id