Implement grader scripts
This commit is contained in:
parent
6aa0a119ff
commit
19d9fe32eb
9 changed files with 63 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
.vagrant
|
.vagrant
|
||||||
.secret_key
|
.secret_key
|
||||||
.bundle/config
|
.bundle/config
|
||||||
|
graders/
|
||||||
logs/
|
logs/
|
||||||
files/
|
files/
|
||||||
pfp/
|
pfp/
|
||||||
|
|
|
@ -23,7 +23,7 @@ def problem_data():
|
||||||
"value": problem.value,
|
"value": problem.value,
|
||||||
"threshold": problem.threshold,
|
"threshold": problem.threshold,
|
||||||
"weightmap": problem.weightmap,
|
"weightmap": problem.weightmap,
|
||||||
"flag": problem.flag
|
"grader_contents": open(problem.grader, "r").read()
|
||||||
})
|
})
|
||||||
problems_return.sort(key=lambda prob: prob["value"])
|
problems_return.sort(key=lambda prob: prob["value"])
|
||||||
return { "success": 1, "problems": problems_return }
|
return { "success": 1, "problems": problems_return }
|
||||||
|
|
|
@ -135,7 +135,6 @@ class Problems(db.Model):
|
||||||
pid = db.Column(db.String(32), primary_key=True, autoincrement=False)
|
pid = db.Column(db.String(32), primary_key=True, autoincrement=False)
|
||||||
title = db.Column(db.String(128))
|
title = db.Column(db.String(128))
|
||||||
category = db.Column(db.String(128))
|
category = db.Column(db.String(128))
|
||||||
flag = db.Column(db.String(128))
|
|
||||||
description = db.Column(db.Text)
|
description = db.Column(db.Text)
|
||||||
value = db.Column(db.Integer)
|
value = db.Column(db.Integer)
|
||||||
hint = db.Column(db.Text)
|
hint = db.Column(db.Text)
|
||||||
|
@ -143,13 +142,13 @@ class Problems(db.Model):
|
||||||
bonus = db.Column(db.Integer)
|
bonus = db.Column(db.Integer)
|
||||||
threshold = db.Column(db.Integer)
|
threshold = db.Column(db.Integer)
|
||||||
weightmap = db.Column(db.PickleType)
|
weightmap = db.Column(db.PickleType)
|
||||||
|
grader = db.Column(db.Text)
|
||||||
|
|
||||||
def __init__(self, pid, title, category, description, flag, value, hint="", autogen=False, bonus=0, threshold=0, weightmap={}):
|
def __init__(self, pid, title, category, description, value, hint="", autogen=False, bonus=0, threshold=0, weightmap={}):
|
||||||
self.pid = pid
|
self.pid = pid
|
||||||
self.title = title
|
self.title = title
|
||||||
self.category = category
|
self.category = category
|
||||||
self.description = description
|
self.description = description
|
||||||
self.flag = flag
|
|
||||||
self.value = value
|
self.value = value
|
||||||
self.hint = hint
|
self.hint = hint
|
||||||
self.autogen = autogen
|
self.autogen = autogen
|
||||||
|
|
|
@ -20,8 +20,8 @@ def problem_add():
|
||||||
category = request.form["category"]
|
category = request.form["category"]
|
||||||
description = request.form["description"]
|
description = request.form["description"]
|
||||||
hint = request.form["hint"]
|
hint = request.form["hint"]
|
||||||
flag = request.form["flag"]
|
|
||||||
value = request.form["value"]
|
value = request.form["value"]
|
||||||
|
grader_contents = request.form["grader_contents"]
|
||||||
pid = utils.generate_string()
|
pid = utils.generate_string()
|
||||||
while Problems.query.filter_by(pid=pid).first():
|
while Problems.query.filter_by(pid=pid).first():
|
||||||
pid = utils.generate_string()
|
pid = utils.generate_string()
|
||||||
|
@ -30,7 +30,7 @@ def problem_add():
|
||||||
if title_exist:
|
if title_exist:
|
||||||
raise WebException("Problem name already taken.")
|
raise WebException("Problem name already taken.")
|
||||||
|
|
||||||
problem = Problems(pid, title, category, description, flag, value, hint=hint)
|
problem = Problems(pid, title, category, description, value, hint=hint)
|
||||||
db.session.add(problem)
|
db.session.add(problem)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -47,6 +47,14 @@ def problem_add():
|
||||||
db_file = Files(problem.pid, "/".join(file_path.split("/")[2:]))
|
db_file = Files(problem.pid, "/".join(file_path.split("/")[2:]))
|
||||||
db.session.add(db_file)
|
db.session.add(db_file)
|
||||||
|
|
||||||
|
grader_folder = os.path.join(app.config["GRADER_FOLDER"], pid)
|
||||||
|
if not os.path.exists(grader_folder):
|
||||||
|
os.makedirs(grader_folder)
|
||||||
|
grader_path = os.path.join(grader_folder, "grader.py")
|
||||||
|
grader_file = open(grader_path, "w")
|
||||||
|
grader_file.write(grader_contents)
|
||||||
|
grader_file.close()
|
||||||
|
problem.grader = grader_path
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return { "success": 1, "message": "Success!" }
|
return { "success": 1, "message": "Success!" }
|
||||||
|
@ -73,8 +81,8 @@ def problem_update():
|
||||||
category = request.form["category"]
|
category = request.form["category"]
|
||||||
description = request.form["description"]
|
description = request.form["description"]
|
||||||
hint = request.form["hint"]
|
hint = request.form["hint"]
|
||||||
flag = request.form["flag"]
|
|
||||||
value = request.form["value"]
|
value = request.form["value"]
|
||||||
|
grader_contents = request.form["grader_contents"]
|
||||||
|
|
||||||
problem = Problems.query.filter_by(pid=pid).first()
|
problem = Problems.query.filter_by(pid=pid).first()
|
||||||
if problem:
|
if problem:
|
||||||
|
@ -82,9 +90,12 @@ def problem_update():
|
||||||
problem.category = category
|
problem.category = category
|
||||||
problem.description = description
|
problem.description = description
|
||||||
problem.hint = hint
|
problem.hint = hint
|
||||||
problem.flag = flag
|
|
||||||
problem.value = value
|
problem.value = value
|
||||||
|
|
||||||
|
grader = open(problem.grader, "w")
|
||||||
|
grader.write(grader_contents)
|
||||||
|
grader.close()
|
||||||
|
|
||||||
db.session.add(problem)
|
db.session.add(problem)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ app.config.from_object(config)
|
||||||
|
|
||||||
if not os.path.exists(app.config["UPLOAD_FOLDER"]):
|
if not os.path.exists(app.config["UPLOAD_FOLDER"]):
|
||||||
os.makedirs(app.config["UPLOAD_FOLDER"])
|
os.makedirs(app.config["UPLOAD_FOLDER"])
|
||||||
|
if not os.path.exists(app.config["GRADER_FOLDER"]):
|
||||||
|
os.makedirs(app.config["GRADER_FOLDER"])
|
||||||
if not os.path.exists("pfp"):
|
if not os.path.exists("pfp"):
|
||||||
os.makedirs("pfp")
|
os.makedirs("pfp")
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ SQLALCHEMY_DATABASE_URI = "mysql://root:i_hate_passwords@localhost/easyctf"
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
|
||||||
UPLOAD_FOLDER = os.path.normpath("../web/files")
|
UPLOAD_FOLDER = os.path.normpath("../web/files")
|
||||||
|
GRADER_FOLDER = os.path.normpath("graders")
|
||||||
|
|
||||||
CTF_BEGIN = 0 # To be used later
|
CTF_BEGIN = 0 # To be used later
|
||||||
CTF_END = 0 # To be used later
|
CTF_END = 0 # To be used later
|
||||||
|
|
|
@ -7,6 +7,8 @@ $(document).ready(function() {
|
||||||
var create_problem = function() {
|
var create_problem = function() {
|
||||||
var input = "#new_problem_form input";
|
var input = "#new_problem_form input";
|
||||||
var data = $("#new_problem_form").serializeObject();
|
var data = $("#new_problem_form").serializeObject();
|
||||||
|
var grader_contents = ace.edit("new_grader").getValue();
|
||||||
|
data["grader_contents"] = grader_contents;
|
||||||
$(input).attr("disabled", "disabled");
|
$(input).attr("disabled", "disabled");
|
||||||
api_call("POST", "/api/problem/add", data, function(result) {
|
api_call("POST", "/api/problem/add", data, function(result) {
|
||||||
if (result["success"] == 1) {
|
if (result["success"] == 1) {
|
||||||
|
@ -30,6 +32,10 @@ var update_problem = function(form_id) {
|
||||||
var input = "#" + form_id + " input";
|
var input = "#" + form_id + " input";
|
||||||
var data = $("#" + form_id).serializeObject();
|
var data = $("#" + form_id).serializeObject();
|
||||||
pid = data["pid"];
|
pid = data["pid"];
|
||||||
|
|
||||||
|
var grader_contents = ace.edit(pid + "_grader").getValue();
|
||||||
|
data["grader_contents"] = grader_contents;
|
||||||
|
|
||||||
$(input).attr("disabled", "disabled");
|
$(input).attr("disabled", "disabled");
|
||||||
api_call("POST", "/api/problem/update", data, function(result) {
|
api_call("POST", "/api/problem/update", data, function(result) {
|
||||||
if (result["success"] == 1) {
|
if (result["success"] == 1) {
|
||||||
|
|
|
@ -216,6 +216,34 @@ app.controller("adminProblemsController", ["$controller", "$scope", "$http", fun
|
||||||
$scope.problems = [];
|
$scope.problems = [];
|
||||||
}
|
}
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
$scope.problems.forEach(function(problem) {
|
||||||
|
|
||||||
|
$(".selectpicker").selectpicker();
|
||||||
|
var config = {
|
||||||
|
toolbar: [
|
||||||
|
{ name: "basicstyles", items: [ "Bold", "Italic", "Underline" ] },
|
||||||
|
{ name: "links", items: [ "Link" ] },
|
||||||
|
{ name: "paragraph", items: [ "NumberedList", "BulletedList", "-", "Outdent", "Indent", "-", "Blockquote" ] },
|
||||||
|
{ name: "tools", items: [ "Maximize" ] },
|
||||||
|
{ name: "document", items: [ "Source" ] },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
var editor = new EpicEditor({
|
||||||
|
container: "new_grader",
|
||||||
|
theme: {
|
||||||
|
base: "https://cdnjs.cloudflare.com/ajax/libs/epiceditor/0.2.2/themes/base/epiceditor.css",
|
||||||
|
preview: "https://cdnjs.cloudflare.com/ajax/libs/epiceditor/0.2.2/themes/preview/github.css",
|
||||||
|
editor: "https://cdnjs.cloudflare.com/ajax/libs/epiceditor/0.2.2/themes/editor/epic-light.css"
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
bar: "show"
|
||||||
|
}
|
||||||
|
}).load();
|
||||||
|
var grader = ace.edit(problem.pid + "_grader");
|
||||||
|
grader.setTheme("ace/theme/tomorrow");
|
||||||
|
grader.getSession().setMode("ace/mode/python");
|
||||||
|
grader.setValue(problem.grader_contents);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
<div class="row"> <div class="tabbable"> <ul class="nav nav-pills nav-stacked col-md-3">
|
<div class="row"> <div class="tabbable"> <ul class="nav nav-pills nav-stacked col-md-3">
|
||||||
<li class="active"><a data-target="#new" data-toggle="tab">New</a></li>
|
<li class="active"><a data-target="#new" data-toggle="tab">New</a></li>
|
||||||
<li ng-repeat="problem in problems"><a data-target="#problem_{{ problem['pid'] }}" data-toggle="tab">{{ problem["name"] }} ({{ problem["value"] }} points)</a></li>
|
<li ng-repeat="problem in problems"><a data-target="#problem_{{ problem['pid'] }}" data-toggle="tab">{{ problem["title"] }} ({{ problem["value"] }} points)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content col-md-9">
|
<div class="tab-content col-md-9">
|
||||||
<div class="tab-pane active" id="new">
|
<div class="tab-pane active" id="new">
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="add-status"></div>
|
<div id="add-status"></div>
|
||||||
<form class="form-horizontal" onsubmit="create_problem(); return false;" id="new_problem_form">
|
<form class="form-horizontal" onsubmit="create_problem(); return false;" id="new_problem_form">
|
||||||
<input class="form-control" name="name" placeholder="Name" required/>
|
<input class="form-control" name="title" placeholder="Name" required/>
|
||||||
<br>
|
<br>
|
||||||
<textarea class="form-control" name="description" placeholder="Description" required autocomplete="off"/>
|
<textarea class="form-control" name="description" placeholder="Description" required autocomplete="off"/>
|
||||||
<br>
|
<br>
|
||||||
|
@ -35,8 +35,6 @@
|
||||||
<br>
|
<br>
|
||||||
<input class="form-control" name="value" type="number" placeholder="Problem Value" required autocomplete="off"/>
|
<input class="form-control" name="value" type="number" placeholder="Problem Value" required autocomplete="off"/>
|
||||||
<br>
|
<br>
|
||||||
<input class="form-control" name="flag" placeholder="Flag" required/>
|
|
||||||
<br>
|
|
||||||
<div id="new_grader"></div>
|
<div id="new_grader"></div>
|
||||||
<br>
|
<br>
|
||||||
<input type="submit" id="create-problem" class="btn btn-success" value="Create"/>
|
<input type="submit" id="create-problem" class="btn btn-success" value="Create"/>
|
||||||
|
@ -47,13 +45,13 @@
|
||||||
<div class="tab-pane" ng-repeat="problem in problems" id="problem_{{ problem['pid'] }}">
|
<div class="tab-pane" ng-repeat="problem in problems" id="problem_{{ problem['pid'] }}">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">{{ problem["name"] }}</h4>
|
<h4 class="panel-title">{{ problem["title"] }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="{{ problem['pid'] }}_status"/>
|
<div id="{{ problem['pid'] }}_status"/>
|
||||||
<form class="form-horizontal" onsubmit="update_problem(this.id); return false;" id="update_{{ problem['pid'] }}">
|
<form class="form-horizontal" onsubmit="update_problem(this.id); return false;" id="update_{{ problem['pid'] }}">
|
||||||
<input type="hidden" name="pid" value="{{ problem['pid'] }}"/>
|
<input type="hidden" name="pid" value="{{ problem['pid'] }}"/>
|
||||||
<input class="form-control" name="name" value="{{ problem['name'] }}" required/>
|
<input class="form-control" name="title" value="{{ problem['title'] }}" required/>
|
||||||
<br>
|
<br>
|
||||||
<textarea class="form-control" name="description" required autocomplete="off">{{ problem["description"] }}</textarea>
|
<textarea class="form-control" name="description" required autocomplete="off">{{ problem["description"] }}</textarea>
|
||||||
<br>
|
<br>
|
||||||
|
@ -63,7 +61,7 @@
|
||||||
<br>
|
<br>
|
||||||
<input class="form-control" type="number" name="value" value="{{ problem['value'] }}" required/>
|
<input class="form-control" type="number" name="value" value="{{ problem['value'] }}" required/>
|
||||||
<br>
|
<br>
|
||||||
<input class="form-control" name="flag" value="{{ problem['flag'] }}" required/>
|
<div id="{{ problem['pid'] }}_grader"></div>
|
||||||
<br>
|
<br>
|
||||||
<input type="submit" class="btn btn-success" value="Update"/>
|
<input type="submit" class="btn btn-success" value="Update"/>
|
||||||
<input onclick="delete_problem(this.closest('form').id); return false;" class="btn btn-danger" value="Delete"/>
|
<input onclick="delete_problem(this.closest('form').id); return false;" class="btn btn-danger" value="Delete"/>
|
||||||
|
|
Loading…
Reference in a new issue