Example #1
0
        def decorated_function(*args: List[Any], **kwargs: Dict[str, Any]) -> Callable:
            cache_key = key.format(id=request.full_path, locale=localization.get_locale()) # include querystring
            cache_policy = ''
            if not cacheable:
                cache_policy += ', no-store' # tells the browser not to cache at all
            else:
                if must_revalidate: # this looks contradicting if you haven't read the article.
                    # no-cache doesn't mean "don't cache", it means it must check
                    # (or "revalidate" as it calls it) with the server before
                    # using the cached resource
                    cache_policy += ', no-cache'
                else:
                    # Also must-revalidate doesn't mean "must revalidate", it
                    # means the local resource can be used if it's younger than
                    # the provided max-age, otherwise it must revalidate
                    cache_policy += ', must-revalidate'

                if client_only:
                    cache_policy += ', private'
                else:
                    cache_policy += ', public'

                actual_client_timeout = client_timeout
                actual_server_timeout = server_timeout
                if get_season_id() and get_season_id() != 0 and get_season_id() < rotation.current_season_num():
                    actual_client_timeout = 7 * 24 * 60 * 60
                    actual_server_timeout = 7 * 24 * 60 * 60

                cache_policy += ', max-age={client_timeout}'.format(client_timeout=actual_client_timeout)

            headers = {}
            cache_policy = cache_policy.strip(',')
            headers['Cache-Control'] = cache_policy
            now = datetime.datetime.utcnow()

            client_etag = request.headers.get('If-None-Match')

            response = CACHE.get(cache_key)  # type: ignore
            # Respect a hard refresh from the client, if sent.
            # Note: Safari/OSX does not send a Cache-Control (or any additional) header on a hard refresh so people using Safari can't bypass/refresh server cache.
            if response is not None and request.headers.get('Cache-Control', '') != 'no-cache':
                headers['X-Cache'] = 'HIT from Server'
                cached_etag = response.headers.get('ETag')
                if client_etag and cached_etag and client_etag == cached_etag:
                    headers['X-Cache'] = 'HIT from Client'
                    headers['X-Last-Modified'] = response.headers.get('X-LastModified')
                    response = make_response('', 304)
            else:
                response = make_response(f(*args, **kwargs))
                if response.status_code == 200 and request.method in ['GET', 'HEAD']:
                    headers['X-Cache'] = 'MISS'
                    # - Added the headers to the response object instead of the
                    # headers dict so they get cached too
                    # - If you can find any faster random algorithm go for it.
                    response.headers.add('ETag', binascii.hexlify(os.urandom(4)))
                    response.headers.add('X-Last-Modified', str(now))
                    CACHE.set(cache_key, response, timeout=actual_server_timeout)

            response.headers.extend(headers)
            return response
def card_history(c: Card) -> str:
    seasons = {}
    for format_name, status in c.legalities.items():
        if 'Penny Dreadful ' in format_name and status == 'Legal':
            season_id = rotation.SEASONS.index(
                format_name.replace('Penny Dreadful ', '')) + 1
            seasons[season_id] = True
    seasons[rotation.current_season_num()] = c.legalities.get('Penny Dreadful', None) == 'Legal'
    s = '   '
    for i in range(1, rotation.current_season_num() + 1):
        s += f'{i} '
        s += ':white_check_mark:' if seasons.get(i, False) else ':no_entry_sign:'
        s += '   '
    s = s.strip()
    s += '\n' + fetcher.decksite_url('/seasons/all/cards/{name}/'.format(
        name=fetch_tools.escape(c.name, skip_double_slash=True)))
    return s
Example #3
0
 def title(self) -> str:
     if not self.page_title():
         return 'pennydreadfulmagic.com'
     if get_season_id() == rotation.current_season_num():
         season = ''
     elif get_season_id() == 'all':
         season = ' - All Time'
     else:
         season = ' - Season {n}'.format(n=get_season_id())
     return '{page_title}{season} – pennydreadfulmagic.com'.format(page_title=self.page_title(), season=season)
