929 better visibility constants (#1490)

* Adds Enums for visibility configs for better reusability. Old tests will continue to use the static values but new ones should use the enum values. 
* Closes #929
This commit is contained in:
Kevin Chung
2020-06-14 04:15:55 -04:00
committed by GitHub
parent bacb8977a4
commit 1143d751c8
6 changed files with 119 additions and 44 deletions

View File

@@ -1,7 +1,42 @@
import json
from CTFd.constants import JinjaEnum, RawEnum
from CTFd.utils import get_config
from CTFd.utils.helpers import markup
class ConfigTypes(str, RawEnum):
CHALLENGE_VISIBILITY = "challenge_visibility"
SCORE_VISIBILITY = "score_visibility"
ACCOUNT_VISIBILITY = "account_visibility"
REGISTRATION_VISIBILITY = "registration_visibility"
@JinjaEnum
class ChallengeVisibilityTypes(str, RawEnum):
PUBLIC = "public"
PRIVATE = "private"
ADMINS = "admins"
@JinjaEnum
class ScoreVisibilityTypes(str, RawEnum):
PUBLIC = "public"
PRIVATE = "private"
HIDDEN = "hidden"
ADMINS = "admins"
@JinjaEnum
class AccountVisibilityTypes(str, RawEnum):
PUBLIC = "public"
PRIVATE = "private"
ADMINS = "admins"
@JinjaEnum
class RegistrationVisibilityTypes(str, RawEnum):
PUBLIC = "public"
PRIVATE = "private"
class _ConfigsWrapper:
@@ -14,10 +49,14 @@ class _ConfigsWrapper:
@property
def theme_header(self):
from CTFd.utils.helpers import markup
return markup(get_config("theme_header", default=""))
@property
def theme_footer(self):
from CTFd.utils.helpers import markup
return markup(get_config("theme_footer", default=""))
@property

View File

@@ -1,3 +1,5 @@
from enum import Enum
import cmarkgfm
from flask import current_app as app
@@ -43,6 +45,10 @@ def _get_config(key):
def get_config(key, default=None):
# Convert enums to raw string values to cache better
if isinstance(key, Enum):
key = str(key)
value = _get_config(key)
if value is KeyError:
return default
@@ -58,5 +64,10 @@ def set_config(key, value):
config = Configs(key=key, value=value)
db.session.add(config)
db.session.commit()
# Convert enums to raw string values to cache better
if isinstance(key, Enum):
key = str(key)
cache.delete_memoized(_get_config, key)
return config

View File

@@ -1,44 +1,51 @@
from CTFd.constants.config import (
AccountVisibilityTypes,
ChallengeVisibilityTypes,
ConfigTypes,
RegistrationVisibilityTypes,
ScoreVisibilityTypes,
)
from CTFd.utils import get_config
from CTFd.utils.user import authed, is_admin
def challenges_visible():
v = get_config("challenge_visibility")
if v == "public":
v = get_config(ConfigTypes.CHALLENGE_VISIBILITY)
if v == ChallengeVisibilityTypes.PUBLIC:
return True
elif v == "private":
elif v == ChallengeVisibilityTypes.PRIVATE:
return authed()
elif v == "admins":
elif v == ChallengeVisibilityTypes.ADMINS:
return is_admin()
def scores_visible():
v = get_config("score_visibility")
if v == "public":
v = get_config(ConfigTypes.SCORE_VISIBILITY)
if v == ScoreVisibilityTypes.PUBLIC:
return True
elif v == "private":
elif v == ScoreVisibilityTypes.PRIVATE:
return authed()
elif v == "hidden":
elif v == ScoreVisibilityTypes.HIDDEN:
return False
elif v == "admins":
elif v == ScoreVisibilityTypes.ADMINS:
return is_admin()
def accounts_visible():
v = get_config("account_visibility")
if v == "public":
v = get_config(ConfigTypes.ACCOUNT_VISIBILITY)
if v == AccountVisibilityTypes.PUBLIC:
return True
elif v == "private":
elif v == AccountVisibilityTypes.PRIVATE:
return authed()
elif v == "admins":
elif v == AccountVisibilityTypes.ADMINS:
return is_admin()
def registration_visible():
v = get_config("registration_visibility")
if v == "public":
v = get_config(ConfigTypes.REGISTRATION_VISIBILITY)
if v == RegistrationVisibilityTypes.PUBLIC:
return True
elif v == "private":
elif v == RegistrationVisibilityTypes.PRIVATE:
return False
else:
return False

View File

@@ -2,6 +2,13 @@ import functools
from flask import abort, redirect, render_template, request, url_for
from CTFd.constants.config import (
AccountVisibilityTypes,
ChallengeVisibilityTypes,
ConfigTypes,
RegistrationVisibilityTypes,
ScoreVisibilityTypes,
)
from CTFd.utils import get_config
from CTFd.utils.user import authed, is_admin
@@ -9,11 +16,11 @@ from CTFd.utils.user import authed, is_admin
def check_score_visibility(f):
@functools.wraps(f)
def _check_score_visibility(*args, **kwargs):
v = get_config("score_visibility")
if v == "public":
v = get_config(ConfigTypes.SCORE_VISIBILITY)
if v == ScoreVisibilityTypes.PUBLIC:
return f(*args, **kwargs)
elif v == "private":
elif v == ScoreVisibilityTypes.PRIVATE:
if authed():
return f(*args, **kwargs)
else:
@@ -22,13 +29,13 @@ def check_score_visibility(f):
else:
return redirect(url_for("auth.login", next=request.full_path))
elif v == "hidden":
elif v == ScoreVisibilityTypes.HIDDEN:
return (
render_template("errors/403.html", error="Scores are currently hidden"),
403,
)
elif v == "admins":
elif v == ScoreVisibilityTypes.ADMINS:
if is_admin():
return f(*args, **kwargs)
else:
@@ -40,11 +47,11 @@ def check_score_visibility(f):
def check_challenge_visibility(f):
@functools.wraps(f)
def _check_challenge_visibility(*args, **kwargs):
v = get_config("challenge_visibility")
if v == "public":
v = get_config(ConfigTypes.CHALLENGE_VISIBILITY)
if v == ChallengeVisibilityTypes.PUBLIC:
return f(*args, **kwargs)
elif v == "private":
elif v == ChallengeVisibilityTypes.PRIVATE:
if authed():
return f(*args, **kwargs)
else:
@@ -53,7 +60,7 @@ def check_challenge_visibility(f):
else:
return redirect(url_for("auth.login", next=request.full_path))
elif v == "admins":
elif v == ChallengeVisibilityTypes.ADMINS:
if is_admin():
return f(*args, **kwargs)
else:
@@ -68,11 +75,11 @@ def check_challenge_visibility(f):
def check_account_visibility(f):
@functools.wraps(f)
def _check_account_visibility(*args, **kwargs):
v = get_config("account_visibility")
if v == "public":
v = get_config(ConfigTypes.ACCOUNT_VISIBILITY)
if v == AccountVisibilityTypes.PUBLIC:
return f(*args, **kwargs)
elif v == "private":
elif v == AccountVisibilityTypes.PRIVATE:
if authed():
return f(*args, **kwargs)
else:
@@ -81,7 +88,7 @@ def check_account_visibility(f):
else:
return redirect(url_for("auth.login", next=request.full_path))
elif v == "admins":
elif v == AccountVisibilityTypes.ADMINS:
if is_admin():
return f(*args, **kwargs)
else:
@@ -93,10 +100,10 @@ def check_account_visibility(f):
def check_registration_visibility(f):
@functools.wraps(f)
def _check_registration_visibility(*args, **kwargs):
v = get_config("registration_visibility")
if v == "public":
v = get_config(ConfigTypes.REGISTRATION_VISIBILITY)
if v == RegistrationVisibilityTypes.PUBLIC:
return f(*args, **kwargs)
elif v == "private":
elif v == RegistrationVisibilityTypes.PRIVATE:
abort(404)
return _check_registration_visibility

View File

@@ -20,12 +20,6 @@ from CTFd.utils.config import (
is_setup,
)
from CTFd.utils.config.pages import get_pages
from CTFd.utils.config.visibility import (
accounts_visible,
challenges_visible,
registration_visible,
scores_visible,
)
from CTFd.utils.countries import get_countries, lookup_country_code
from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
from CTFd.utils.events import EventManager, RedisEventManager
@@ -61,6 +55,12 @@ def init_template_globals(app):
from CTFd.constants.plugins import Plugins
from CTFd.constants.sessions import Session
from CTFd.forms import Forms
from CTFd.utils.config.visibility import (
accounts_visible,
challenges_visible,
registration_visible,
scores_visible,
)
app.jinja_env.globals.update(config=config)
app.jinja_env.globals.update(get_pages=get_pages)

View File

@@ -7,6 +7,13 @@ from flask.helpers import safe_join
from sqlalchemy.exc import IntegrityError
from CTFd.cache import cache
from CTFd.constants.config import (
AccountVisibilityTypes,
ChallengeVisibilityTypes,
ConfigTypes,
RegistrationVisibilityTypes,
ScoreVisibilityTypes,
)
from CTFd.models import (
Admins,
Files,
@@ -156,10 +163,14 @@ def setup():
page = Pages(title=None, route="index", content=index, draft=False)
# Visibility
set_config("challenge_visibility", "private")
set_config("registration_visibility", "public")
set_config("score_visibility", "public")
set_config("account_visibility", "public")
set_config(
ConfigTypes.CHALLENGE_VISIBILITY, ChallengeVisibilityTypes.PRIVATE
)
set_config(
ConfigTypes.REGISTRATION_VISIBILITY, RegistrationVisibilityTypes.PUBLIC
)
set_config(ConfigTypes.SCORE_VISIBILITY, ScoreVisibilityTypes.PUBLIC)
set_config(ConfigTypes.ACCOUNT_VISIBILITY, AccountVisibilityTypes.PUBLIC)
# Verify emails
set_config("verify_emails", None)
@@ -354,7 +365,7 @@ def files(path):
# Check user is admin if challenge_visibility is admins only
if (
get_config("challenge_visibility") == "admins"
get_config(ConfigTypes.CHALLENGE_VISIBILITY) == "admins"
and user.type != "admin"
):
abort(403)