General fixes and PEP8 enforcement (#258)

* Fixing index page links when you deploy on a subdirectory

* Updating travis for pep8

* autopep8 with just formatting changes
This commit is contained in:
Kevin Chung
2017-05-12 00:34:20 -04:00
committed by GitHub
parent b4d0d1ecab
commit e16d3a0b6e
21 changed files with 152 additions and 147 deletions

View File

@@ -5,4 +5,5 @@ python:
install: install:
- pip install -r development.txt - pip install -r development.txt
script: script:
- pep8 --ignore E501,E712 CTFd/ tests/
- nosetests - nosetests

View File

@@ -13,6 +13,7 @@ from CTFd import utils
__version__ = '1.0.2' __version__ = '1.0.2'
class ThemeLoader(FileSystemLoader): class ThemeLoader(FileSystemLoader):
def get_source(self, environment, template): def get_source(self, environment, template):
if template.startswith('admin/'): if template.startswith('admin/'):
@@ -34,21 +35,21 @@ def create_app(config='CTFd.config.Config'):
if url.drivername == 'postgres': if url.drivername == 'postgres':
url.drivername = 'postgresql' url.drivername = 'postgresql'
## Creates database if the database database does not exist # Creates database if the database database does not exist
if not database_exists(url): if not database_exists(url):
create_database(url) create_database(url)
## Register database # Register database
db.init_app(app) db.init_app(app)
## Register Flask-Migrate # Register Flask-Migrate
migrate.init_app(app, db) migrate.init_app(app, db)
## This creates tables instead of db.create_all() # This creates tables instead of db.create_all()
## Allows migrations to happen properly # Allows migrations to happen properly
migrate_upgrade() migrate_upgrade()
## Alembic sqlite support is lacking so we should just create_all anyway # Alembic sqlite support is lacking so we should just create_all anyway
if url.drivername.startswith('sqlite'): if url.drivername.startswith('sqlite'):
db.create_all() db.create_all()
@@ -59,10 +60,10 @@ def create_app(config='CTFd.config.Config'):
version = utils.get_config('ctf_version') version = utils.get_config('ctf_version')
if not version: ## Upgrading from an unversioned CTFd if not version: # Upgrading from an unversioned CTFd
utils.set_config('ctf_version', __version__) utils.set_config('ctf_version', __version__)
if version and (StrictVersion(version) < StrictVersion(__version__)): ## Upgrading from an older version of CTFd if version and (StrictVersion(version) < StrictVersion(__version__)): # Upgrading from an older version of CTFd
print("/*\\ CTFd has updated and must update the database! /*\\") print("/*\\ CTFd has updated and must update the database! /*\\")
print("/*\\ Please backup your database before proceeding! /*\\") print("/*\\ Please backup your database before proceeding! /*\\")
print("/*\\ CTFd maintainers are not responsible for any data loss! /*\\") print("/*\\ CTFd maintainers are not responsible for any data loss! /*\\")

View File

@@ -6,6 +6,7 @@ from CTFd import utils
admin_containers = Blueprint('admin_containers', __name__) admin_containers = Blueprint('admin_containers', __name__)
@admin_containers.route('/admin/containers', methods=['GET']) @admin_containers.route('/admin/containers', methods=['GET'])
@admins_only @admins_only
def list_container(): def list_container():

View File

@@ -7,6 +7,7 @@ from CTFd import utils
admin_keys = Blueprint('admin_keys', __name__) admin_keys = Blueprint('admin_keys', __name__)
@admin_keys.route('/admin/key_types', methods=['GET']) @admin_keys.route('/admin/key_types', methods=['GET'])
@admins_only @admins_only
def admin_key_types(): def admin_key_types():
@@ -16,6 +17,7 @@ def admin_key_types():
return jsonify(data) return jsonify(data)
@admin_keys.route('/admin/keys', defaults={'keyid': None}, methods=['POST', 'GET']) @admin_keys.route('/admin/keys', defaults={'keyid': None}, methods=['POST', 'GET'])
@admin_keys.route('/admin/keys/<int:keyid>', methods=['POST', 'GET']) @admin_keys.route('/admin/keys/<int:keyid>', methods=['POST', 'GET'])
@admins_only @admins_only
@@ -53,7 +55,6 @@ def admin_keys_view(keyid):
return '1' return '1'
@admin_keys.route('/admin/keys/<int:keyid>/delete', methods=['POST']) @admin_keys.route('/admin/keys/<int:keyid>/delete', methods=['POST'])
@admins_only @admins_only
def admin_delete_keys(keyid): def admin_delete_keys(keyid):

View File

@@ -6,6 +6,7 @@ from CTFd import utils
admin_pages = Blueprint('admin_pages', __name__) admin_pages = Blueprint('admin_pages', __name__)
@admin_pages.route('/admin/css', methods=['GET', 'POST']) @admin_pages.route('/admin/css', methods=['GET', 'POST'])
@admins_only @admins_only
def admin_css(): def admin_css():

View File

@@ -7,6 +7,7 @@ from CTFd import utils
admin_scoreboard = Blueprint('admin_scoreboard', __name__) admin_scoreboard = Blueprint('admin_scoreboard', __name__)
@admin_scoreboard.route('/admin/scoreboard') @admin_scoreboard.route('/admin/scoreboard')
@admins_only @admins_only
def admin_scoreboard_view(): def admin_scoreboard_view():

View File

@@ -6,11 +6,13 @@ from CTFd import utils
admin_statistics = Blueprint('admin_statistics', __name__) admin_statistics = Blueprint('admin_statistics', __name__)
@admin_statistics.route('/admin/graphs') @admin_statistics.route('/admin/graphs')
@admins_only @admins_only
def admin_graphs(): def admin_graphs():
return render_template('admin/graphs.html') return render_template('admin/graphs.html')
@admin_statistics.route('/admin/graphs/<graph_type>') @admin_statistics.route('/admin/graphs/<graph_type>')
@admins_only @admins_only
def admin_graph(graph_type): def admin_graph(graph_type):
@@ -31,6 +33,7 @@ def admin_graph(graph_type):
json_data[name] = count json_data[name] = count
return jsonify(json_data) return jsonify(json_data)
@admin_statistics.route('/admin/statistics', methods=['GET']) @admin_statistics.route('/admin/statistics', methods=['GET'])
@admins_only @admins_only
def admin_stats(): def admin_stats():
@@ -66,6 +69,7 @@ def admin_stats():
most_solved=most_solved, most_solved=most_solved,
least_solved=least_solved) least_solved=least_solved)
@admin_statistics.route('/admin/wrong_keys', defaults={'page': '1'}, methods=['GET']) @admin_statistics.route('/admin/wrong_keys', defaults={'page': '1'}, methods=['GET'])
@admin_statistics.route('/admin/wrong_keys/<int:page>', methods=['GET']) @admin_statistics.route('/admin/wrong_keys/<int:page>', methods=['GET'])
@admins_only @admins_only

