Max attmpts (#227)

* Making max_attempts use the Challenge value instead of the Config value
This commit is contained in:
Kevin Chung
2017-03-09 23:47:08 -05:00
committed by GitHub
parent 92c7f2e293
commit 613ede5738
10 changed files with 89 additions and 19 deletions

View File

@@ -103,8 +103,6 @@ def admin_config():
mg_base_url = set_config("mg_base_url", request.form.get('mg_base_url', None)) mg_base_url = set_config("mg_base_url", request.form.get('mg_base_url', None))
mg_api_key = set_config("mg_api_key", request.form.get('mg_api_key', None)) mg_api_key = set_config("mg_api_key", request.form.get('mg_api_key', None))
max_tries = set_config("max_tries", request.form.get('max_tries', None))
db_start = Config.query.filter_by(key='start').first() db_start = Config.query.filter_by(key='start').first()
db_start.value = start db_start.value = start
@@ -124,7 +122,6 @@ def admin_config():
cache.clear() cache.clear()
ctf_name = get_config('ctf_name') ctf_name = get_config('ctf_name')
ctf_theme = get_config('ctf_theme') ctf_theme = get_config('ctf_theme')
max_tries = get_config('max_tries')
hide_scores = get_config('hide_scores') hide_scores = get_config('hide_scores')
mail_server = get_config('mail_server') mail_server = get_config('mail_server')
@@ -135,9 +132,6 @@ def admin_config():
mailfrom_addr = get_config('mailfrom_addr') mailfrom_addr = get_config('mailfrom_addr')
mg_api_key = get_config('mg_api_key') mg_api_key = get_config('mg_api_key')
mg_base_url = get_config('mg_base_url') mg_base_url = get_config('mg_base_url')
if not max_tries:
set_config('max_tries', 0)
max_tries = 0
view_after_ctf = get_config('view_after_ctf') view_after_ctf = get_config('view_after_ctf')
start = get_config('start') start = get_config('start')
@@ -164,7 +158,6 @@ def admin_config():
start=start, start=start,
end=end, end=end,
hide_scores=hide_scores, hide_scores=hide_scores,
max_tries=max_tries,
mail_server=mail_server, mail_server=mail_server,
mail_port=mail_port, mail_port=mail_port,
mail_username=mail_username, mail_username=mail_username,

View File

@@ -24,7 +24,7 @@ def admin_chal_types():
@admins_only @admins_only
def admin_chals(): def admin_chals():
if request.method == 'POST': if request.method == 'POST':
chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden').order_by(Challenges.value).all() chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category', 'hidden', 'max_attempts').order_by(Challenges.value).all()
teams_with_points = db.session.query(Solves.teamid).join(Teams).filter( teams_with_points = db.session.query(Solves.teamid).join(Teams).filter(
Teams.banned == False).group_by(Solves.teamid).count() Teams.banned == False).group_by(Solves.teamid).count()
@@ -45,6 +45,7 @@ def admin_chals():
'description': x.description, 'description': x.description,
'category': x.category, 'category': x.category,
'hidden': x.hidden, 'hidden': x.hidden,
'max_attempts': x.max_attempts,
'percentage_solved': percentage 'percentage_solved': percentage
}) })
@@ -145,6 +146,11 @@ def admin_create_chal():
chal.hidden = True chal.hidden = True
else: else:
chal.hidden = False chal.hidden = False
max_attempts = request.form.get('max_attempts')
if max_attempts and max_attempts.isdigit():
chal.max_attempts = int(max_attempts)
db.session.add(chal) db.session.add(chal)
db.session.flush() db.session.flush()
@@ -191,7 +197,8 @@ def admin_update_chal():
challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404() challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404()
challenge.name = request.form['name'] challenge.name = request.form['name']
challenge.description = request.form['desc'] challenge.description = request.form['desc']
challenge.value = request.form['value'] challenge.value = int(request.form.get('value', 0)) if request.form.get('value', 0) else 0
challenge.max_attempts = int(request.form.get('max_attempts', 0)) if request.form.get('max_attempts', 0) else 0
challenge.category = request.form['category'] challenge.category = request.form['category']
challenge.hidden = 'hidden' in request.form challenge.hidden = 'hidden' in request.form
db.session.add(challenge) db.session.add(challenge)

View File

