def person_api(person):
    try:
        p = ps.load_person(person)
        p.decks_url = url_for('person_decks_api', person=person)
        p.head_to_head = url_for('person_h2h_api', person=person)
        return return_json(p)
    except DoesNotExistException:
        return return_json(generate_error('NOTFOUND', 'Person does not exist'))
def random_deck_api() -> Response:
    blob = league.random_legal_deck()
    if blob is None:
        return return_json({
            'error': True,
            'msg': 'No legal decks could be found'
        })
    blob['url'] = url_for('deck', deck_id=blob['id'], _external=True)
    return return_json(blob)
def person_api(person: str, season_id: int = -1) -> Response:
    if season_id == -1:
        season_id = rotation.current_season_num()
    try:
        p = ps.load_person_by_discord_id_or_username(person, season_id)
        p.decks_url = url_for('person_decks_api', person=person, season_id=season_id)
        p.head_to_head = url_for('person_h2h_api', person=person, season_id=season_id)
        return return_json(p)
    except DoesNotExistException:
        return return_json(generate_error('NOTFOUND', 'Person does not exist'))
Beispiel #4
0
def search() -> Response:
    init_search_cache()
    q = request.args.get('q', '').lower()
    results: List[SearchItem] = []
    if len(q) < 2:
        return return_json(results)
    for item in SEARCH_CACHE:
        if q in item['name'].lower():
            results.append(item)
    return return_json(results)
def league_run_api(person):
    decks = league.active_decks_by(person)
    if len(decks) == 0:
        return return_json(None)

    run = guarantee_at_most_one_or_retire(decks)

    decks = league.active_decks()
    already_played = [m.opponent_deck_id for m in match.get_matches(run)]
    run.can_play = [d.person for d in decks if d.person != person and d.id not in already_played]

    return return_json(run)
def drop(person):
    error = validate_api_key()
    if error:
        return error

    decks = league.active_decks_by(person)
    if len(decks) == 0:
        return return_json(generate_error('NO_ACTIVE_RUN', 'That person does not have an active run'))

    run = guarantee.exactly_one(decks)

    league.retire_deck(run)
    result = {'success':True}
    return return_json(result)
def league_api() -> Response:
    lg = league.active_league(should_load_decks=True)
    pdbot = request.form.get('api_token',
                             None) == configuration.get('pdbot_api_token')
    if not pdbot:
        lg.decks = [d for d in lg.decks if not d.is_in_current_run()]
    return return_json(lg)
def person_decks_api(person: str, season_id: int = 0) -> Response:
    p = ps.load_person_by_discord_id_or_username(person, season_id=season_id)
    blob = {
        'name': p.name,
        'decks': p.decks,
    }
    return return_json(blob)
Beispiel #9
0
def person_status():
    r = {
        'mtgo_username':
        auth.mtgo_username(),
        'discord_id':
        auth.discord_id(),
        'admin':
        session.get('admin', False),
        'demimod':
        session.get('demimod', False),
        'hide_intro':
        request.cookies.get('hide_intro', False) or auth.hide_intro()
        or auth.mtgo_username() or auth.discord_id(),
        'in_guild':
        session.get('in_guild', False),
    }
    if auth.mtgo_username():
        d = guarantee_at_most_one_or_retire(
            league.active_decks_by(auth.mtgo_username()))
        if d is not None:
            r['deck'] = {
                'name': d.name,
                'url': url_for('deck', deck_id=d.id),
                'wins': d.get('wins', 0),
                'losses': d.get('losses', 0)
            }
    if r['admin'] or r['demimod']:
        r['archetypes_to_tag'] = len(deck.load_decks('NOT d.reviewed'))
    return return_json(r)
Beispiel #10
0
def person_status() -> Response:
    r = {
        'mtgo_username': session.get('mtgo_username'),
        'discord_id': session.get('discord_id'),
        'admin': session.get('admin', False),
        'hide_intro': request.cookies.get('hide_intro', False),
    }
    return return_json(r)