View File

@@ -8,6 +8,7 @@ from CTFd import utils
admin_teams = Blueprint('admin_teams', __name__) admin_teams = Blueprint('admin_teams', __name__)
@admin_teams.route('/admin/teams', defaults={'page': '1'}) @admin_teams.route('/admin/teams', defaults={'page': '1'})
@admin_teams.route('/admin/teams/<int:page>') @admin_teams.route('/admin/teams/<int:page>')
@admins_only @admins_only
@@ -225,6 +226,7 @@ def delete_wrong_key(keyid):
db.session.close() db.session.close()
return '1' return '1'
@admin_teams.route('/admin/awards/<int:award_id>/delete', methods=['POST']) @admin_teams.route('/admin/awards/<int:award_id>/delete', methods=['POST'])
@admins_only @admins_only
def delete_award(award_id): def delete_award(award_id):
@@ -234,6 +236,7 @@ def delete_award(award_id):
db.session.close() db.session.close()
return '1' return '1'
@admin_teams.route('/admin/teams/<int:teamid>/awards', methods=['GET']) @admin_teams.route('/admin/teams/<int:teamid>/awards', methods=['GET'])
@admins_only @admins_only
def admin_awards(teamid): def admin_awards(teamid):

View File

@@ -14,6 +14,7 @@ from CTFd import utils
challenges = Blueprint('challenges', __name__) challenges = Blueprint('challenges', __name__)
@challenges.route('/hints/<int:hintid>', methods=['GET', 'POST']) @challenges.route('/hints/<int:hintid>', methods=['GET', 'POST'])
def hints_view(hintid): def hints_view(hintid):
hint = Hints.query.filter_by(id=hintid).first_or_404() hint = Hints.query.filter_by(id=hintid).first_or_404()
@@ -104,9 +105,9 @@ def chals():
hints = [] hints = []
for hint in Hints.query.filter_by(chal=x.id).all(): for hint in Hints.query.filter_by(chal=x.id).all():
if hint.id in unlocked_hints: if hint.id in unlocked_hints:
hints.append({'id':hint.id, 'cost':hint.cost, 'hint':hint.hint}) hints.append({'id': hint.id, 'cost': hint.cost, 'hint': hint.hint})
else: else:
hints.append({'id':hint.id, 'cost':hint.cost}) hints.append({'id': hint.id, 'cost': hint.cost})
# hints = [{'id':hint.id, 'cost':hint.cost} for hint in Hints.query.filter_by(chal=x.id).all()] # hints = [{'id':hint.id, 'cost':hint.cost} for hint in Hints.query.filter_by(chal=x.id).all()]
chal_type = get_chal_class(x.type) chal_type = get_chal_class(x.type)
json['game'].append({ json['game'].append({
@@ -293,7 +294,7 @@ def chal(chalid):
logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data)) logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data))
# return '0' # key was wrong # return '0' # key was wrong
if max_tries: if max_tries:
attempts_left = max_tries - fails - 1 ## Off by one since fails has changed since it was gotten attempts_left = max_tries - fails - 1 # Off by one since fails has changed since it was gotten
tries_str = 'tries' tries_str = 'tries'
if attempts_left == 1: if attempts_left == 1:
tries_str = 'try' tries_str = 'try'