@@ -205,8 +205,8 @@ def chal(chalid):
saved_keys = Keys.query.filter_by(chal=chal.id).all() saved_keys = Keys.query.filter_by(chal=chal.id).all()
# Hit max attempts # Hit max attempts
max_tries = int(get_config("max_tries")) max_tries = chal.max_attempts
if fails >= max_tries > 0: if max_tries and fails >= max_tries > 0:
return jsonify({ return jsonify({
'status': '0', 'status': '0',
'message': "You have 0 tries remaining" 'message': "You have 0 tries remaining"
@@ -230,7 +230,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 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

@@ -58,6 +58,7 @@ class Challenges(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80)) name = db.Column(db.String(80))
description = db.Column(db.Text) description = db.Column(db.Text)
max_attempts = db.Column(db.Integer, default=0)
value = db.Column(db.Integer) value = db.Column(db.Integer)
category = db.Column(db.String(80)) category = db.Column(db.String(80))
type = db.Column(db.Integer) type = db.Column(db.Integer)

View File

@@ -49,6 +49,11 @@ function loadchal(id, update) {
$('.chal-name').val(obj.name); $('.chal-name').val(obj.name);
$('.chal-desc').val(obj.description); $('.chal-desc').val(obj.description);
$('.chal-value').val(obj.value); $('.chal-value').val(obj.value);
if (parseInt(obj.max_attempts) > 0){
$('.chal-attempts').val(obj.max_attempts);
$('#limit_max_attempts').prop('checked', true);
$('#chal-attempts-group').show();
}
$('.chal-category').val(obj.category); $('.chal-category').val(obj.category);
$('.chal-id').val(obj.id); $('.chal-id').val(obj.id);
$('.chal-hidden').prop('checked', false); $('.chal-hidden').prop('checked', false);
@@ -309,7 +314,14 @@ $(".tag-insert").keyup(function (e) {
} }
}); });
$('#limit_max_attempts').change(function() {
if(this.checked) {
$('#chal-attempts-group').show();
} else {
$('#chal-attempts-group').hide();
$('#chal-attempts-input').val('');
}
});
// Markdown Preview // Markdown Preview
$('#desc-edit').on('shown.bs.tab', function (event) { $('#desc-edit').on('shown.bs.tab', function (event) {

View File

@@ -66,6 +66,19 @@
</div> </div>
</div> </div>
<div class="form-group">
<div class="checkbox">
<label>
<input name="hidden" type="checkbox" id="solve-attempts-checkbox">
Limit amount of solve attempts
</label>
</div>
<div id="solve-attempts-input" style="display: none;">
<label for="max_attempts">Maximum Attempts</label>
<input class="form-control" id='max_attempts' name='max_attempts' type='number' placeholder="0">
</div>
</div>
<div class="row"> <div class="row">
<div class="form-group"> <div class="form-group">
<div class="col-md-9"> <div class="col-md-9">

View File

@@ -1,11 +1,19 @@
// Markdown Preview // Markdown Preview
$('#desc-edit').on('shown.bs.tab', function (event) { $('#desc-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#desc-preview'){ if (event.target.hash == '#desc-preview'){
$(event.target.hash).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true})) $(event.target.hash).html(marked($('#desc-editor').val(), {'gfm':true, 'breaks':true}));
} }
}); });
$('#new-desc-edit').on('shown.bs.tab', function (event) { $('#new-desc-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#new-desc-preview'){ if (event.target.hash == '#new-desc-preview'){
$(event.target.hash).html(marked($('#new-desc-editor').val(), {'gfm':true, 'breaks':true})) $(event.target.hash).html(marked($('#new-desc-editor').val(), {'gfm':true, 'breaks':true}));
}
});
$("#solve-attempts-checkbox").change(function() {
if(this.checked) {
$('#solve-attempts-input').show();
} else {
$('#solve-attempts-input').hide();
$('#max_attempts').val('');
} }
}); });

View File

@@ -137,6 +137,18 @@
<label for="value">Value</label> <label for="value">Value</label>
<input type="number" class="form-control chal-value" name="value" placeholder="Enter value" required> <input type="number" class="form-control chal-value" name="value" placeholder="Enter value" required>
</div> </div>
<div class="checkbox">
<label>
<input class="chal-attempts-checkbox" id="limit_max_attempts" name="limit_max_attempts" type="checkbox">
Limit challenge attempts
</label>
</div>
<div class="form-group" id="chal-attempts-group" style="display:none;">
<label for="value">Max Attempts</label>
<input type="number" class="form-control chal-attempts" id="chal-attempts-input" name="max_attempts" placeholder="Enter value">
</div>
<input class="chal-id" type='hidden' name='id' placeholder='ID'> <input class="chal-id" type='hidden' name='id' placeholder='ID'>
<div class="checkbox"> <div class="checkbox">

View File

@@ -59,10 +59,6 @@
</div> </div>
</div> </div>
<div role="tabpanel" class="tab-pane" id="accounts-section"> <div role="tabpanel" class="tab-pane" id="accounts-section">
<div class="form-group">
<label for="max_tries">Maximum Attempts Per Challenge (0 to disable):</label>
<input class="form-control" id='max_tries' name='max_tries' type='text' placeholder="0" {% if max_tries is defined and max_tries != None %}value="{{ max_tries }}"{% endif %}>
</div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input id="verify_emails" name="verify_emails" type="checkbox" {% if verify_emails %}checked{% endif %}> <input id="verify_emails" name="verify_emails" type="checkbox" {% if verify_emails %}checked{% endif %}>

View File

@@ -0,0 +1,28 @@
"""Adding max_attempts to Challenges
Revision ID: d6514ec92738
Revises: a4e30c94c360
Create Date: 2017-03-09 01:20:31.423407
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'd6514ec92738'
down_revision = 'a4e30c94c360'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('challenges', sa.Column('max_attempts', sa.Integer(), nullable=True, default=0))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('challenges', 'max_attempts')
# ### end Alembic commands ###