Example #4
0
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'))
Example #5
0
def pd_rotation_changes(season_id):
    # It doesn't really make sense to do this for 'all' so just show current season in that case.
    if season_id == 'all':
        season_id = rotation.current_season_num()
    try:
        from_format_id = multiverse.get_format_id_from_season_id(int(season_id) - 1)
    except InvalidArgumentException:
        from_format_id = -1
    try:
        to_format_id = multiverse.get_format_id_from_season_id(season_id)
    except InvalidArgumentException:
        to_format_id = -1
    return changes_between_formats(from_format_id, to_format_id)
Example #6
0
def random_legal_deck() -> Optional[Deck]:
    where = 'd.reviewed AND d.created_date > (SELECT start_date FROM season WHERE number = {current_season_num})'.format(
        current_season_num=rotation.current_season_num())
    having = '(d.competition_id NOT IN ({active_competition_id_query}) OR SUM(cache.wins + cache.draws + cache.losses) >= 5)'.format(
        active_competition_id_query=active_competition_id_query())
    try:
        return deck.load_decks(where=where,
                               having=having,
                               order_by='RAND()',
                               limit='LIMIT 1')[0]
    except IndexError:
        # For a short while at the start of a season there are no decks that match the WHERE/HAVING clauses.
        return None
Example #7
0
def seasonized_url(season_id: Union[int, str]) -> str:
    args = request.view_args.copy()
    if season_id == rotation.current_season_num():
        args.pop('season_id', None)
        endpoint = request.endpoint.replace('seasons.', '')
    else:
        args['season_id'] = season_id
        prefix = '' if request.endpoint.startswith('seasons.') else 'seasons.'
        endpoint = '{prefix}{endpoint}'.format(prefix=prefix, endpoint=request.endpoint)
    try:
        return url_for(endpoint, **args)
    except BuildError:
        return url_for(request.endpoint)
Example #8
0
def pd_rotation_changes(season_id):
    # Bit of a hack to make 'all' not explode until we cope with selective season dropdowns.
    if season_id == 'all':
        season_id = rotation.current_season_num()
    try:
        from_format_id = multiverse.get_format_id_from_season_id(
            int(season_id) - 1)
    except InvalidArgumentException:
        from_format_id = -1
    try:
        to_format_id = multiverse.get_format_id_from_season_id(season_id)
    except InvalidArgumentException:
        to_format_id = -1
    return changes_between_formats(from_format_id, to_format_id)
Example #9
0
 def __init__(self,
              cards: List[Card],
              tournament_only: bool = False,
              query: str = '') -> None:
     super().__init__()
     self.show_seasons = True
     self.show_tournament_toggle = True
     self.tournament_only = self.hide_source = tournament_only
     self.query = query
     # if it's the current season, allow the scryfall filter to add "f:pd" to speed up results
     if self.season_id() == current_season_num():
         self.filter_current_season = True
     self.toggle_results_url = url_for(
         '.cards',
         deck_type=None if tournament_only else DeckType.TOURNAMENT.value)
     self.cards = cards
     self.show_filters_toggle = True
Example #10
0
def test_seasonized_url_for_app() -> None:
    with APP.test_request_context('/decks/'):
        assert view.seasonized_url(1) == '/seasons/1/decks/'
        assert view.seasonized_url(rotation.current_season_num()) == '/decks/'
Example #11
0
def test_seasonized_url_simple() -> None:
    with APP.test_request_context('/tournaments/'):
        assert view.seasonized_url(1) == '/tournaments/'
        assert view.seasonized_url(
            rotation.current_season_num()) == '/tournaments/'
def get_season_id() -> int:
    return g.get('season_id', rotation.current_season_num())
Example #13
0
def get_season_id() -> int:
    season_id = g.get('season_id', rotation.current_season_num())
    if season_id == 'all':
        return 0
    return season_id