View File

@@ -1,6 +1,6 @@
import os import os
##### GENERATE SECRET KEY ##### ''' GENERATE SECRET KEY '''
with open('.ctfd_secret_key', 'a+b') as secret: with open('.ctfd_secret_key', 'a+b') as secret:
secret.seek(0) # Seek to beginning of file since a+ mode leaves you at the end and w+ deletes the file secret.seek(0) # Seek to beginning of file since a+ mode leaves you at the end and w+ deletes the file
@@ -10,7 +10,8 @@ with open('.ctfd_secret_key', 'a+b') as secret:
secret.write(key) secret.write(key)
secret.flush() secret.flush()
##### SERVER SETTINGS ##### ''' SERVER SETTINGS '''
class Config(object): class Config(object):
''' '''
@@ -25,7 +26,6 @@ class Config(object):
''' '''
SECRET_KEY = os.environ.get('SECRET_KEY') or key SECRET_KEY = os.environ.get('SECRET_KEY') or key
''' '''
SQLALCHEMY_DATABASE_URI is the URI that specifies the username, password, hostname, port, and database of the server SQLALCHEMY_DATABASE_URI is the URI that specifies the username, password, hostname, port, and database of the server
used to hold the CTFd database. used to hold the CTFd database.
@@ -34,52 +34,44 @@ class Config(object):
''' '''
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///{}/ctfd.db'.format(os.path.dirname(os.path.abspath(__file__))) SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///{}/ctfd.db'.format(os.path.dirname(os.path.abspath(__file__)))
''' '''
SQLALCHEMY_TRACK_MODIFICATIONS is automatically disabled to suppress warnings and save memory. You should only enable SQLALCHEMY_TRACK_MODIFICATIONS is automatically disabled to suppress warnings and save memory. You should only enable
this if you need it. this if you need it.
''' '''
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
''' '''
SESSION_TYPE is a configuration value used for Flask-Session. It is currently unused in CTFd. SESSION_TYPE is a configuration value used for Flask-Session. It is currently unused in CTFd.
http://pythonhosted.org/Flask-Session/#configuration http://pythonhosted.org/Flask-Session/#configuration
''' '''
SESSION_TYPE = "filesystem" SESSION_TYPE = "filesystem"
''' '''
SESSION_FILE_DIR is a configuration value used for Flask-Session. It is currently unused in CTFd. SESSION_FILE_DIR is a configuration value used for Flask-Session. It is currently unused in CTFd.
http://pythonhosted.org/Flask-Session/#configuration http://pythonhosted.org/Flask-Session/#configuration
''' '''
SESSION_FILE_DIR = "/tmp/flask_session" SESSION_FILE_DIR = "/tmp/flask_session"
''' '''
SESSION_COOKIE_HTTPONLY controls if cookies should be set with the HttpOnly flag. SESSION_COOKIE_HTTPONLY controls if cookies should be set with the HttpOnly flag.
''' '''
SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_HTTPONLY = True
''' '''
PERMANENT_SESSION_LIFETIME is the lifetime of a session. PERMANENT_SESSION_LIFETIME is the lifetime of a session.
''' '''
PERMANENT_SESSION_LIFETIME = 604800 # 7 days in seconds PERMANENT_SESSION_LIFETIME = 604800 # 7 days in seconds
''' '''
HOST specifies the hostname where the CTFd instance will exist. It is currently unused. HOST specifies the hostname where the CTFd instance will exist. It is currently unused.
''' '''
HOST = ".ctfd.io" HOST = ".ctfd.io"
''' '''
MAILFROM_ADDR is the email address that emails are sent from if not overridden in the configuration panel. MAILFROM_ADDR is the email address that emails are sent from if not overridden in the configuration panel.
''' '''
MAILFROM_ADDR = "noreply@ctfd.io" MAILFROM_ADDR = "noreply@ctfd.io"
''' '''
UPLOAD_FOLDER is the location where files are uploaded. UPLOAD_FOLDER is the location where files are uploaded.
The default destination is the CTFd/uploads folder. If you need Amazon S3 files The default destination is the CTFd/uploads folder. If you need Amazon S3 files
@@ -87,14 +79,12 @@ class Config(object):
''' '''
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads') UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads')
''' '''
TEMPLATES_AUTO_RELOAD specifies whether Flask should check for modifications to templates and TEMPLATES_AUTO_RELOAD specifies whether Flask should check for modifications to templates and
reload them automatically reload them automatically
''' '''
TEMPLATES_AUTO_RELOAD = True TEMPLATES_AUTO_RELOAD = True
''' '''
TRUSTED_PROXIES defines a set of regular expressions used for finding a user's IP address if the CTFd instance TRUSTED_PROXIES defines a set of regular expressions used for finding a user's IP address if the CTFd instance
is behind a proxy. If you are running a CTF and users are on the same network as you, you may choose to remove is behind a proxy. If you are running a CTF and users are on the same network as you, you may choose to remove
@@ -114,7 +104,6 @@ class Config(object):
'^192\.168\.' '^192\.168\.'
] ]
''' '''
CACHE_TYPE specifies how CTFd should cache configuration values. If CACHE_TYPE is set to 'redis', CTFd will make use CACHE_TYPE specifies how CTFd should cache configuration values. If CACHE_TYPE is set to 'redis', CTFd will make use
of the REDIS_URL specified in environment variables. You can also choose to hardcode the REDIS_URL here. of the REDIS_URL specified in environment variables. You can also choose to hardcode the REDIS_URL here.

