diff --git a/CTFd/challenges.py b/CTFd/challenges.py index a084c39..58112f9 100644 --- a/CTFd/challenges.py +++ b/CTFd/challenges.py @@ -144,9 +144,21 @@ def solves_per_chal(): if not utils.user_can_view_challenges(): return redirect(url_for('auth.login', next=request.path)) - solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves')).join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False).group_by(Solves.chalid).subquery() - solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves, Challenges.name) \ - .join(Challenges, solves_sub.columns.chalid == Challenges.id).all() + solves_sub = db.session.query( + Solves.chalid, + db.func.count(Solves.chalid).label('solves') + )\ + .join(Teams, Solves.teamid == Teams.id) \ + .filter(Teams.banned == False) \ + .group_by(Solves.chalid).subquery() + + solves = db.session.query( + solves_sub.columns.chalid, + solves_sub.columns.solves, + Challenges.name + ) \ + .join(Challenges, solves_sub.columns.chalid == Challenges.id).all() + json = {} if utils.hide_scores(): for chal, count, name in solves: @@ -174,18 +186,23 @@ def solves(teamid=None): else: return redirect(url_for('auth.login', next='solves')) else: - solves = Solves.query.filter_by(teamid=teamid) - awards = Awards.query.filter_by(teamid=teamid) + if utils.hide_scores(): + # Use empty values to hide scores + solves = [] + awards = [] + else: + solves = Solves.query.filter_by(teamid=teamid) + awards = Awards.query.filter_by(teamid=teamid) - freeze = utils.get_config('freeze') - if freeze: - freeze = utils.unix_time_to_utc(freeze) - if teamid != session.get('id'): - solves = solves.filter(Solves.date < freeze) - awards = awards.filter(Awards.date < freeze) + freeze = utils.get_config('freeze') + if freeze: + freeze = utils.unix_time_to_utc(freeze) + if teamid != session.get('id'): + solves = solves.filter(Solves.date < freeze) + awards = awards.filter(Awards.date < freeze) - solves = solves.all() - awards = awards.all() + solves = solves.all() + awards = awards.all() db.session.close() json = {'solves': []} for solve in solves: @@ -224,10 +241,19 @@ def attempts(): return jsonify(json) -@challenges.route('/fails/', methods=['GET']) -def fails(teamid): - fails = WrongKeys.query.filter_by(teamid=teamid).count() - solves = Solves.query.filter_by(teamid=teamid).count() +@challenges.route('/fails') +@challenges.route('/fails/') +def fails(teamid=None): + if teamid is None: + fails = WrongKeys.query.filter_by(teamid=session['id']).count() + solves = Solves.query.filter_by(teamid=session['id']).count() + else: + if utils.hide_scores(): + fails = 0 + solves = 0 + else: + fails = WrongKeys.query.filter_by(teamid=teamid).count() + solves = Solves.query.filter_by(teamid=teamid).count() db.session.close() json = {'fails': str(fails), 'solves': str(solves)} return jsonify(json) diff --git a/tests/user/test_challenges.py b/tests/user/test_challenges.py index eb93752..91914db 100644 --- a/tests/user/test_challenges.py +++ b/tests/user/test_challenges.py @@ -45,6 +45,44 @@ def test_viewing_challenges(): destroy_ctfd(app) +def test_chals_solves(): + '''Test that the /chals/solves endpoint works properly''' + app = create_ctfd() + with app.app_context(): + # Generate 5 users + for c in range(1, 6): + name = "user{}".format(c) + email = "user{}@ctfd.io".format(c) + register_user(app, name=name, email=email, password="password") + + # Generate 5 challenges + for c in range(5): + chal1 = gen_challenge(app.db, value=100) + + user_ids = list(range(2, 7)) + chal_ids = list(range(1, 6)) + for u in user_ids: + for c in chal_ids: + gen_solve(app.db, teamid=u, chalid=c) + chal_ids.pop() + + client = login_as_user(app, name="user1") + + with client.session_transaction() as sess: + r = client.get('/chals/solves') + output = r.get_data(as_text=True) + saved = json.loads('''{ + "1": 5, + "2": 4, + "3": 3, + "4": 2, + "5": 1 + } + ''') + received = json.loads(output) + assert saved == received + + def test_submitting_correct_flag(): """Test that correct flags are correct""" app = create_ctfd()