mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 14:34:21 +01:00
Make scoreboard caching only cache the score table (#1586)
* Make scoreboard caching only cache the score table instead of the entire page * Closes #1584
This commit is contained in:
7
CTFd/cache/__init__.py
vendored
7
CTFd/cache/__init__.py
vendored
@@ -1,5 +1,5 @@
|
||||
from flask import request
|
||||
from flask_caching import Cache
|
||||
from flask_caching import Cache, make_template_fragment_key
|
||||
|
||||
cache = Cache()
|
||||
|
||||
@@ -27,6 +27,7 @@ def clear_config():
|
||||
|
||||
def clear_standings():
|
||||
from CTFd.models import Users, Teams
|
||||
from CTFd.constants.static import CacheKeys
|
||||
from CTFd.utils.scores import get_standings, get_team_standings, get_user_standings
|
||||
from CTFd.api.v1.scoreboard import ScoreboardDetail, ScoreboardList
|
||||
from CTFd.api import api
|
||||
@@ -55,11 +56,13 @@ def clear_standings():
|
||||
cache.delete_memoized(get_team_place)
|
||||
|
||||
# Clear out HTTP request responses
|
||||
cache.delete(make_cache_key(path="scoreboard.listing"))
|
||||
cache.delete(make_cache_key(path=api.name + "." + ScoreboardList.endpoint))
|
||||
cache.delete(make_cache_key(path=api.name + "." + ScoreboardDetail.endpoint))
|
||||
cache.delete_memoized(ScoreboardList.get)
|
||||
|
||||
# Clear out scoreboard templates
|
||||
cache.delete(make_template_fragment_key(CacheKeys.PUBLIC_SCOREBOARD_TABLE))
|
||||
|
||||
|
||||
def clear_pages():
|
||||
from CTFd.utils.config.pages import get_page, get_pages
|
||||
|
||||
@@ -3,6 +3,7 @@ from enum import Enum
|
||||
from flask import current_app
|
||||
|
||||
JS_ENUMS = {}
|
||||
JINJA_ENUMS = {}
|
||||
|
||||
|
||||
class RawEnum(Enum):
|
||||
@@ -59,6 +60,7 @@ def JinjaEnum(cls):
|
||||
"""
|
||||
if cls.__name__ not in current_app.jinja_env.globals:
|
||||
current_app.jinja_env.globals[cls.__name__] = cls
|
||||
JINJA_ENUMS[cls.__name__] = cls
|
||||
else:
|
||||
raise KeyError("{} was already defined as a JinjaEnum".format(cls.__name__))
|
||||
return cls
|
||||
|
||||
14
CTFd/constants/static.py
Normal file
14
CTFd/constants/static.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from CTFd.constants import JinjaEnum, RawEnum
|
||||
|
||||
|
||||
@JinjaEnum
|
||||
class CacheKeys(str, RawEnum):
|
||||
PUBLIC_SCOREBOARD_TABLE = "public_scoreboard_table"
|
||||
|
||||
|
||||
# Placeholder object. Not used, just imported to force initialization of any Enums here
|
||||
class _StaticsWrapper:
|
||||
pass
|
||||
|
||||
|
||||
Static = _StaticsWrapper()
|
||||
@@ -1,6 +1,5 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
from CTFd.cache import cache, make_cache_key
|
||||
from CTFd.utils import config
|
||||
from CTFd.utils.config.visibility import scores_visible
|
||||
from CTFd.utils.decorators.visibility import check_score_visibility
|
||||
@@ -13,7 +12,6 @@ scoreboard = Blueprint("scoreboard", __name__)
|
||||
|
||||
@scoreboard.route("/scoreboard")
|
||||
@check_score_visibility
|
||||
@cache.cached(timeout=60, key_prefix=make_cache_key)
|
||||
def listing():
|
||||
infos = get_infos()
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% cache 60, CacheKeys.PUBLIC_SCOREBOARD_TABLE %}
|
||||
{% if standings %}
|
||||
<div id="scoreboard" class="row">
|
||||
<div class="col-md-12">
|
||||
@@ -55,6 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -52,9 +52,11 @@ def init_template_filters(app):
|
||||
|
||||
|
||||
def init_template_globals(app):
|
||||
from CTFd.constants import JINJA_ENUMS
|
||||
from CTFd.constants.config import Configs
|
||||
from CTFd.constants.plugins import Plugins
|
||||
from CTFd.constants.sessions import Session
|
||||
from CTFd.constants.static import Static
|
||||
from CTFd.constants.users import User
|
||||
from CTFd.constants.teams import Team
|
||||
from CTFd.forms import Forms
|
||||
@@ -101,10 +103,20 @@ def init_template_globals(app):
|
||||
app.jinja_env.globals.update(Configs=Configs)
|
||||
app.jinja_env.globals.update(Plugins=Plugins)
|
||||
app.jinja_env.globals.update(Session=Session)
|
||||
app.jinja_env.globals.update(Static=Static)
|
||||
app.jinja_env.globals.update(Forms=Forms)
|
||||
app.jinja_env.globals.update(User=User)
|
||||
app.jinja_env.globals.update(Team=Team)
|
||||
|
||||
# Add in JinjaEnums
|
||||
# The reason this exists is that on double import, JinjaEnums are not reinitialized
|
||||
# Thus, if you try to create two jinja envs (e.g. during testing), sometimes
|
||||
# an Enum will not be available to Jinja.
|
||||
# Instead we can just directly grab them from the persisted global dictionary.
|
||||
for k, v in JINJA_ENUMS.items():
|
||||
# .update() can't be used here because it would use the literal value k
|
||||
app.jinja_env.globals[k] = v
|
||||
|
||||
|
||||
def init_logs(app):
|
||||
logger_submissions = logging.getLogger("submissions")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask_caching import make_template_fragment_key
|
||||
|
||||
from CTFd.cache import clear_standings
|
||||
from tests.helpers import (
|
||||
create_ctfd,
|
||||
@@ -40,13 +42,19 @@ def test_scoreboard_is_cached():
|
||||
assert app.cache.get("view/api.scoreboard_scoreboard_detail")
|
||||
|
||||
# Check scoreboard page
|
||||
assert app.cache.get("view/scoreboard.listing") is None
|
||||
assert (
|
||||
app.cache.get(make_template_fragment_key("public_scoreboard_table"))
|
||||
is None
|
||||
)
|
||||
client.get("/scoreboard")
|
||||
assert app.cache.get("view/scoreboard.listing")
|
||||
assert app.cache.get(make_template_fragment_key("public_scoreboard_table"))
|
||||
|
||||
# Empty standings and check that the cached data is gone
|
||||
clear_standings()
|
||||
assert app.cache.get("view/api.scoreboard_scoreboard_list") is None
|
||||
assert app.cache.get("view/api.scoreboard_scoreboard_detail") is None
|
||||
assert app.cache.get("view/scoreboard.listing") is None
|
||||
assert (
|
||||
app.cache.get(make_template_fragment_key("public_scoreboard_table"))
|
||||
is None
|
||||
)
|
||||
destroy_ctfd(app)
|
||||
|
||||
Reference in New Issue
Block a user