View File

@@ -1,10 +1,12 @@
from CTFd.plugins.keys import get_key_class from CTFd.plugins.keys import get_key_class
from CTFd.models import db, Keys from CTFd.models import db, Keys
class BaseChallenge(object): class BaseChallenge(object):
id = None id = None
name = None name = None
class CTFdStandardChallenge(BaseChallenge): class CTFdStandardChallenge(BaseChallenge):
id = 0 id = 0
name = "standard" name = "standard"
@@ -19,9 +21,10 @@ class CTFdStandardChallenge(BaseChallenge):
CHALLENGE_CLASSES = { CHALLENGE_CLASSES = {
0 : CTFdStandardChallenge 0: CTFdStandardChallenge
} }
def get_chal_class(class_id): def get_chal_class(class_id):
cls = CHALLENGE_CLASSES.get(class_id) cls = CHALLENGE_CLASSES.get(class_id)
if cls is None: if cls is None:

View File

@@ -11,6 +11,7 @@ class BaseKey(object):
def compare(self, saved, provided): def compare(self, saved, provided):
return True return True
class CTFdStaticKey(BaseKey): class CTFdStaticKey(BaseKey):
id = 0 id = 0
name = "static" name = "static"
@@ -36,8 +37,8 @@ class CTFdRegexKey(BaseKey):
KEY_CLASSES = { KEY_CLASSES = {
0 : CTFdStaticKey, 0: CTFdStaticKey,
1 : CTFdRegexKey 1: CTFdRegexKey
} }

