Problem editor.

This commit is contained in:
Michael Zhang 2016-03-12 01:34:26 -06:00
parent e9bf0be78b
commit dae7aec24e
16 changed files with 276 additions and 327 deletions

View file

@ -14,7 +14,7 @@ server {
# }
# Put all the pages here so Angular doesn't fail.
location ~^/(about|chat|help|learn|login|profile|register|scoreboard|settings|team|forgot)$ {
location ~^/(about|chat|help|learn|login|logout|profile|register|scoreboard|settings|team|forgot)$ {
default_type text/html;
try_files /index.html /index.html;
}

View file

@ -3,9 +3,9 @@
"title": "Cancer",
"hint": "No hint!",
"category": "Miscellaneous",
"autogen": false,
"autogen": true,
"programming": false,
"value": 20,
"value": 100,
"bonus": 0,
"threshold": 0,
"weightmap": { }

View file

@ -5,4 +5,5 @@ SQLAlchemy
gunicorn
requests
voluptuous
PIL
PIL
markdown2

View file

@ -3,7 +3,7 @@ from decorators import admins_only, api_wrapper
from models import db, Problems, Files
from schemas import verify_to_schema, check
import json
import cPickle as pickle
blueprint = Blueprint("admin", __name__)
@ -16,14 +16,15 @@ def problem_data():
for problem in problems:
problems_return.append({
"pid": problem.pid,
"name": problem.name,
"title": problem.title,
"category": problem.category,
"description": problem.description,
"hint": problem.hint,
"value": problem.value,
"threshold": problem.threshold,
"weightmap": json.loads(problem.weightmap)
"weightmap": problem.weightmap
})
problems_return.sort(key=lambda prob: prob["value"])
return { "success": 1, "problems": problems_return }
"""

View file

@ -7,6 +7,7 @@ import traceback
import utils
class WebException(Exception): pass
class InternalException(Exception): pass
response_header = { "Content-Type": "application/json; charset=utf-8" }
def api_wrapper(f):

View file

@ -28,7 +28,7 @@ def initialize_logs():
for importer, modname, ispkg in pkgutil.walk_packages(path="../api"):
create_logger(modname)
def log(logname, level, message):
def log(logname, message, level=INFO):
logger = logging.getLogger(logname)
message = "[%s] %s" % (datetime.datetime.now().strftime("%m/%d/%Y %X"), message)
logger.log(level, message)

View file

@ -3,6 +3,7 @@ from flask.ext.sqlalchemy import SQLAlchemy
import time
import traceback
import utils
import cPickle as pickle
db = SQLAlchemy()
@ -70,17 +71,14 @@ class Teams(db.Model):
return members
def points(self):
score = db.func.sum(Problems.value).label("score")
team = db.session.query(Solves.tid, score).join(Teams).join(Problems).filter(Teams.tid==self.tid).group_by(Solves.tid).first()
if team:
return team.score
else:
return 0
""" TODO: Implement scoring with Bonus Points """
return 0
def place(self, ranked=True):
score = db.func.sum(Problems.value).label("score")
quickest = db.func.max(Solves.date).label("quickest")
teams = db.session.query(Solves.tid).join(Teams).join(Problems).filter().group_by(Solves.tid).order_by(score.desc(), quickest).all()
# score = db.func.sum(Problems.value).label("score")
# quickest = db.func.max(Solves.date).label("quickest")
# teams = db.session.query(Solves.tid).join(Teams).join(Problems).filter().group_by(Solves.tid).order_by(score.desc(), quickest).all()
teams = [ self.tid ]
try:
i = teams.index((self.tid,)) + 1
k = i % 10
@ -134,23 +132,28 @@ class Teams(db.Model):
return False
class Problems(db.Model):
pid = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
pid = db.Column(db.String(128), primary_key=True, autoincrement=False)
title = db.Column(db.String(128))
category = db.Column(db.String(128))
description = db.Column(db.Text)
hint = db.Column(db.Text)
flag = db.Column(db.Text)
disabled = db.Column(db.Boolean, default=False)
value = db.Column(db.Integer)
solves = db.Column(db.Integer, default=0)
hint = db.Column(db.Text)
autogen = db.Column(db.Boolean)
bonus = db.Column(db.Integer)
threshold = db.Column(db.Integer)
weightmap = db.Column(db.PickleType)
def __init__(self, name, category, description, hint, flag, value):
self.name = name
def __init__(self, pid, title, category, description, value, hint="", autogen=False, bonus=0, threshold=0, weightmap={}):
self.pid = pid
self.title = title
self.category = category
self.description = description
self.hint = hint
self.flag = flag
self.value = value
self.hint = hint
self.autogen = autogen
self.bonus = bonus
self.threshold = threshold
self.weightmap = weightmap
class Files(db.Model):
fid = db.Column(db.Integer, primary_key=True)
@ -162,12 +165,11 @@ class Files(db.Model):
self.location = location
class Solves(db.Model):
__table_args__ = (db.UniqueConstraint("pid", "tid"), {})
sid = db.Column(db.Integer, primary_key=True)
pid = db.Column(db.Integer, db.ForeignKey("problems.pid"))
tid = db.Column(db.Integer, db.ForeignKey("teams.tid"))
pid = db.Column(db.Integer)
tid = db.Column(db.Integer)
date = db.Column(db.Integer, default=utils.get_time_since_epoch())
team = db.relationship("Teams", foreign_keys="Solves.tid", lazy="joined")
prob = db.relationship("Problems", foreign_keys="Solves.pid", lazy="joined")
correct = db.Column(db.Boolean)
flag = db.Column(db.Text)

View file

@ -7,7 +7,7 @@ from flask import current_app as app
from werkzeug import secure_filename
from models import db, Files, Problems, Solves, Teams
from decorators import admins_only, api_wrapper, login_required, WebException
from decorators import admins_only, api_wrapper, login_required, InternalException, WebException
blueprint = Blueprint("problem", __name__)
@ -15,122 +15,149 @@ blueprint = Blueprint("problem", __name__)
@admins_only
@api_wrapper
def problem_add():
name = request.form["name"]
category = request.form["category"]
description = request.form["description"]
hint = request.form["problem-hint"]
flag = request.form["flag"]
value = request.form["value"]
name = request.form["name"]
category = request.form["category"]
description = request.form["description"]
hint = request.form["problem-hint"]
flag = request.form["flag"]
value = request.form["value"]
name_exists = Problems.query.filter_by(name=name).first()
if name_exists:
raise WebException("Problem name already taken.")
problem = Problems(name, category, description, hint, flag, value)
db.session.add(problem)
db.session.commit()
name_exists = Problems.query.filter_by(name=name).first()
if name_exists:
raise WebException("Problem name already taken.")
problem = Problems(name, category, description, hint, flag, value)
db.session.add(problem)
db.session.commit()
files = request.files.getlist("files[]")
for _file in files:
filename = secure_filename(_file.filename)
files = request.files.getlist("files[]")
for _file in files:
filename = secure_filename(_file.filename)
if len(filename) == 0:
continue
if len(filename) == 0:
continue
file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
_file.save(file_path)
db_file = Files(problem.pid, "/".join(file_path.split("/")[2:]))
db.session.add(db_file)
_file.save(file_path)
db_file = Files(problem.pid, "/".join(file_path.split("/")[2:]))
db.session.add(db_file)
db.session.commit()
db.session.commit()
return { "success": 1, "message": "Success!" }
return { "success": 1, "message": "Success!" }
@blueprint.route("/delete", methods=["POST"])
@admins_only
@api_wrapper
def problem_delete():
pid = request.form["pid"]
problem = Problems.query.filter_by(pid=pid).first()
if problem:
Solves.query.filter_by(pid=pid).delete()
Problems.query.filter_by(pid=pid).delete()
db.session.commit()
return { "success": 1, "message": "Success!" }
raise WebException("Problem does not exist!")
pid = request.form["pid"]
problem = Problems.query.filter_by(pid=pid).first()
if problem:
Solves.query.filter_by(pid=pid).delete()
Problems.query.filter_by(pid=pid).delete()
db.session.commit()
return { "success": 1, "message": "Success!" }
raise WebException("Problem does not exist!")
@blueprint.route("/update", methods=["POST"])
@admins_only
@api_wrapper
def problem_update():
pid = request.form["pid"]
name = request.form["name"]
category = request.form["category"]
description = request.form["description"]
hint = request.form["hint"]
flag = request.form["flag"]
disabled = request.form.get("disabled", 0)
value = request.form["value"]
pid = request.form["pid"]
name = request.form["name"]
category = request.form["category"]
description = request.form["description"]
hint = request.form["hint"]
flag = request.form["flag"]
disabled = request.form.get("disabled", 0)
value = request.form["value"]
problem = Problems.query.filter_by(pid=pid).first()
if problem:
problem.name = name
problem.category = category
problem.description = description
problem.hint = hint
problem.flag = flag
problem.disabled = disabled
problem.value = value
problem = Problems.query.filter_by(pid=pid).first()
if problem:
problem.name = name
problem.category = category
problem.description = description
problem.hint = hint
problem.flag = flag
problem.disabled = disabled
problem.value = value
db.session.add(problem)
db.session.commit()
db.session.add(problem)
db.session.commit()
return { "success": 1, "message": "Success!" }
raise WebException("Problem does not exist!")
return { "success": 1, "message": "Success!" }
raise WebException("Problem does not exist!")
@blueprint.route("/submit", methods=["POST"])
@api_wrapper
@login_required
def problem_submit():
pid = request.form["pid"]
flag = request.form["flag"]
tid = session["tid"]
pid = request.form["pid"]
flag = request.form["flag"]
tid = session["tid"]
problem = Problems.query.filter_by(pid=pid).first()
team = Teams.query.filter_by(tid=tid).first()
if problem:
if flag == problem.flag:
solve = Solves(pid, tid)
team.score += problem.value
problem.solves += 1
db.session.add(solve)
db.session.add(team)
db.session.add(problem)
db.session.commit()
problem = Problems.query.filter_by(pid=pid).first()
team = Teams.query.filter_by(tid=tid).first()
if problem:
if flag == problem.flag:
solve = Solves(pid, tid)
team.score += problem.value
problem.solves += 1
db.session.add(solve)
db.session.add(team)
db.session.add(problem)
db.session.commit()
logger.log(__name__, logger.WARNING, "%s has solved %s by submitting %s" % (team.name, problem.name, flag))
return { "success": 1, "message": "Correct!" }
logger.log(__name__, logger.WARNING, "%s has solved %s by submitting %s" % (team.name, problem.name, flag))
return { "success": 1, "message": "Correct!" }
else:
logger.log(__name__, logger.WARNING, "%s has incorrectly submitted %s to %s" % (team.name, flag, problem.name))
raise WebException("Incorrect.")
else:
logger.log(__name__, logger.WARNING, "%s has incorrectly submitted %s to %s" % (team.name, flag, problem.name))
raise WebException("Incorrect.")
else:
raise WebException("Problem does not exist!")
else:
raise WebException("Problem does not exist!")
@blueprint.route("/data", methods=["POST"])
#@api_wrapper # Disable atm due to json serialization issues: will fix
@login_required
def problem_data():
problems = Problems.query.add_columns("pid", "name", "category", "description", "hint", "value", "solves").order_by(Problems.value).filter_by(disabled=False).all()
jason = []
problems = Problems.query.add_columns("pid", "name", "category", "description", "hint", "value", "solves").order_by(Problems.value).filter_by(disabled=False).all()
jason = []
for problem in problems:
problem_files = [ str(_file.location) for _file in Files.query.filter_by(pid=int(problem.pid)).all() ]
jason.append({"pid": problem[1], "name": problem[2] ,"category": problem[3], "description": problem[4], "hint": problem[5], "value": problem[6], "solves": problem[7], "files": problem_files})
for problem in problems:
problem_files = [ str(_file.location) for _file in Files.query.filter_by(pid=int(problem.pid)).all() ]
jason.append({"pid": problem[1], "name": problem[2] ,"category": problem[3], "description": problem[4], "hint": problem[5], "value": problem[6], "solves": problem[7], "files": problem_files})
return jsonify(data=jason)
return jsonify(data=jason)
def insert_problem(data):
print data
pass
def insert_problem(data, force=False):
with app.app_context():
if len(list(get_problem(pid=data["pid"]).all())) > 0:
if force == True:
_problem = Problems.query.filter_by(pid=data["pid"]).first()
db.session.delete(_problem)
db.session.commit()
else:
raise InternalException("Problem already exists.")
insert = Problems(data["pid"], data["title"], data["category"], data["description"], data["value"])
if "hint" in data: insert.hint = data["hint"]
if "autogen" in data: insert.autogen = data["autogen"]
if "bonus" in data: insert.bonus = data["bonus"]
if "threshold" in data: insert.threshold = data["threshold"]
if "weightmap" in data: insert.weightmap = data["weightmap"]
db.session.add(insert)
db.session.commit()
return True
def get_problem(title=None, pid=None):
match = {}
if title != None:
match.update({ "title": title })
elif pid != None:
match.update({ "pid": pid })
with app.app_context():
result = Problems.query.filter_by(**match)
return result

View file

@ -35,52 +35,53 @@ def team_create():
db.session.commit()
Users.query.filter_by(uid=_user.uid).update({ "tid": team.tid })
db.session.commit()
db.session.close()
session["tid"] = team.tid
session["tid"] = team.tid
return { "success": 1, "message": "Success!" }
@blueprint.route("/delete", methods=["POST"])
@api_wrapper
@login_required
def team_delete():
username = session["username"]
tid = session["tid"]
team = Teams.query.filter_by(tid=tid).first()
usr = Users.query.filter_by(username=username).first()
owner = team.owner
if usr.uid == owner or usr.admin:
for member in Users.query.filter_by(tid=tid).all():
member.tid = -1
with app.app_context():
db.session.add(member)
with app.app_context():
db.session.delete(team)
db.session.commit()
session.pop("tid")
return { "success": 1, "message": "Success!" }
else:
raise WebException("Not authorized.")
username = session["username"]
tid = session["tid"]
team = Teams.query.filter_by(tid=tid).first()
usr = Users.query.filter_by(username=username).first()
owner = team.owner
if usr.uid == owner or usr.admin:
with app.app_context():
for member in Users.query.filter_by(tid=tid).all():
member.tid = -1
db.session.add(member)
db.session.delete(team)
db.session.commit()
db.session.close()
session.pop("tid")
return { "success": 1, "message": "Success!" }
else:
raise WebException("Not authorized.")
@blueprint.route("/remove_member", methods=["POST"])
@api_wrapper
@login_required
def team_remove_member():
username = session["username"]
tid = session["tid"]
team = Teams.query.filter_by(tid=tid).first()
usr = Users.query.filter_by(username=username).first()
owner = team.owner
if usr.uid == owner or usr.admin:
params = utils.flat_multi(request.form)
user_to_remove = Users.query.filter_by(username=params.get("user"))
user_to_remove.tid = -1
with app.app_context():
db.session.add(user_to_remove)
db.session.commit()
return { "success": 1, "message": "Success!" }
else:
raise WebException("Not authorized.")
username = session["username"]
tid = session["tid"]
team = Teams.query.filter_by(tid=tid).first()
usr = Users.query.filter_by(username=username).first()
owner = team.owner
if usr.uid == owner or usr.admin:
params = utils.flat_multi(request.form)
user_to_remove = Users.query.filter_by(username=params.get("user"))
user_to_remove.tid = -1
with app.app_context():
db.session.add(user_to_remove)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
else:
raise WebException("Not authorized.")
@blueprint.route("/invite", methods=["POST"])
@api_wrapper
@ -110,6 +111,7 @@ def team_invite():
with app.app_context():
db.session.add(req)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
@ -135,6 +137,7 @@ def team_invite_rescind():
with app.app_context():
db.session.delete(invitation)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
@ -159,6 +162,7 @@ def team_invite_request():
with app.app_context():
db.session.add(req)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
@ -190,6 +194,7 @@ def team_accept_invite():
if invitation2 is not None:
db.session.delete(invitation2)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
@ -225,6 +230,7 @@ def team_accept_invite_request():
if invitation2 is not None:
db.session.delete(invitation2)
db.session.commit()
db.session.close()
return { "success": 1, "message": "Success!" }
@ -280,7 +286,7 @@ TeamSchema = Schema({
([__check_teamname], "This teamname is taken, did you forget your password?")
),
Required("school"): check(
([str, Length(min=4, max=60)], "Your school name should be between 4 and 60 characters long."),
([str, Length(min=4, max=40)], "Your school name should be between 4 and 40 characters long."),
([utils.__check_ascii], "Please only use ASCII characters in your school name."),
),
}, extra=True)

View file

View file

@ -8,7 +8,7 @@ from decorators import api_wrapper, WebException
from schemas import verify_to_schema, check
import datetime
import logger
import logger, logging
import os
import re
import requests
@ -94,7 +94,7 @@ def user_register():
db.session.commit()
utils.generate_identicon(email, user.uid)
logger.log(__name__, logger.INFO, "%s registered with %s" % (name.encode("utf-8"), email.encode("utf-8")))
logger.log(__name__, "%s registered with %s" % (name.encode("utf-8"), email.encode("utf-8")))
login_user(username, password)
return { "success": 1, "message": "Success!" }

View file

@ -10,6 +10,7 @@ import config
import json
import logging
import os
import traceback
from api.decorators import api_wrapper
@ -23,6 +24,8 @@ with app.app_context():
db.init_app(app)
db.create_all()
app.db = db
app.secret_key = config.SECRET_KEY
app.register_blueprint(api.admin.blueprint, url_prefix="/api/admin")
@ -39,27 +42,29 @@ def api_main():
def run(args):
with app.app_context():
app.debug = keyword_args["debug"]
keyword_args = dict(args._get_kwargs())
app.debug = keyword_args["debug"] if "debug" in keyword_args else False
app.run(host="0.0.0.0", port=8000)
def load_problems(args):
keyword_args = dict(args._get_kwargs())
force = keyword_args["force"] if "force" in keyword_args else False
if not os.path.exists(config.PROBLEM_DIR):
logging.critical("Problems directory doesn't exist.")
api.logger.log("api.problem.log", "Problems directory doesn't exist.")
return
for (dirpath, dirnames, filenames) in os.walk(config.PROBLEM_DIR):
if "problem.json" in filenames:
json_file = os.path.join(dirpath, "problem.json")
contents = open(json_file).read()
try:
data = json.loads(contents)
except ValueError as e:
logging.warning("Invalid JSON format in file {filename} ({exception})".format(filename=json_file, exception=e))
api.logger.log("api.problem.log", "Invalid JSON format in file {filename} ({exception})".format(filename=json_file, exception=e))
continue
if not isinstance(data, dict):
logging.warning("{filename} is not a dict.".format(filename=json_file))
api.logger.log("api.problem.log", "{filename} is not a dict.".format(filename=json_file))
continue
missing_keys = []
@ -67,24 +72,29 @@ def load_problems(args):
if key not in data:
missing_keys.append(key)
if len(missing_keys) > 0:
logging.warning("{filename} is missing the following keys: {keys}".format(filename=json_file, keys=", ".join(missing_keys)))
api.logger.log("api.problem.log", "{filename} is missing the following keys: {keys}".format(filename=json_file, keys=", ".join(missing_keys)))
continue
relative_path = os.path.relpath(dirpath, config.PROBLEM_DIR)
logging.info("Found problem '{}'".format(data["title"]))
data["description"] = open(os.path.join(dirpath, "description.md"), "r").read()
api.logger.log("api.problem.log", "Found problem '{}'".format(data["title"]))
with app.app_context():
try:
api.problem.insert_problem(data, force=force)
except Exception as e:
api.logger.log("api.problem.log", "Problem '{}' was not added to the database. Error: {}".format(data["title"], e))
api.logger.log("api.problem.log", "{}".format(traceback.format_exc()))
try:
api.problem.insert_problem(data)
except Exception as e:
logging.warning("Problem '{}' was not added to the database. Error: {}".format(data["title"], e))
api.logger.log("api.problem.log", "Finished.")
if __name__ == "__main__":
def main():
parser = ArgumentParser(description="EasyCTF Server Management")
subparser = parser.add_subparsers(help="Select one of the following actions.")
parser_problems = subparser.add_parser("problems", help="Manage problems.")
subparser_problems = parser_problems.add_subparsers(help="Select one of the following actions.")
parser_problems_load = subparser_problems.add_parser("load", help="Load all problems into database.")
parser_problems_load.add_argument("-f", "--force", action="store_true", help="Force overwrite problems.", default=False)
parser_problems_load.set_defaults(func=load_problems)
parser_run = subparser.add_parser("run", help="Run the server.")
@ -92,10 +102,10 @@ if __name__ == "__main__":
parser_run.set_defaults(func=run)
args = parser.parse_args()
keyword_args, _ = dict(args._get_kwargs()), args._get_args()
logging.getLogger().setLevel(logging.INFO)
if "func" in args:
args.func(args)
else:
parser.print_help()
parser.print_help()
main()

View file

@ -27,6 +27,7 @@
</head>
<body ng-controller="mainController">
<div id="site-message" style="margin: 0"></div>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">

View file

@ -75,10 +75,37 @@ app.config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
});
function api_call(method, url, data, callback_success, callback_fail) {
if (method.toLowerCase() == "post") {
data["csrf_token"] = $.cookie("csrf_token");
}
$.ajax({
"type": method,
"datatype": "json",
"data": data,
"url": url,
"cache": false
}).done(callback_success).fail(callback_fail);
}
function permanent_message(containerId, alertType, message, callback) {
$("#" + containerId).html("<div class=\"alert alert-" + alertType + "\" style=\"margin:0;\">" + message + "</div>");
$("#" + containerId).hide().slideDown("fast", "swing");
};
function display_message(containerId, alertType, message, callback) {
$("#" + containerId).html("<div class=\"alert alert-" + alertType + "\">" + message + "</div>");
$("#" + containerId).hide().slideDown("fast", "swing", function() {
window.setTimeout(function () {
$("#" + containerId).slideUp("fast", "swing", callback);
}, message.length * 55);
});
};
app.controller("mainController", ["$scope", "$http", function($scope, $http) {
$scope.config = { navbar: { } };
$scope.timestamp = Date.now();
$.get("/api/user/status", function(result) {
api_call("GET", "/api/user/status", {}, function(result) {
if (result["success"] == 1) {
delete result["success"];
$scope.config.navbar = result;
@ -87,14 +114,15 @@ app.controller("mainController", ["$scope", "$http", function($scope, $http) {
$scope.config.navbar.logged_in = false;
}
$scope.$apply();
}).fail(function() {
}, function() {
$scope.config.navbar.logged_in = false;
$scope.$apply();
permanent_message("site-message", "danger", "<div class='container'>The EasyCTF API server is currently down. We're working to fix this error right away. Follow <a href='http://twitter.com/easyctf' target='_blank'>@easyctf</a> for status updates.</div>");
});
}]);
app.controller("logoutController", function() {
$.get("/api/user/logout", function(result) {
api_call("GET", "/api/user/logout", {}, function(result) {
location.href = "/";
});
});
@ -103,7 +131,7 @@ app.controller("profileController", ["$controller", "$scope", "$http", "$routePa
var data = { };
if ("username" in $routeParams) data["username"] = $routeParams["username"];
$controller("mainController", { $scope: $scope });
$.get("/api/user/info", data, function(result) {
api_call("GET", "/api/user/info", data, function(result) {
if (result["success"] == 1) {
$scope.user = result["user"];
}
@ -129,7 +157,7 @@ app.controller("teamController", ["$controller", "$scope", "$http", "$routeParam
} else {
$controller("loginController", { $scope: $scope });
}
$.get("/api/team/info", data, function(result) {
api_call("GET", "/api/team/info", data, function(result) {
if (result["success"] == 1) {
$scope.team = result["team"];
}
@ -155,7 +183,7 @@ app.controller("resetController", ["$controller", "$scope", "$http", "$routePara
if ("token" in $routeParams) {
$scope.token = true;
token = $routeParams["token"];
$.get("/api/user/forgot/" + token, data, function(data) {
api_call("GET", "/api/user/forgot/" + token, data, function(data) {
$scope.body = data["message"];
$scope.success = data["success"]
$scope.$apply();
@ -181,9 +209,11 @@ app.controller("adminController", ["$controller", "$scope", "$http", function($c
app.controller("adminProblemsController", ["$controller", "$scope", "$http", function($controller, $scope, $http) {
$controller("adminController", { $scope: $scope });
$.get("/api/admin/problems/list", function(result) {
api_call("GET", "/api/admin/problems/list", {}, function(result) {
if (result["success"] == 1) {
$scope.problems = result["problems"];
} else {
$scope.problems = [];
}
$scope.$apply();
});
@ -191,7 +221,7 @@ app.controller("adminProblemsController", ["$controller", "$scope", "$http", fun
app.controller("settingsController", ["$controller", "$scope", "$http", function($controller, $scope, $http) {
$controller("loginController", { $scope: $scope });
$.get("/api/user/info", {}, function(result) {
api_call("GET", "/api/user/info", {}, function(result) {
if (result["success"] == 1) {
$scope.user = result["user"];
}
@ -199,27 +229,6 @@ app.controller("settingsController", ["$controller", "$scope", "$http", function
});
}]);
function display_message(containerId, alertType, message, callback) {
$("#" + containerId).html("<div class=\"alert alert-" + alertType + "\">" + message + "</div>");
$("#" + containerId).hide().slideDown("fast", "swing", function() {
window.setTimeout(function () {
$("#" + containerId).slideUp("fast", "swing", callback);
}, message.length * 55);
});
};
function api_call(method, url, data, callback_success, callback_fail) {
if (method.toLowerCase() == "post") {
data["csrf_token"] = $.cookie("csrf_token");
}
$.ajax({
"type": method,
"datatype": "json",
"data": data,
"url": url
}).done(callback_success).fail(callback_fail);
}
$.fn.serializeObject = function() {
var a, o;
o = {};

View file

@ -12,147 +12,38 @@
}
</style>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#problems" aria-controls="problems" role="tab" data-toggle="tab">Problems</a></li>
<li role="presentation"><a href="#filesystem" aria-controls="filesystem" role="tab" data-toggle="tab">Filesystem</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="problems">
<div class="row">
<div class="col-sm-12 col-md-3">
<div class="panel-group" id="problems" role="tablist" aria-multiselectable="true">
<div class="well" ng-show="problems.length==0">There are no problems to show!</div>
<!-- <div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading-new">
<h4 class="panel-title">
<a class="NO_HOVER_UNDERLINE_DAMMIT" style="display:block;" data-toggle="collapse" data-parent="#accordion" href="#collapse-new" aria-expanded="true" aria-controls="collapse-new">
<i class="fa fa-fw fa-plus"></i> Create New Problem
</a>
</h4>
</div>
<div id="collapse-new" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-new">
<div class="panel-body">
</div>
</div>
</div> -->
</div>
</div>
<div class="col-sm-12 col-md-9">
<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 ng-repeat="problem in problems"><a data-target="#problem_{{ problem['pid'] }}" data-toggle="tab">{{ problem["title"] }} ({{ problem["value"] }} points)</a></li>
</ul>
<div class="tab-content col-md-9">
<div class="tab-pane active" id="new">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading-new">
<h4 class="panel-title">
<i class="fa fa-fw fa-plus"></i> Create New Problem
</h4>
<div class="panel-heading">
<h4 class="panel-title">New Problem</h4>
</div>
<div id="collapse-new" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-new">
<div class="panel-body">
<form class="form-horizontal" onsubmit="create_problem(); return false;" id="create_problem">
<fieldset>
<div id="register_msg"></div>
</fieldset>
<fieldset class="container-fluid">
<p>Be sure you are familiar with guidelines to writing problems before you submit! Problem unlocking and other options will be available after you submit your problem.</p>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="name"><small>Title</small></label>
<div class="col-sm-12">
<input class="form-control" type="text" required name="name" placeholder="Title" autocomplete="off" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="category"><small>Category</small></label>
<div class="col-sm-12">
<select name="category" class="selectpicker" data-width="100%">
<option value="Algorithm">Algorithm</option>
<option value="Binary Exploitation">Binary Exploitation</option>
<option value="Cryptography">Cryptography</option>
<option value="Forensics">Forensics</option>
<option value="Linux">Linux</option>
<option value="Miscellaneous">Miscellaneous</option>
<option value="Programming">Programming</option>
<option value="Reconnaissance">Reconnaissance</option>
<option value="Reverse Engineering">Reverse Engineering</option>
<option value="Web Exploitation">Web Exploitation</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="value"><small>Value</small></label>
<div class="col-sm-12">
<input class="form-control" type="number" required name="value" placeholder="Value" autocomplete="off" value="10" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="description"><small>Description</small></label>
<div class="col-sm-12">
<div id="description"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="hint"><small>Hint</small></label>
<div class="col-sm-12">
<input class="form-control" type="text" required name="hint" placeholder="Hint" autocomplete="off" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<label class="col-sm-12" for="grader"><small>Grader</small></label>
<div class="col-sm-12">
<div id="new_grader" class="ace_editor">def grade(key, tid):
""" Grade this problem. """
flag = "easyctf{a_flag}"
case_sensitive = True
if (key.find(flag) >= 0) if case_sensitive \
else (key.lower().find(flag.lower()) >= 0):
return { "success": 1, "message": "Correct!" }
return { "success": 0, "message": "Sorry, try again." }</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 form-group">
<center>
<input type="submit" class="btn btn-primary btn-lg" value="Create" />
</center>
</div>
</div>
</fieldset>
</form>
</div>
<div class="panel-body">
</div>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="filesystem">
<div class="row">
<div class="col-sm-12 col-md-3">
<div class="">
<div class="tab-pane" ng-repeat="problem in problems" id="problem_{{ problem['pid'] }}">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">{{ problem["title"] }}</h4>
</div>
<div class="panel-body">
</div>
</div>
</div>
<div class="col-sm-12 col-md-9">
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$("ul[role=tablist]").tab();
$("a[role=tab]").click(function(e) {
e.preventDefault();
});
$(".selectpicker").selectpicker();
/*$(".selectpicker").selectpicker();
var config = {
toolbar: [
{ name: "basicstyles", items: [ "Bold", "Italic", "Underline" ] },
@ -175,6 +66,6 @@
}).load();
var new_grader = ace.edit("new_grader");
new_grader.setTheme("ace/theme/tomorrow");
new_grader.getSession().setMode("ace/mode/python");
new_grader.getSession().setMode("ace/mode/python");*/
});
</script>

View file

@ -33,7 +33,7 @@
<i class="fa fa-fw fa-flag"></i>
I'm in the team!
</div>
<div class="label label-warning">
<div class="label label-warning" ng-show="team['observer']==true">
<i class="fa fa-fw fa-globe"></i>
OBSERVER
</div>
@ -43,7 +43,7 @@
<h1><span class="padded">{{ team['teamname'] }}</span></h1>
<h4><i class="fa fa-fw fa-university"></i> <span class="padded">{{ team['school'] || 'Unknown Affiliation' }}</span></h4>
<div class="row">
<div class="label label-warning">
<div class="label label-warning" ng-show="team['observer']==true">
<i class="fa fa-fw fa-globe"></i>
OBSERVER
</div>