Beispiel #11
0
def upload() -> Response:
    error = validate_api_key()
    if error:
        return error
    match_id = int(request.form['match_id'])
    if match_id == 219603564:
        return return_json({'success': True})  # Prevent infinite 500 errors.
    if request.form.get('lines'):
        lines = request.form['lines']
        importing.import_log(lines.split('\n'), match_id)
    else:
        importing.import_from_pdbot(match_id)
    start_time = int(request.form['start_time_utc'])
    end_time = int(request.form['end_time_utc'])
    match.get_match(match_id).set_times(start_time, end_time)

    return return_json({'success': True})
def all_achievements() -> Response:
    data = {}
    data['achievements'] = [{
        'key': a.key,
        'title': a.title,
        'description': a.description_safe
    } for a in Achievement.all_achievements]
    return return_json(data)
def rotation_api() -> Response:
    now = dtutil.now()
    diff = rotation.next_rotation() - now
    result = {
        'last': rotation.last_rotation_ex(),
        'next': rotation.next_rotation_ex(),
        'diff': diff.total_seconds(),
        'friendly_diff': dtutil.display_time(diff.total_seconds())
    }
    return return_json(result)
def decks_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of decks.
    Input:
        {
            'archetypeId': <int?>,
            'cardName': <str?>,
            'competitionId': <int?>,
            'personId': <int?>,
            'deckType': <'league'|'tournament'|'all'>,
            'page': <int>,
            'pageSize': <int>,
            'personId': <int?>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'>
        }
    Output:
        {
            'page': <int>,
            'pages': <int>,
            'decks': [<deck>]
        }
    """
    if not request.args.get('sortBy') and request.args.get('competitionId'):
        sort_by = 'top8'
        sort_order = 'ASC'
    elif not request.args.get('sortBy'):
        sort_by = 'date'
        sort_order = 'DESC'
    else:
        sort_by = str(request.args.get('sortBy'))
        sort_order = str(request.args.get('sortOrder'))
    assert sort_order in ['ASC', 'DESC']
    order_by = query.decks_order_by(sort_by, sort_order)
    page_size = int(request.args.get('pageSize', 20))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    # Don't restrict by season if we're loading something with a date by its id.
    season_id = 'all' if request.args.get(
        'competitionId') else rotation.season_id(
            str(request.args.get('seasonId')), None)
    where = query.decks_where(request.args, session.get('person_id'))
    total = deck.load_decks_count(where=where, season_id=season_id)
    pages = max(ceil(total / page_size) - 1, 0)  # 0-indexed
    ds = deck.load_decks(where=where,
                         order_by=order_by,
                         limit=limit,
                         season_id=season_id)
    prepare_decks(ds)
    r = {'page': page, 'pages': pages, 'decks': ds}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #15
0
def leaderboards_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of leaderboard entries.
    Input:
        {
            'competitionId': <int?>,
            'competitionSeriesId': <int?>
            'page': <int>,
            'pageSize': <int>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'?>,
            'q': <str>
        }
    Output:
        {
            'page': <int>,
            'objects': [<entry>],
            'total': <int>
        }
    """
    order_by = query.leaderboard_order_by(request.args.get('sortBy'),
                                          request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'

    q = request.args.get('q', '').strip()
    where = query.text_match_where(query.person_query(), q) if q else 'TRUE'
    try:
        competition_id = int(request.args.get('competitionId', ''))
        where += f' AND (c.id = {competition_id})'
        season_id = None
    except ValueError:
        season_id = seasons.season_id(str(request.args.get('seasonId')), None)
    try:
        competition_series_id = int(request.args.get('competitionSeriesId',
                                                     ''))
        where += f' AND (cs.id = {competition_series_id})'
    except ValueError:
        pass
    entries = comp.load_leaderboard(where=where,
                                    group_by='p.id',
                                    order_by=order_by,
                                    limit=limit,
                                    season_id=season_id)
    prepare_leaderboard(entries)
    total = comp.load_leaderboard_count(where=where, season_id=season_id)
    r = {'page': page, 'total': total, 'objects': entries}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #16
0
def upload() -> Response:
    error = validate_api_key()
    if error:
        return error
    match_id = int(request.form['match_id'])
    lines = request.form['lines']
    importing.import_log(lines.split('\n'), match_id)
    start_time = int(request.form['start_time_utc'])
    end_time = int(request.form['end_time_utc'])
    match.get_match(match_id).set_times(start_time, end_time)

    return return_json({'success': True})
def competitions_api() -> Response:
    # Don't send competitions with any decks that do not have their correct archetype to third parties otherwise they
    # will store it and be wrong forever.
    comps = comp.load_competitions(having='num_reviewed = num_decks', should_load_decks=True)
    r = []
    for c in comps:
        if c.decks:
            cr = {}
            cr['id'] = c.id
            cr['name'] = c.name
            cr['url'] = url_for('competition_api', competition_id=c.id, _external=True)
            r.append(cr)
    return return_json(r) # type: ignore
Beispiel #18
0
def matches_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of matches.
    Input:
        {
            'competitionId': <int?>,
            'page': <int>,
            'pageSize': <int>,
            'q': <str>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'?>
        }
    Output:
        {
            'page': <int>,
            'objects': [<entry>],
            'total': <int>
        }
    """
    order_by = query.matches_order_by(request.args.get('sortBy'),
                                      request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    q = request.args.get('q', '').strip()
    person_where = query.text_match_where(query.person_query(),
                                          q) if q else 'TRUE'
    opponent_where = query.text_match_where(query.person_query('o'),
                                            q) if q else 'TRUE'
    where = f'({person_where} OR {opponent_where})'
    try:
        competition_id = int(request.args.get('competitionId', ''))
        where += f' AND (c.id = {competition_id})'
        season_id = None
    except ValueError:
        season_id = seasons.season_id(str(request.args.get('seasonId')), None)
    entries = match.load_matches(where=where,
                                 order_by=order_by,
                                 limit=limit,
                                 season_id=season_id,
                                 show_active_deck_names=session.get(
                                     'admin', False))
    prepare_matches(entries)
    total = match.load_matches_count(where=where, season_id=season_id)
    r = {'page': page, 'total': total, 'objects': entries}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
def deck_embed(deck_id: int) -> Response:
    # Discord doesn't actually show this yet.  I've reached out to them for better documentation about what they do/don't accept.
    d = deck.load_deck(deck_id)
    view = DeckEmbed(d, None, None)
    width = 1200
    height = 500
    embed = {
        'type': 'rich',
        'version': '1.0',
        'title': view.page_title(),
        'width': width,
        'height': height,
        'html': template.render(view)
    }
    return return_json(embed)
Beispiel #20
0
def h2h_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of head-to-head entries.
    Input:
        {
            'page': <int>,
            'pageSize': <int>,
            'personId': <int>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'>,
            'q': <str>
        }
    Output:
        {
            'page': <int>,
            'objects': [<entry>],
            'total': <int>
        }
    """
    order_by = query.head_to_head_order_by(request.args.get('sortBy'),
                                           request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    season_id = seasons.season_id(str(request.args.get('seasonId')), None)
    person_id = int(request.args.get('personId', 0))
    q = request.args.get('q', '').strip()
    where = query.text_match_where('opp.mtgo_username', q) if q else 'TRUE'
    entries = ps.load_head_to_head(person_id,
                                   where=where,
                                   order_by=order_by,
                                   limit=limit,
                                   season_id=season_id)
    for entry in entries:
        entry.opp_url = url_for('.person',
                                mtgo_username=entry.opp_mtgo_username,
                                season_id=None if season_id
                                == seasons.current_season_num() else season_id)
    total = ps.load_head_to_head_count(person_id=person_id,
                                       where=where,
                                       season_id=season_id)
    r = {'page': page, 'total': total, 'objects': entries}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #21
0
def cards2_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of cards.
    Input:
        {
            'deckType': <'league'|'tournament'|'all'>,
            'page': <int>,
            'pageSize': <int>,
            'personId': <int?>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'>,
            'q': <str>
        }
    Output:
        {
            'page': <int>,
            'objects': [<card>],
            'total': <int>
        }
    """
    order_by = query.cards_order_by(request.args.get('sortBy'),
                                    request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    person_id = request.args.get('personId') or None
    tournament_only = request.args.get('deckType') == 'tournament'
    season_id = seasons.season_id(str(request.args.get('seasonId')), None)
    q = request.args.get('q', '').strip()
    additional_where = query.card_search_where(q) if q else 'TRUE'
    cs = card.load_cards(additional_where=additional_where,
                         order_by=order_by,
                         limit=limit,
                         person_id=person_id,
                         tournament_only=tournament_only,
                         season_id=season_id)
    prepare_cards(cs, tournament_only=tournament_only)
    total = card.load_cards_count(additional_where=additional_where,
                                  person_id=person_id,
                                  season_id=season_id)
    r = {'page': page, 'total': total, 'objects': cs}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #22
0
def rotation_cards_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of cards that are potentially rotating in.
    Input:
        {
            'page': <int>,
            'pageSize': <int>,
            'q': <str>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>
        }
    Output:
        {
            'page': <int>,
            'objects': [<entry>],
            'total': <int>
        }
    """
    _, _, cs = rotation.read_rotation_files()
    q = request.args.get('q', '').lower()
    search_results = None
    try:
        search_results = [c.name for c in card_search.search(q)] if q else None
    except card_search.InvalidSearchException:
        pass
    if search_results is not None:
        cs = [c for c in cs if c.name in search_results]
    if not session.get('admin', False):
        cs = [c for c in cs if c.status != 'Undecided']
    total = len(cs)
    # Now add interestingness to the cards, which only decksite knows not magic.rotation.
    playability = card.playability()
    for c in cs:
        c.interestingness = rotation.interesting(playability, c)
    rotation.rotation_sort(cs, request.args.get('sortBy'),
                           request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    end = start + page_size
    cs = cs[start:end]
    prepare_cards(cs)
    r = {'page': page, 'total': total, 'objects': cs}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #23
0
def decks_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of decks.
    Input:
        {
            'archetypeId': <int?>,
            'cardName': <str?>,
            'competitionId': <int?>,
            'deckType': <'league'|'tournament'|'all'>,
            'page': <int>,
            'pageSize': <int>,
            'personId': <int?>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'>
        }
    Output:
        {
            'page': <int>,
            'objects': [<deck>]
            'total': <int>
        }
    """
    order_by = query.decks_order_by(request.args.get('sortBy'),
                                    request.args.get('sortOrder'),
                                    request.args.get('competitionId'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    # Don't restrict by season if we're loading something with a date by its id.
    season_id = 'all' if request.args.get(
        'competitionId') else seasons.season_id(
            str(request.args.get('seasonId')), None)
    where = query.decks_where(request.args, session.get('admin'),
                              session.get('person_id'))
    total = deck.load_decks_count(where=where, season_id=season_id)
    ds = deck.load_decks(where=where,
                         order_by=order_by,
                         limit=limit,
                         season_id=season_id)
    prepare_decks(ds)
    r = {'page': page, 'total': total, 'objects': ds}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
Beispiel #24
0
def person_status():
    r = {
        'mtgo_username': auth.mtgo_username(),
        'discord_id': auth.discord_id(),
        'admin': session.get('admin', False)
    }
    if auth.mtgo_username():
        d = guarantee_at_most_one_or_retire(
            league.active_decks_by(auth.mtgo_username()))
        if d is not None:
            r['deck'] = {
                'name': d.name,
                'url': url_for('deck', deck_id=d.id),
                'wins': d.get('wins', 0),
                'losses': d.get('losses', 0)
            }
    return return_json(r)
def person_status() -> Response:
    username = auth.mtgo_username()
    r = {
        'mtgo_username': username,
        'discord_id': auth.discord_id(),
        'admin': session.get('admin', False),
        'demimod': session.get('demimod', False),
        'hide_intro': request.cookies.get('hide_intro', False) or auth.hide_intro() or username or auth.discord_id(),
        'in_guild': session.get('in_guild', False),
        }
    if username:
        d = guarantee_at_most_one_or_retire(league.active_decks_by(username))
        if d is not None:
            r['deck'] = {'name': d.name, 'url': url_for('deck', deck_id=d.id), 'wins': d.get('wins', 0), 'losses': d.get('losses', 0)} # type: ignore
    if r['admin'] or r['demimod']:
        r['archetypes_to_tag'] = len(deck.load_decks('NOT d.reviewed'))
    active_league = league.active_league()
    if active_league:
        time_until_league_end = active_league.end_date - datetime.datetime.now(tz=datetime.timezone.utc)
        if time_until_league_end <= datetime.timedelta(days=2):
            r['league_end'] = dtutil.display_time(time_until_league_end/datetime.timedelta(seconds=1), granularity=2)
    return return_json(r)
Beispiel #26
0
def people_api() -> Response:
    """
    Grab a slice of results from a 0-indexed resultset of people.
    Input:
        {
            'page': <int>,
            'pageSize': <int>,
            'sortBy': <str>,
            'sortOrder': <'ASC'|'DESC'>,
            'seasonId': <int|'all'>,
            'q': <str>
        }
    Output:
        {
            'page': <int>,
            'objects': [<person>],
            'total': <int>
        }
    """
    order_by = query.people_order_by(request.args.get('sortBy'),
                                     request.args.get('sortOrder'))
    page_size = int(request.args.get('pageSize', DEFAULT_LIVE_TABLE_PAGE_SIZE))
    page = int(request.args.get('page', 0))
    start = page * page_size
    limit = f'LIMIT {start}, {page_size}'
    season_id = seasons.season_id(str(request.args.get('seasonId')), None)
    q = request.args.get('q', '').strip()
    where = query.text_match_where(query.person_query(), q) if q else 'TRUE'
    people = ps.load_people(where=where,
                            order_by=order_by,
                            limit=limit,
                            season_id=season_id)
    prepare_people(people)
    total = ps.load_people_count(where=where, season_id=season_id)
    r = {'page': page, 'total': total, 'objects': people}
    resp = return_json(r, camelize=True)
    resp.set_cookie('page_size', str(page_size))
    return resp
def post_rule_update(rule_id: int = None) -> Response:
    if rule_id is not None and request.form.get('include') is not None and request.form.get('exclude') is not None:
        inc = []
        exc = []
        for line in cast(str, request.form.get('include')).strip().splitlines():
            try:
                inc.append(parse_line(line))
            except InvalidDataException:
                return return_json({'success':False, 'msg':f"Couldn't find a card count and name on line: {line}"})
            if not cs.card_exists(inc[-1][1]):
                return return_json({'success':False, 'msg':f'Card not found in any deck: {line}'})
        for line in cast(str, request.form.get('exclude')).strip().splitlines():
            try:
                exc.append(parse_line(line))
            except InvalidDataException:
                return return_json({'success':False, 'msg':f"Couldn't find a card count and name on line: {line}"})
            if not cs.card_exists(exc[-1][1]):
                return return_json({'success':False, 'msg':f'Card not found in any deck {line}'})
        rs.update_cards(rule_id, inc, exc)
        return return_json({'success':True})
    return return_json({'success':False, 'msg':'Required keys not found'})
def deck_api(deck_id: int) -> Response:
    blob = deck.load_deck(deck_id)
    return return_json(blob)
def test_500() -> Response:
    if configuration.get_bool('production'):
        return return_json(generate_error(
            'ON_PROD', 'This only works on test environments'),
                           status=404)
    raise TooManyItemsException()
def person_notes(person_id: int) -> Response:
    return return_json({'notes': ps.load_notes(person_id)})