View File

@@ -102,7 +102,6 @@ def topteams(count):
solves = Solves.query.filter_by(teamid=team.teamid) solves = Solves.query.filter_by(teamid=team.teamid)
awards = Awards.query.filter_by(teamid=team.teamid) awards = Awards.query.filter_by(teamid=team.teamid)
freeze = utils.get_config('freeze') freeze = utils.get_config('freeze')
if freeze: if freeze:
@@ -112,7 +111,6 @@ def topteams(count):
solves = solves.all() solves = solves.all()
awards = awards.all() awards = awards.all()
json['scores'][team.name] = [] json['scores'][team.name] = []
for x in solves: for x in solves:
json['scores'][team.name].append({ json['scores'][team.name].append({

View File

@@ -226,7 +226,6 @@ def is_scoreboard_frozen():
return False return False
def ctftime(): def ctftime():
""" Checks whether it's CTF time or not. """ """ Checks whether it's CTF time or not. """
@@ -669,7 +668,7 @@ def export_ctf(segments=None):
] ]
} }
## Backup database # Backup database
backup = io.BytesIO() backup = io.BytesIO()
backup_zip = zipfile.ZipFile(backup, 'w') backup_zip = zipfile.ZipFile(backup, 'w')
@@ -682,7 +681,7 @@ def export_ctf(segments=None):
result_file.seek(0) result_file.seek(0)
backup_zip.writestr('db/{}.json'.format(item), result_file.read()) backup_zip.writestr('db/{}.json'.format(item), result_file.read())
## Backup uploads # Backup uploads
upload_folder = os.path.join(os.path.normpath(app.root_path), get_config('UPLOAD_FOLDER')) upload_folder = os.path.join(os.path.normpath(app.root_path), get_config('UPLOAD_FOLDER'))
for root, dirs, files in os.walk(upload_folder): for root, dirs, files in os.walk(upload_folder):
for file in files: for file in files:
@@ -730,7 +729,7 @@ def import_ctf(backup, segments=None, erase=False):
] ]
} }
## Need special handling of metadata # Need special handling of metadata
if 'metadata' in segments: if 'metadata' in segments:
meta = groups['metadata'] meta = groups['metadata']
segments.remove('metadata') segments.remove('metadata')
@@ -741,7 +740,7 @@ def import_ctf(backup, segments=None, erase=False):
path = "db/{}.json".format(item) path = "db/{}.json".format(item)
data = backup.open(path).read() data = backup.open(path).read()
## Some JSON files will be empty # Some JSON files will be empty
if data: if data:
if item == 'config': if item == 'config':
saved = json.loads(data) saved = json.loads(data)
@@ -776,7 +775,6 @@ def import_ctf(backup, segments=None, erase=False):
db.session.add(container) db.session.add(container)
db.session.commit() db.session.commit()
for segment in segments: for segment in segments:
group = groups[segment] group = groups[segment]
for item in group: for item in group:
@@ -791,20 +789,20 @@ def import_ctf(backup, segments=None, erase=False):
else: else:
continue continue
## Extracting files # Extracting files
files = [f for f in backup.namelist() if f.startswith('uploads/')] files = [f for f in backup.namelist() if f.startswith('uploads/')]
upload_folder = app.config.get('UPLOAD_FOLDER') upload_folder = app.config.get('UPLOAD_FOLDER')
for f in files: for f in files:
filename = f.split(os.sep, 1) filename = f.split(os.sep, 1)
if len(filename) < 2: ## just an empty uploads directory (e.g. uploads/) if len(filename) < 2: # just an empty uploads directory (e.g. uploads/)
continue continue
filename = filename[1] ## Get the second entry in the list (the actual filename) filename = filename[1] # Get the second entry in the list (the actual filename)
full_path = os.path.join(upload_folder, filename) full_path = os.path.join(upload_folder, filename)
dirname = os.path.dirname(full_path) dirname = os.path.dirname(full_path)
## Create any parent directories for the file # Create any parent directories for the file
if not os.path.exists(dirname): if not os.path.exists(dirname):
os.makedirs(dirname) os.makedirs(dirname)

View File

@@ -45,7 +45,7 @@ def setup():
# Index page # Index page
page = Pages('index', """<div class="container main-container"> page = Pages('index', """<div class="container main-container">
<img class="logo" src="{0}/static/original/img/logo.png" /> <img class="logo" src="static/original/img/logo.png" />
<h3 class="text-center"> <h3 class="text-center">
<p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p> <p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
<p>Follow us on social media:</p> <p>Follow us on social media:</p>
@@ -55,7 +55,7 @@ def setup():
</h3> </h3>
<br> <br>
<h4 class="text-center"> <h4 class="text-center">
<a href="{0}/admin">Click here</a> to login and setup your CTF <a href="admin">Click here</a> to login and setup your CTF
</h4> </h4>
</div>""".format(request.script_root)) </div>""".format(request.script_root))

View File

@@ -3,3 +3,4 @@ coverage>=4.1
mock>=2.0.0 mock>=2.0.0
nose>=1.3.7 nose>=1.3.7
rednose>=1.1.1 rednose>=1.1.1
pep8==1.7.0

View File

@@ -106,6 +106,7 @@ def gen_solve(db, chalid, teamid, ip='127.0.0.1', flag='rightkey'):
db.session.commit() db.session.commit()
return solve return solve
def gen_wrongkey(db, teamid, chalid, flag='wrongkey'): def gen_wrongkey(db, teamid, chalid, flag='wrongkey'):
wrongkey = WrongKeys(teamid, chalid, flag) wrongkey = WrongKeys(teamid, chalid, flag)
db.session.add(wrongkey) db.session.add(wrongkey)

View File

@@ -22,7 +22,7 @@ def test_register_user():
def test_register_duplicate_teamname(): def test_register_duplicate_teamname():
"""A user shouldn't be able to use and already registered team name""" """A user shouldn't be able to use an already registered team name"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app, name="user1", email="user1@ctfd.io", password="password") register_user(app, name="user1", email="user1@ctfd.io", password="password")
@@ -74,7 +74,7 @@ def test_user_isnt_admin():
def test_user_get_teams(): def test_user_get_teams():
"""Can a registered user can load /teams""" """Can a registered user load /teams"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -84,7 +84,7 @@ def test_user_get_teams():
def test_user_get_scoreboard(): def test_user_get_scoreboard():
"""Can a registered user can load /scoreboard""" """Can a registered user load /scoreboard"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -94,7 +94,7 @@ def test_user_get_scoreboard():
def test_user_get_scores(): def test_user_get_scores():
"""Can a registered user can load /scores""" """Can a registered user load /scores"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -104,7 +104,7 @@ def test_user_get_scores():
def test_user_get_topteams(): def test_user_get_topteams():
"""Can a registered user can load /top/10""" """Can a registered user load /top/10"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -114,7 +114,7 @@ def test_user_get_topteams():
def test_user_get_challenges(): def test_user_get_challenges():
"""Can a registered user can load /challenges""" """Can a registered user load /challenges"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -124,7 +124,7 @@ def test_user_get_challenges():
def test_user_get_chals(): def test_user_get_chals():
"""Can a registered user can load /chals""" """Can a registered user load /chals"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -134,7 +134,7 @@ def test_user_get_chals():
def test_user_get_solves_per_chal(): def test_user_get_solves_per_chal():
"""Can a registered user can load /chals/solves""" """Can a registered user load /chals/solves"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -144,7 +144,7 @@ def test_user_get_solves_per_chal():
def test_user_get_solves(): def test_user_get_solves():
"""Can a registered user can load /solves""" """Can a registered user load /solves"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -154,7 +154,7 @@ def test_user_get_solves():
def test_user_get_team_page(): def test_user_get_team_page():
"""Can a registered user can load their public profile (/team/2)""" """Can a registered user load their public profile (/team/2)"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)
@@ -164,7 +164,7 @@ def test_user_get_team_page():
def test_user_get_profile(): def test_user_get_profile():
"""Can a registered user can load their private profile (/profile)""" """Can a registered user load their private profile (/profile)"""
app = create_ctfd() app = create_ctfd()
with app.app_context(): with app.app_context():
register_user(app) register_user(app)