Design improvements (#276)

* Fixes #269
* Adding tooltips to some admin content
* Switching from spaces to tabs in HTML files
* A variety of aesthetic improvements
selenium-screenshot-testing
Kevin Chung 2017-06-10 00:11:27 -04:00 committed by GitHub
parent 285b320ea5
commit 4fedc8f69e
37 changed files with 2843 additions and 2795 deletions

View File

@ -494,3 +494,7 @@ table{
margin: 0;
width: 100%;
}
.gray-text{
color: lightgray;
}

View File

@ -0,0 +1,3 @@
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});

View File

@ -1,11 +1,15 @@
<div class="col-md-6 col-md-offset-3">
<form method="POST" action="{{ script_root }}/admin/chal/new" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Name</label>
<label for="name">Name
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="The name of your challenge"></i>
</label>
<input type="text" class="form-control" name="name" placeholder="Enter challenge name">
</div>
<div class="form-group">
<label for="category">Category</label>
<label for="category">Category
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="The category of your challenge"></i>
</label>
<input type="text" class="form-control" name="category" placeholder="Enter challenge category">
</div>
@ -16,22 +20,28 @@
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="new-desc-write">
<div class="form-group">
<label for="message-text" class="control-label">Message:</label>
<label for="message-text" class="control-label">Message:
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="Use this to give a brief introduction to your challenge. The description supports HTML and Markdown."></i>
</label>
<textarea id="new-desc-editor" class="form-control" name="desc" rows="10"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="new-desc-preview" style="height:234px">
<div role="tabpanel" class="tab-pane content" id="new-desc-preview" style="height:234px; overflow-y: scroll;">
</div>
</div>
<div class="form-group">
<label for="value">Value</label>
<label for="value">Value
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="This is how many points are rewarded for solving this challenge."></i>
</label>
<input type="number" class="form-control" name="value" placeholder="Enter value" required>
</div>
<div class="row">
<div class="form-group">
<div class="col-md-8">
<label for="key">Key</label>
<label for="key">Key
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="This is the flag/solution for the challenge."></i>
</label>
<input type="text" class="form-control" name="key" placeholder="Enter key">
</div>
<div class="form-vertical">
@ -74,7 +84,9 @@
</label>
</div>
<div id="solve-attempts-input" style="display: none;">
<label for="max_attempts">Maximum Attempts</label>
<label for="max_attempts">Maximum Attempts
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="How many attempts should a user have for this challenge? For unlimited attempts, use the value 0"></i>
</label>
<input class="form-control" id='max_attempts' name='max_attempts' type='number' placeholder="0">
</div>
</div>
@ -82,7 +94,9 @@
<div class="row">
<div class="form-group">
<div class="col-md-9">
<label>Upload challenge files</label>
<label>Upload Challenge Files
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="Challenges files are provided to users for download alongside your challenge description"></i>
</label>
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
<input type="file" name="files[]" multiple="multiple">
</div>

View File

@ -17,3 +17,7 @@ $("#solve-attempts-checkbox").change(function() {
$('#max_attempts').val('');
}
});
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});

View File

@ -10,11 +10,15 @@
<input name='nonce' type='hidden' value="{{ nonce }}">
<div class="form-group">
<label for="name">Name</label>
<label for="name">Name
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="The name of your challenge"></i>
</label>
<input type="text" class="form-control chal-name" name="name" placeholder="Enter challenge name">
</div>
<div class="form-group">
<label for="category">Category</label>
<label for="category">Category
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="The category of your challenge"></i>
</label>
<input type="text" class="form-control chal-category" name="category" placeholder="Enter challenge category">
</div>
@ -25,16 +29,20 @@
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="desc-write">
<div class="form-group">
<label for="message-text" class="control-label">Message:</label>
<label for="message-text" class="control-label">Message:
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="Use this to give a brief introduction to your challenge. The description supports HTML and Markdown."></i>
</label>
<textarea id="desc-editor" class="form-control chal-desc" name="desc" rows="10"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="desc-preview" style="height:214px">
<div role="tabpanel" class="tab-pane content" id="desc-preview" style="height:214px; overflow-y: scroll;">
</div>
</div>
<div class="form-group">
<label for="value">Value</label>
<label for="value">Value
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="This is how many points teams will receive once they solve this challenge."></i>
</label>
<input type="number" class="form-control chal-value" name="value" placeholder="Enter value" required>
</div>

View File

@ -388,3 +388,6 @@ function openchal(id){
loadfiles(id);
}
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});

View File

@ -18,6 +18,10 @@ a {
outline: 0;
}
img {
max-width: 100%;
}
.body-container {
min-height: 100%;
position: relative;

View File

@ -2,82 +2,83 @@
<html>
<head>
<title>Admin Panel</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/style.css">
<link href='{{ request.script_root }}/static/admin/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/admin/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/style.css">
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/moment-timezone-with-data.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
{% block stylesheets %} {% endblock %}
<title>Admin Panel</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/style.css">
<link href='{{ request.script_root }}/static/admin/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/admin/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/style.css">
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/moment-timezone-with-data.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
{% block stylesheets %} {% endblock %}
</head>
<body>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">CTFd</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right">
<li><a href="{{ request.script_root }}/admin/graphs">Graphs</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Pages <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ request.script_root }}/admin/pages">All Pages</a></li>
<li><a href="{{ request.script_root }}/admin/pages?mode=create">New Page</a></li>
</ul>
</li>
<li><a href="{{ request.script_root }}/admin/teams">Teams</a></li>
<li><a href="{{ request.script_root }}/admin/scoreboard">Scoreboard</a></li>
{% if can_create_container() %}
<li><a href="{{ request.script_root }}/admin/containers">Containers</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/admin/chals">Challenges</a></li>
<li><a href="{{ request.script_root }}/admin/statistics">Statistics</a></li>
<li><a href="{{ request.script_root }}/admin/config">Config</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Plugins <span class="caret"></span></a>
<ul class="dropdown-menu">
{% for plugin in get_configurable_plugins() %}
<li><a href="{{ request.script_root }}/admin/plugins/{{ plugin }}">{{ plugin }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">CTFd</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right">
<li><a href="{{ request.script_root }}/admin/graphs">Graphs</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Pages <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ request.script_root }}/admin/pages">All Pages</a></li>
<li><a href="{{ request.script_root }}/admin/pages?mode=create">New Page</a></li>
</ul>
</li>
<li><a href="{{ request.script_root }}/admin/teams">Teams</a></li>
<li><a href="{{ request.script_root }}/admin/scoreboard">Scoreboard</a></li>
{% if can_create_container() %}
<li><a href="{{ request.script_root }}/admin/containers">Containers</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/admin/chals">Challenges</a></li>
<li><a href="{{ request.script_root }}/admin/statistics">Statistics</a></li>
<li><a href="{{ request.script_root }}/admin/config">Config</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Plugins <span class="caret"></span></a>
<ul class="dropdown-menu">
{% for plugin in get_configurable_plugins() %}
<li><a href="{{ request.script_root }}/admin/plugins/{{ plugin }}">{{ plugin }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
{% block content %}
{% endblock %}
<div class="navbar navbar-bottom footer">
<p class="text-muted text-center"><a style="text-decoration:none;" href="https://ctfd.io"><sub>Powered by CTFd</sub></p>
</div>
</div>
</div>
<script src="{{ request.script_root }}/static/admin/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/bootstrap.min.js"></script>
{% block scripts %} {% endblock %}
<div class="container">
{% block content %}
{% endblock %}
<div class="navbar navbar-bottom footer">
<p class="text-muted text-center"><a style="text-decoration:none;" href="https://ctfd.io"><sub>Powered by CTFd</sub></p>
</div>
</div>
</div>
<script src="{{ request.script_root }}/static/admin/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/bootstrap.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/main.js"></script>
{% block scripts %} {% endblock %}
</body>
</html>

View File

@ -11,46 +11,46 @@
{% endblock %}
{% block content %}
<div id="email-user" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
<div id="email-user" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
<input type="hidden" value="{{ nonce }}" id="nonce">
<input type="hidden" value="{{ nonce }}" id="nonce">
<div id="create-challenge" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3>New Challenge</h3>
</div>
</div>
</div>
</div>
<div id="create-challenge" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3>New Challenge</h3>
</div>
</div>
</div>
</div>
<div id="update-modals-entry-div">
</div>
<div id="update-modals-entry-div">
</div>
<div style="text-align:center">
<br>
<h1 class="text-center">Challenges</h1>
<a class="btn btn-theme btn-outlined create-challenge" href="{{ request.script_root }}/admin/chal/new" role="button">New Challenge</a>
<div>
<table id='challenges'>
</table>
</div>
</div>
<div style="text-align:center">
<br>
<h1 class="text-center">Challenges</h1>
<a class="btn btn-theme btn-outlined create-challenge" href="{{ request.script_root }}/admin/chal/new" role="button">New Challenge</a>
<div>
<table id='challenges'>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/chalboard.js"></script>
<script src="{{ request.script_root }}/static/admin/js/multi-modal.js"></script>
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/chalboard.js"></script>
<script src="{{ request.script_root }}/static/admin/js/multi-modal.js"></script>
{% endblock %}

View File

@ -12,61 +12,61 @@
{% block content %}
<div id="create-challenge" class="container main-container">
<h1 class="text-center">Create Challenge</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="create-chals-select-div">
<label for="create-chals-select" class="control-label">Choose Challenge Type</label>
<select class="form-control" id="create-chals-select">
</select>
</div>
</div>
</div>
<br>
<div class="row">
<div id="create-chal-entry-div">
</div>
</div>
<h1 class="text-center">Create Challenge</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="create-chals-select-div">
<label for="create-chals-select" class="control-label">Choose Challenge Type</label>
<select class="form-control" id="create-chals-select">
</select>
</div>
</div>
</div>
<br>
<div class="row">
<div id="create-chal-entry-div">
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/codemirror.min.js"></script>
<script>
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/codemirror.min.js"></script>
<script>
function load_chal_template(chal_type_name){
$.get(script_root + '/static/admin/js/templates/challenges/'+ chal_type_name +'/' + chal_type_name + '-challenge-create.hbs', function(template_data){
var template = Handlebars.compile(template_data);
$("#create-chal-entry-div").html(template({'nonce':nonce, 'script_root':script_root}));
$.getScript(script_root + '/static/admin/js/templates/challenges/'+chal_type_name+'/'+chal_type_name+'-challenge-create.js', function(){
console.log('loaded');
});
});
}
function load_chal_template(chal_type_name){
$.get(script_root + '/static/admin/js/templates/challenges/'+ chal_type_name +'/' + chal_type_name + '-challenge-create.hbs', function(template_data){
var template = Handlebars.compile(template_data);
$("#create-chal-entry-div").html(template({'nonce':nonce, 'script_root':script_root}));
$.getScript(script_root + '/static/admin/js/templates/challenges/'+chal_type_name+'/'+chal_type_name+'-challenge-create.js', function(){
console.log('loaded');
});
});
}
nonce = "{{ nonce }}";
$.get(script_root + '/admin/chal_types', function(data){
console.log(data);
$("#create-chals-select").empty();
var chal_type_amt = Object.keys(data).length;
if (chal_type_amt > 1){
var option = "<option> -- </option>";
$("#create-chals-select").append(option);
for (var key in data){
var option = "<option value='{0}'>{1}</option>".format(key, data[key]);
$("#create-chals-select").append(option);
}
} else if (chal_type_amt == 1) {
var key = Object.keys(data)[0];
$("#create-chals-select").parent().parent().parent().empty();
load_chal_template(data[key]);
}
});
$('#create-chals-select').change(function(){
var chal_type_name = $(this).find("option:selected").text();
load_chal_template(chal_type_name);
});
</script>
nonce = "{{ nonce }}";
$.get(script_root + '/admin/chal_types', function(data){
console.log(data);
$("#create-chals-select").empty();
var chal_type_amt = Object.keys(data).length;
if (chal_type_amt > 1){
var option = "<option> -- </option>";
$("#create-chals-select").append(option);
for (var key in data){
var option = "<option value='{0}'>{1}</option>".format(key, data[key]);
$("#create-chals-select").append(option);
}
} else if (chal_type_amt == 1) {
var key = Object.keys(data)[0];
$("#create-chals-select").parent().parent().parent().empty();
load_chal_template(data[key]);
}
});
$('#create-chals-select').change(function(){
var chal_type_name = $(this).find("option:selected").text();
load_chal_template(chal_type_name);
});
</script>
{% endblock %}

File diff suppressed because it is too large Load Diff

View File

@ -2,109 +2,109 @@
{% block content %}
<div class="modal fade" id="create-container-modal" tabindex="-1" role="dialog" aria-labelledby="container-modal-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="container-modal-label">Create Container</h4>
</div>
<form method="POST" action="{{ request.script_root }}/admin/containers/new" enctype="multipart/form-data">
<div class="modal-body">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" name="name" placeholder="Enter container name">
</div>
<div class="form-group">
<label for="buildfile-editor" class="control-label">Build File</label>
<textarea id="buildfile-editor" class="form-control" name="buildfile" rows="10" placeholder="Enter container build file"></textarea>
</div>
<div class="form-group">
<label for="container-files">Associated Files
<i class="fa fa-question-circle" title="These files are uploaded alongside your buildfile"></i>
</label>
<input type="file" name="files[]" id="container-files" multiple>
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
</div>
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="container-modal-label">Create Container</h4>
</div>
<form method="POST" action="{{ request.script_root }}/admin/containers/new" enctype="multipart/form-data">
<div class="modal-body">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" name="name" placeholder="Enter container name">
</div>
<div class="form-group">
<label for="buildfile-editor" class="control-label">Build File</label>
<textarea id="buildfile-editor" class="form-control" name="buildfile" rows="10" placeholder="Enter container build file"></textarea>
</div>
<div class="form-group">
<label for="container-files">Associated Files
<i class="fa fa-question-circle gray-text" data-toggle="tooltip" data-placement="right" title="These files are uploaded alongside your buildfile"></i>
</label>
<input type="file" name="files[]" id="container-files" multiple>
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
</div>
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
</div>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center"><span id="confirm-container-title"></span> Container</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to <span id="confirm-container-method"></span> <strong id="confirm-container-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="confirm-container" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center"><span id="confirm-container-title"></span> Container</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to <span id="confirm-container-method"></span> <strong id="confirm-container-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="confirm-container" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<br>
<div style="text-align:center">
<h1>Containers</h1>
<button class="btn btn-theme btn-outlined create-challenge" data-toggle="modal" data-target="#create-container-modal">
New Container
</button>
</div>
<br>
<br>
<div style="text-align:center">
<h1>Containers</h1>
<button class="btn btn-theme btn-outlined create-challenge" data-toggle="modal" data-target="#create-container-modal">
New Container
</button>
</div>
<br>
{% if containers %}
<table id="teamsboard">
<thead>
<tr>
<td class="text-center"><strong>Status</strong>
</td>
<td class="text-center"><strong>Name</strong>
</td>
<td class="text-center"><strong>Ports</strong>
</td>
<td class="text-center"><strong>Settings</strong>
</td>
</tr>
</thead>
<tbody>
{% for c in containers %}
<tr>
<td class="text-center">{{ c.status }}</td>
<td class="text-center container_item" id="{{ c.id }}">{{ c.name }}</td>
<td class="text-center">{{ c.ports }}</td>
<td class="text-center">
<span>
{% if c.status != 'running' %}
<i class="fa fa-play"></i>
{% else %}
<i class="fa fa-stop"></i>
{% endif %}
<i class="fa fa-times"></i>
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="teamsboard">
<thead>
<tr>
<td class="text-center"><strong>Status</strong>
</td>
<td class="text-center"><strong>Name</strong>
</td>
<td class="text-center"><strong>Ports</strong>
</td>
<td class="text-center"><strong>Settings</strong>
</td>
</tr>
</thead>
<tbody>
{% for c in containers %}
<tr>
<td class="text-center">{{ c.status }}</td>
<td class="text-center container_item" id="{{ c.id }}">{{ c.name }}</td>
<td class="text-center">{{ c.ports }}</td>
<td class="text-center">
<span>
{% if c.status != 'running' %}
<i class="fa fa-play"></i>
{% else %}
<i class="fa fa-stop"></i>
{% endif %}
<i class="fa fa-times"></i>
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endblock %}
@ -113,46 +113,50 @@
<script>
function load_confirm_modal(title, url, container_name){
var modal = $('#confirm')
modal.find('#confirm-container-name').text(container_name)
modal.find('#confirm-container-title').text(title)
modal.find('#confirm-container-method').text(title.toLowerCase())
$('#confirm form').attr('action', url);
$('#confirm').modal('show');
var modal = $('#confirm')
modal.find('#confirm-container-name').text(container_name)
modal.find('#confirm-container-title').text(title)
modal.find('#confirm-container-method').text(title.toLowerCase())
$('#confirm form').attr('action', url);
$('#confirm').modal('show');
}
$('#confirm-container').click(function(e){
e.preventDefault();
var id = $('#confirm input[name="id"]').val()
var user_data = $('#confirm form').serializeArray()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
e.preventDefault();
var id = $('#confirm input[name="id"]').val()
var user_data = $('#confirm form').serializeArray()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
});
$('.fa-times').click(function(){
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Delete', '/admin/containers/'+container+'/delete', container_name)
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Delete', '/admin/containers/'+container+'/delete', container_name)
});
$('.fa-play').click(function(){
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Start', '/admin/containers/'+container+'/start', container_name)
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Start', '/admin/containers/'+container+'/start', container_name)
});
$('.fa-stop').click(function(){
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Stop', '/admin/containers/'+container+'/stop', container_name)
var elem = $(this).parent().parent().parent().find('.container_item');
var container = elem.attr('id');
var container_name = elem.text().trim();
load_confirm_modal('Stop', '/admin/containers/'+container+'/stop', container_name)
});
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
</script>

View File

@ -10,102 +10,102 @@
{% block content %}
<div class="row">
<br>
<h1>Correct Key Submissions</h1>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Delete Key</h3>
</div>
<div class="modal-body">
<form method="POST" action="">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete successful key submission for team: <strong id="confirm-team-name"></strong> in challenge: <strong id="confirm-chal-name"></strong>?</p>
<a onclick="$('#confirm').modal('hide')" class="btn btn-primary">No</a>
<button class="btn btn-danger" id="delete-solve" type="button">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<table id="teamsboard" class=" table table-striped">
<thead>
<tr>
<td class="text-center"><b>Team</b>
</td>
<td class="text-center"><b>Challenge</b>
</td>
<td class="text-center"><b>Date</b>
</td>
<td class="text-center"><b>Key Submitted</b>
</td>
<td class="text-center"><b>Delete</b>
</td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr>
<td class="text-center team" id="{{ solve.teamid }}"><a href="{{ request.script_root }}/admin/team/{{ solve.teamid }}">{{ solve.team_name }}</a>
<td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal_name }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center flag" id="{{ solve.id }}">{{ solve.flag }}</td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/admin/correct_keys/{{ page }}">{{ page }}</a>
{% else %}
<b>{{ page }}</b>
{% endif %}
{% endfor %}
{% if curr_page != pages %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href="{{ request.script_root }}">
</div>
{% endif %}
<br>
<h1>Correct Key Submissions</h1>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3>Delete Key</h3>
</div>
<div class="modal-body">
<form method="POST" action="">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete successful key submission for team: <strong id="confirm-team-name"></strong> in challenge: <strong id="confirm-chal-name"></strong>?</p>
<a onclick="$('#confirm').modal('hide')" class="btn btn-primary">No</a>
<button class="btn btn-danger" id="delete-solve" type="button">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<table id="teamsboard" class=" table table-striped">
<thead>
<tr>
<td class="text-center"><b>Team</b>
</td>
<td class="text-center"><b>Challenge</b>
</td>
<td class="text-center"><b>Date</b>
</td>
<td class="text-center"><b>Key Submitted</b>
</td>
<td class="text-center"><b>Delete</b>
</td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr>
<td class="text-center team" id="{{ solve.teamid }}"><a href="{{ request.script_root }}/admin/team/{{ solve.teamid }}">{{ solve.team_name }}</a>
<td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal_name }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center flag" id="{{ solve.id }}">{{ solve.flag }}</td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/admin/correct_keys/{{ page }}">{{ page }}</a>
{% else %}
<b>{{ page }}</b>
{% endif %}
{% endfor %}
{% if curr_page != pages %}<a href="{{ request.script_root }}/admin/correct_keys/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href="{{ request.script_root }}">
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script>
$('#delete-solve').click(function(e){
e.preventDefault();
var solve = $('#confirm input[name="solve"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
});
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script>
$('#delete-solve').click(function(e){
e.preventDefault();
var solve = $('#confirm input[name="solve"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
});
function load_confirm_modal(key_id, team_name, chal_name){
var modal = $('#confirm')
modal.find('#confirm-team-name').text(team_name)
modal.find('#confirm-chal-name').text(chal_name)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/solves/'+key_id+'/delete');
$('#confirm').modal('show');
}
function load_confirm_modal(key_id, team_name, chal_name){
var modal = $('#confirm')
modal.find('#confirm-team-name').text(team_name)
modal.find('#confirm-chal-name').text(chal_name)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/solves/'+key_id+'/delete');
$('#confirm').modal('show');
}
$('.fa-times').click(function(){
var elem = $(this).parent().parent();
var chal = elem.find('.chal').attr('id');
var chal_name = elem.find('.chal').text().trim();
var team = elem.find('.team').attr('id');
var team_name = elem.find('.team').text().trim();
var key_id = elem.find('.flag').attr('id');
load_confirm_modal(key_id, team_name, chal_name)
});
</script>
$('.fa-times').click(function(){
var elem = $(this).parent().parent();
var chal = elem.find('.chal').attr('id');
var chal_name = elem.find('.chal').text().trim();
var team = elem.find('.team').attr('id');
var team_name = elem.find('.team').text().trim();
var key_id = elem.find('.flag').attr('id');
load_confirm_modal(key_id, team_name, chal_name)
});
</script>
{% endblock %}

View File

@ -1,130 +1,130 @@
{% extends "admin/base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/vendor/codemirror.min.css">
<style>
.row-fluid { margin: 25px; padding-bottom: 25px; }
.media-item-wrapper { height: 120px; margin: 5px;
float: left; border: 1px solid #eee; text-align: center; text-overflow: ellipsis; overflow: hidden;}
.media-item-wrapper > a > i {line-height: 90px;}
.media-item-title{ font-size: 10px; }
#media-item{display: none;}
</style>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/vendor/codemirror.min.css">
<style>
.row-fluid { margin: 25px; padding-bottom: 25px; }
.media-item-wrapper { height: 120px; margin: 5px;
float: left; border: 1px solid #eee; text-align: center; text-overflow: ellipsis; overflow: hidden;}
.media-item-wrapper > a > i {line-height: 90px;}
.media-item-title{ font-size: 10px; }
#media-item{display: none;}
</style>
{% endblock %}
{% block content %}
<div id="media-modal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3 class="text-center">Media Library</h3>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3 class="text-center">Media Library</h3>
<div class="row">
<div class="col-md-8 col-md-offset-1" id="media-library-list">
</div>
<div class="col-md-2">
<h4 class="text-center">Media Details</h4>
<div id="media-item">
<div class="row text-center" id="media-icon">
</div>
<br>
<div class="row text-center" id="media-filename">
</div>
<br>
<div class="row form-group">
Link: <input class="form-control" type="text" id="media-link">
</div>
<div class="row">
<div class="col-md-8 col-md-offset-1" id="media-library-list">
</div>
<div class="col-md-2">
<h4 class="text-center">Media Details</h4>
<div id="media-item">
<div class="row text-center" id="media-icon">
</div>
<br>
<div class="row text-center" id="media-filename">
</div>
<br>
<div class="row form-group">
Link: <input class="form-control" type="text" id="media-link">
</div>
<div class="row form-group text-center">
<button class="btn btn-success" id="media-insert">Insert</button>
</div>
</div>
</div>
</div>
<div class="row form-group text-center">
<button class="btn btn-success" id="media-insert">Insert</button>
</div>
</div>
</div>
</div>
<hr>
<hr>
<form id="media-library-upload">
<div class="form-group">
<label for="media-files">Upload Files
</label>
<input type="file" name="files[]" id="media-files" multiple>
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
</div>
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
</form>
<div class="pull-right">
<button type="submit" class="btn btn-primary" onclick="uploadfiles();">Upload</button>
</div>
<form id="media-library-upload">
<div class="form-group">
<label for="media-files">Upload Files
</label>
<input type="file" name="files[]" id="media-files" multiple>
<sub class="help-block">Attach multiple files using Control+Click or Cmd+Click.</sub>
</div>
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
</form>
<div class="pull-right">
<button type="submit" class="btn btn-primary" onclick="uploadfiles();">Upload</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
</div>
</div>
{% endfor %}
</div>
<div class="row">
{% for error in errors %}
<div class="large-8 large-centered columns">
<div data-alert class="alert-box alert radius centered text-center">
<span>{{ error }}</span>
<a href="#" class="close">×</a>
</div>
</div>
{% endfor %}
</div>
<form id="page-edit" method="POST">
<div class="row-fluid">
<div class="col-md-12">
<h3>Route: </h3>
<p class="help-block">This is the URL route that your page will be at (e.g. /page)</p>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input class="form-control radius" id="route" type="text" name="route" value="{% if page is defined %}{{ page.route }}{% endif %}" placeholder="Route">
</div>
</div>
<br>
<div class="row-fluid">
<div class="col-md-12">
<form id="page-edit" method="POST">
<div class="row-fluid">
<div class="col-md-12">
<h3>Route: </h3>
<p class="help-block">This is the URL route that your page will be at (e.g. /page)</p>
<input name='nonce' type='hidden' value="{{ nonce }}">
<input class="form-control radius" id="route" type="text" name="route" value="{% if page is defined %}{{ page.route }}{% endif %}" placeholder="Route">
</div>
</div>
<br>
<div class="row-fluid">
<div class="col-md-12">
<h3>Content: </h3>
<p class="help-block">This is the HTML content of your page</p>
<h3>Content: </h3>
<p class="help-block">This is the HTML content of your page</p>
<ul class="nav nav-tabs" role="tablist" id="content-edit">
<li role="presentation" class="active"><a href="#content-write" aria-controls="home" role="tab" data-toggle="tab">Write</a></li>
<li role="presentation"><a href="#content-preview" aria-controls="home" role="tab" data-toggle="tab">Preview</a></li>
</ul>
<ul class="nav nav-tabs" role="tablist" id="content-edit">
<li role="presentation" class="active"><a href="#content-write" aria-controls="home" role="tab" data-toggle="tab">Write</a></li>
<li role="presentation"><a href="#content-preview" aria-controls="home" role="tab" data-toggle="tab">Preview</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="content-write" style="height:400px">
<div class="form-group">
<br>
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" id="media-button"><i class="fa fa-camera-retro" aria-hidden="true"></i> Media Library</button>
</div>
</div>
<br>
<br>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="content-write" style="height:400px">
<div class="form-group">
<br>
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default" id="media-button"><i class="fa fa-camera-retro" aria-hidden="true"></i> Media Library</button>
</div>
</div>
<br>
<br>
<textarea id="admin-pages-editor" name="html">{% if page is defined %}{{ page.html }}{% endif %}</textarea><br>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="content-preview" style="height:400px">
</div>
</div>
</div>
<button class="btn btn-theme btn-outlined create-challenge pull-right">
{% if page is defined %}
Update
{% else %}
Create
{% endif %}
</button>
</div>
</form>
<textarea id="admin-pages-editor" name="html">{% if page is defined %}{{ page.html }}{% endif %}</textarea><br>
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="content-preview" style="height:400px">
</div>
</div>
</div>
<button class="btn btn-theme btn-outlined create-challenge pull-right">
{% if page is defined %}
Update
{% else %}
Create
{% endif %}
</button>
</div>
</form>
</div>
{% endblock %}
@ -132,158 +132,158 @@
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/codemirror.min.js"></script>
<script>
function uploadfiles(){
var form = $('#media-library-upload')[0];
var formData = new FormData(form);
console.log(formData);
$.ajax({
url: script_root + '/admin/media',
data: formData,
type: 'POST',
cache: false,
contentType: false,
processData: false,
success: function(data){
refreshfiles(data);
form.reset();
}
});
}
function uploadfiles(){
var form = $('#media-library-upload')[0];
var formData = new FormData(form);
console.log(formData);
$.ajax({
url: script_root + '/admin/media',
data: formData,
type: 'POST',
cache: false,
contentType: false,
processData: false,
success: function(data){
refreshfiles(data);
form.reset();
}
});
}
function refreshfiles(data){
var data = data.results;
var list = $('#media-library-list');
var mapping = {
// Image Files
'png': 'fa-file-image-o',
'jpg': 'fa-file-image-o',
'jpeg': 'fa-file-image-o',
'gif': 'fa-file-image-o',
'bmp': 'fa-file-image-o',
'svg': 'fa-file-image-o',
function refreshfiles(data){
var data = data.results;
var list = $('#media-library-list');
var mapping = {
// Image Files
'png': 'fa-file-image-o',
'jpg': 'fa-file-image-o',
'jpeg': 'fa-file-image-o',
'gif': 'fa-file-image-o',
'bmp': 'fa-file-image-o',
'svg': 'fa-file-image-o',
// Text Files
'txt': 'fa-file-text-o',
// Text Files
'txt': 'fa-file-text-o',
// Video Files
'mov': 'fa-file-video-o',
'mp4': 'fa-file-video-o',
'wmv': 'fa-file-video-o',
'flv': 'fa-file-video-o',
'mkv': 'fa-file-video-o',
'avi': 'fa-file-video-o',
// Video Files
'mov': 'fa-file-video-o',
'mp4': 'fa-file-video-o',
'wmv': 'fa-file-video-o',
'flv': 'fa-file-video-o',
'mkv': 'fa-file-video-o',
'avi': 'fa-file-video-o',
// PDF Files
'pdf': 'fa-file-pdf-o',
// PDF Files
'pdf': 'fa-file-pdf-o',
// Audio Files
'mp3': 'fa-file-sound-o',
'wav': 'fa-file-sound-o',
'aac': 'fa-file-sound-o',
// Audio Files
'mp3': 'fa-file-sound-o',
'wav': 'fa-file-sound-o',
'aac': 'fa-file-sound-o',
// Archive Files
'zip': 'fa-file-archive-o',
'gz': 'fa-file-archive-o',
'tar': 'fa-file-archive-o',
'7z': 'fa-file-archive-o',
'rar': 'fa-file-archive-o',
// Archive Files
'zip': 'fa-file-archive-o',
'gz': 'fa-file-archive-o',
'tar': 'fa-file-archive-o',
'7z': 'fa-file-archive-o',
'rar': 'fa-file-archive-o',
// Code Files
'py': 'fa-file-code-o',
'c': 'fa-file-code-o',
'cpp': 'fa-file-code-o',
'html': 'fa-file-code-o',
'js': 'fa-file-code-o',
'rb': 'fa-file-code-o',
'go': 'fa-file-code-o',
}
for (var i = 0; i < data.length; i++) {
var f = data[i];
var ext = f.location.split('.').pop();
var fname = f.location.split('/')[1];
// Code Files
'py': 'fa-file-code-o',
'c': 'fa-file-code-o',
'cpp': 'fa-file-code-o',
'html': 'fa-file-code-o',
'js': 'fa-file-code-o',
'rb': 'fa-file-code-o',
'go': 'fa-file-code-o',
}
for (var i = 0; i < data.length; i++) {
var f = data[i];
var ext = f.location.split('.').pop();
var fname = f.location.split('/')[1];
var wrapper = $('<div>').attr('class', 'media-item-wrapper col-md-2')
var wrapper = $('<div>').attr('class', 'media-item-wrapper col-md-2')
var link = $('<a>');
link.attr('href', '#');
var link = $('<a>');
link.attr('href', '##');
if (mapping[ext] == undefined)
link.append('<i class="fa fa-file-o fa-4x" aria-hidden="true"></i>'.format(mapping[ext]));
else
link.append('<i class="fa {0} fa-4x" aria-hidden="true"></i>'.format(mapping[ext]));
if (mapping[ext] == undefined)
link.append('<i class="fa fa-file-o fa-4x" aria-hidden="true"></i>'.format(mapping[ext]));
else
link.append('<i class="fa {0} fa-4x" aria-hidden="true"></i>'.format(mapping[ext]));
link.click(function(e){
var media_div = $(this).parent();
var icon = $(this).find('.fa')[0];
var f_loc = media_div.attr('data-location');
var fname = media_div.attr('data-filename');
$('#media-link').val(f_loc);
$('#media-filename').text(fname);
link.click(function(e){
var media_div = $(this).parent();
var icon = $(this).find('.fa')[0];
var f_loc = media_div.attr('data-location');
var fname = media_div.attr('data-filename');
$('#media-link').val(f_loc);
$('#media-filename').text(fname);
$('#media-icon').empty()
if ($(icon).hasClass('fa-file-image-o')){
$('#media-icon').append($('<img>').attr('src', f_loc).attr('width', '100%'));
} else {
// icon is empty so we need to pull outerHTML
$('#media-icon').append(icon.outerHTML);
}
$('#media-item').show();
});
wrapper.append(link);
wrapper.attr('data-location', script_root + '/files/' + f.location);
wrapper.attr('data-id', f.id);
wrapper.attr('data-filename', fname);
list.append(wrapper);
$('#media-icon').empty()
if ($(icon).hasClass('fa-file-image-o')){
$('#media-icon').append($('<img>').attr('src', f_loc).attr('width', '100%'));
} else {
// icon is empty so we need to pull outerHTML
$('#media-icon').append(icon.outerHTML);
}
$('#media-item').show();
});
wrapper.append(link);
wrapper.attr('data-location', script_root + '/files/' + f.location);
wrapper.attr('data-id', f.id);
wrapper.attr('data-filename', fname);
list.append(wrapper);
wrapper.append($('<span>').attr('class', 'media-item-title').text(fname));
}
}
wrapper.append($('<span>').attr('class', 'media-item-title').text(fname));
}
}
var editor = CodeMirror.fromTextArea(document.getElementById("admin-pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'elegant'
});
var editor = CodeMirror.fromTextArea(document.getElementById("admin-pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'elegant'
});
function insert_at_cursor(editor, text) {
var doc = editor.getDoc();
var cursor = doc.getCursor();
doc.replaceRange(text, cursor);
}
function insert_at_cursor(editor, text) {
var doc = editor.getDoc();
var cursor = doc.getCursor();
doc.replaceRange(text, cursor);
}
$('#media-insert').click(function(e){
var tag = $('#media-icon').children()[0].nodeName.toLowerCase();
console.log(tag);
var link = $('#media-link').val();
var fname = $('#media-filename').text();
if (tag == 'img'){
var entry = '![{0}]({1})'.format(fname, link);
} else if (tag == 'i'){
var entry = '[{0}]({1})'.format(fname, link);
}
$('#media-insert').click(function(e){
var tag = $('#media-icon').children()[0].nodeName.toLowerCase();
console.log(tag);
var link = $('#media-link').val();
var fname = $('#media-filename').text();
if (tag == 'img'){
var entry = '![{0}]({1})'.format(fname, link);
} else if (tag == 'i'){
var entry = '[{0}]({1})'.format(fname, link);
}
insert_at_cursor(editor, entry);
});
insert_at_cursor(editor, entry);
});
$('#page-edit').submit(function (e){
$(this).attr('action', '{{ request.script_root }}/admin/pages/'+$('#route').val());
});
$('#page-edit').submit(function (e){
$(this).attr('action', '{{ request.script_root }}/admin/pages/'+$('#route').val());
});
// Markdown Preview
$('#content-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#content-preview'){
$(event.target.hash).html(marked(editor.getValue(), {'gfm':true, 'breaks':true}));
}
});
// Markdown Preview
$('#content-edit').on('shown.bs.tab', function (event) {
if (event.target.hash == '#content-preview'){
$(event.target.hash).html(marked(editor.getValue(), {'gfm':true, 'breaks':true}));
}
});
$('#media-button').click(function(){
$.get(script_root + '/admin/media', function(data){
$('#media-library-list').empty();
refreshfiles(data);
$('#media-modal').modal();
});
})
$('#media-button').click(function(){
$.get(script_root + '/admin/media', function(data){
$('#media-library-list').empty();
refreshfiles(data);
$('#media-modal').modal();
});
})
</script>
{% endblock %}

View File

@ -1,178 +1,178 @@
{% extends "admin/base.html" %}
{% block content %}
<div class="row">
<div id="solves-graph"></div>
</div>
<div class="row">
<div>
<div id="keys-pie-graph"></div>
</div>
<div>
<div id="categories-pie-graph"></div>
</div>
</div>
<div class="row">
<div id="solves-graph"></div>
</div>
<div class="row">
<div>
<div id="keys-pie-graph"></div>
</div>
<div>
<div id="categories-pie-graph"></div>
</div>
</div>
{% endblock %}
{% block scripts %}
<style>
#solves-graph{
display: block;
height: 500px;
}
#keys-pie-graph{
height: 400px;
display: block;
}
#categories-pie-graph{
height: 400px;
display: block;
}
</style>
<script src="{{ request.script_root }}/static/admin/js/vendor/plotly.min.js"></script>
<script type="text/javascript">
// $.distint(array)
// Unique elements in array
$.extend({
distinct : function(anArray) {
var result = [];
$.each(anArray, function(i,v){
if ($.inArray(v, result) == -1) result.push(v);
});
return result;
}
});
<style>
#solves-graph{
display: block;
height: 500px;
}
#keys-pie-graph{
height: 400px;
display: block;
}
#categories-pie-graph{
height: 400px;
display: block;
}
</style>
<script src="{{ request.script_root }}/static/admin/js/vendor/plotly.min.js"></script>
<script type="text/javascript">
// $.distint(array)
// Unique elements in array
$.extend({
distinct : function(anArray) {
var result = [];
$.each(anArray, function(i,v){
if ($.inArray(v, result) == -1) result.push(v);
});
return result;
}
});
// Praise Resig: http://ejohn.org/blog/fast-javascript-maxmin/
Array.max = function( array ){
return Math.max.apply( Math, array );
};
// Praise Resig: http://ejohn.org/blog/fast-javascript-maxmin/
Array.max = function( array ){
return Math.max.apply( Math, array );
};
function colorhash (x) {
color = ""
for (var i = 20; i <= 60; i+=20){
x += i
x *= i
color += x.toString(16)
};
return "#" + color.substring(0, 6)
}
function colorhash (x) {
color = ""
for (var i = 20; i <= 60; i+=20){
x += i
x *= i
color += x.toString(16)
};
return "#" + color.substring(0, 6)
}
function solves_graph() {
$.get('{{ request.script_root }}/admin/graphs/solves', function (data) {
var solves = $.parseJSON(JSON.stringify(data));
var chals = [];
var counts = [];
var colors = [];
var annotations = [];
var i = 1;
solves_order = Object.keys(solves).sort(function (a, b) {
return solves[b] - solves[a]
});
$.each(solves_order, function (key, value) {
chals.push(value);
counts.push(solves[value]);
var result = {
x: value,
y: solves[value],
text: solves[value],
xanchor: 'center',
yanchor: 'bottom',
showarrow: false
};
annotations.push(result);
colors.push(colorhash(i++));
});
function solves_graph() {
$.get('{{ request.script_root }}/admin/graphs/solves', function (data) {
var solves = $.parseJSON(JSON.stringify(data));
var chals = [];
var counts = [];
var colors = [];
var annotations = [];
var i = 1;
solves_order = Object.keys(solves).sort(function (a, b) {
return solves[b] - solves[a]
});
$.each(solves_order, function (key, value) {
chals.push(value);
counts.push(solves[value]);
var result = {
x: value,
y: solves[value],
text: solves[value],
xanchor: 'center',
yanchor: 'bottom',
showarrow: false
};
annotations.push(result);
colors.push(colorhash(i++));
});
var data = [{
type: 'bar',
x: chals,
y: counts,
text: counts,
orientation: 'v'
}];
var data = [{
type: 'bar',
x: chals,
y: counts,
text: counts,
orientation: 'v'
}];
var layout = {
title: 'Score Counts',
annotations: annotations
};
var layout = {
title: 'Score Counts',
annotations: annotations
};
Plotly.newPlot('solves-graph', data, layout);
});
}
Plotly.newPlot('solves-graph', data, layout);
});
}
function keys_percentage_graph(){
// Solves and Fails pie chart
$.get('{{ request.script_root }}/admin/fails/all', function(data){
var res = $.parseJSON(JSON.stringify(data));
var solves = res['solves'];
var fails = res['fails'];
function keys_percentage_graph(){
// Solves and Fails pie chart
$.get('{{ request.script_root }}/admin/fails/all', function(data){
var res = $.parseJSON(JSON.stringify(data));
var solves = res['solves'];
var fails = res['fails'];
var data = [{
values: [solves, fails],
labels: ['Solves', 'Fails'],
marker: {
colors: [
"rgb(0, 209, 64)",
"rgb(207, 38, 0)"
]
},
hole: .4,
type: 'pie'
}];
var data = [{
values: [solves, fails],
labels: ['Solves', 'Fails'],
marker: {
colors: [
"rgb(0, 209, 64)",
"rgb(207, 38, 0)"
]
},
hole: .4,
type: 'pie'
}];
var layout = {
title: 'Key Percentages'
};
var layout = {
title: 'Key Percentages'
};
Plotly.newPlot('keys-pie-graph', data, layout);
});
}
Plotly.newPlot('keys-pie-graph', data, layout);
});
}
function category_breakdown_graph(){
$.get('{{ request.script_root }}/admin/graphs/categories', function(data){
res = $.parseJSON(JSON.stringify(data));
res = res['categories']
function category_breakdown_graph(){
$.get('{{ request.script_root }}/admin/graphs/categories', function(data){
res = $.parseJSON(JSON.stringify(data));
res = res['categories']
categories = [];
count = [];
for (var i = 0; i < res.length; i++) {
categories.push(res[i].category)
count.push(res[i].count)
};
categories = [];
count = [];
for (var i = 0; i < res.length; i++) {
categories.push(res[i].category)
count.push(res[i].count)
};
var data = [{
values: count,
labels: categories,
hole: .4,
type: 'pie'
}];
var data = [{
values: count,
labels: categories,
hole: .4,
type: 'pie'
}];
var layout = {
title: 'Category Breakdown'
};
var layout = {
title: 'Category Breakdown'
};
Plotly.newPlot('categories-pie-graph', data, layout);
});
}
Plotly.newPlot('categories-pie-graph', data, layout);
});
}
function update(){
solves_graph();
keys_percentage_graph();
category_breakdown_graph();
}
function update(){
solves_graph();
keys_percentage_graph();
category_breakdown_graph();
}
$(function() {
update();
window.onresize = function () {
console.log('resizing')
Plotly.Plots.resize(document.getElementById('keys-pie-graph'));
Plotly.Plots.resize(document.getElementById('categories-pie-graph'));
Plotly.Plots.resize(document.getElementById('solves-graph'));
};
});
$(function() {
update();
window.onresize = function () {
console.log('resizing')
Plotly.Plots.resize(document.getElementById('keys-pie-graph'));
Plotly.Plots.resize(document.getElementById('categories-pie-graph'));
Plotly.Plots.resize(document.getElementById('solves-graph'));
};
});
setInterval(update, 300000);
setInterval(update, 300000);
</script>
</script>
{% endblock %}

View File

@ -2,78 +2,78 @@
<html>
<head>
<title>Admin Panel</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/style.css">
<link href='{{ request.script_root }}/static/admin/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/admin/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/style.css">
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/moment-timezone-with-data.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
{% block stylesheets %} {% endblock %}
<title>Admin Panel</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/original/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/vendor/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="{{ request.script_root }}/static/admin/css/style.css">
<link href='{{ request.script_root }}/static/admin/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/admin/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/style.css">
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/moment-timezone-with-data.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
{% block stylesheets %} {% endblock %}
</head>
<body>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">CTFd</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right">
<li><a href="{{ request.script_root }}/admin/graphs">Graphs</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Pages <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ request.script_root }}/admin/pages">All Pages</a></li>
<li><a href="{{ request.script_root }}/admin/pages?mode=create">New Page</a></li>
</ul>
</li>
<li><a href="{{ request.script_root }}/admin/teams">Teams</a></li>
<li><a href="{{ request.script_root }}/admin/scoreboard">Scoreboard</a></li>
{% if can_create_container() %}
<li><a href="{{ request.script_root }}/admin/containers">Containers</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/admin/chals">Challenges</a></li>
<li><a href="{{ request.script_root }}/admin/statistics">Statistics</a></li>
<li><a href="{{ request.script_root }}/admin/config">Config</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Plugins <span class="caret"></span></a>
<ul class="dropdown-menu">
{% for plugin in get_configurable_plugins() %}
<li><a href="{{ request.script_root }}/admin/plugins/{{ plugin }}">{{ plugin }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">CTFd</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav navbar-nav-right">
<li><a href="{{ request.script_root }}/admin/graphs">Graphs</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Pages <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ request.script_root }}/admin/pages">All Pages</a></li>
<li><a href="{{ request.script_root }}/admin/pages?mode=create">New Page</a></li>
</ul>
</li>
<li><a href="{{ request.script_root }}/admin/teams">Teams</a></li>
<li><a href="{{ request.script_root }}/admin/scoreboard">Scoreboard</a></li>
{% if can_create_container() %}
<li><a href="{{ request.script_root }}/admin/containers">Containers</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/admin/chals">Challenges</a></li>
<li><a href="{{ request.script_root }}/admin/statistics">Statistics</a></li>
<li><a href="{{ request.script_root }}/admin/config">Config</a></li>
<li>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Plugins <span class="caret"></span></a>
<ul class="dropdown-menu">
{% for plugin in get_configurable_plugins() %}
<li><a href="{{ request.script_root }}/admin/plugins/{{ plugin }}">{{ plugin }}</a></li>
{% endfor %}
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="container">
{{ content | safe }}
</div>
<div class="container">
{{ content | safe }}
</div>
</div>
<script src="{{ request.script_root }}/static/admin/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/bootstrap.min.js"></script>
{% block scripts %} {% endblock %}
<script src="{{ request.script_root }}/static/admin/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/bootstrap.min.js"></script>
{% block scripts %} {% endblock %}
</body>
</html>

View File

@ -1,79 +1,79 @@
{% extends "admin/base.html" %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/vendor/codemirror.min.css">
<style>
.CodeMirror {
padding-left: 15px;
margin-bottom: 10px;
}
</style>
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/admin/css/vendor/codemirror.min.css">
<style>
.CodeMirror {
padding-left: 15px;
margin-bottom: 10px;
}
</style>
{% endblock %}
{% block content %}
<div class="row">
<br>
<div id="confirm" class="modal fade" tabindex="-1" data-width="760">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Delete Page</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-route-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-route" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<br>
<div id="confirm" class="modal fade" tabindex="-1" data-width="760">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Delete Page</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-route-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-route" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<h3>Pages</h3>
<table id="pages" class="table table-striped">
<thead>
<tr>
<td><b>Route</b></td>
<td class="text-center" style="width: 150px;"><b>Settings</b></td>
</tr>
</thead>
<tbody>
{% for route in routes %}
<tr name="{{ route.route }}">
<td class="route-name"><a
href="{{ request.script_root }}/admin/pages/{{ route.route }}">{{ route.route }}</a></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="col-md-6">
<h3>Pages</h3>
<table id="pages" class="table table-striped">
<thead>
<tr>
<td><b>Route</b></td>
<td class="text-center" style="width: 150px;"><b>Settings</b></td>
</tr>
</thead>
<tbody>
{% for route in routes %}
<tr name="{{ route.route }}">
<td class="route-name"><a
href="{{ request.script_root }}/admin/pages/{{ route.route }}">{{ route.route }}</a></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ request.script_root }}/admin/pages?mode=create">
<button type="button" id="submit" class="btn btn-md btn-primary btn-theme btn-outlined">
Add Page
</button>
</a>
</div>
<a href="{{ request.script_root }}/admin/pages?mode=create">
<button type="button" id="submit" class="btn btn-md btn-primary btn-theme btn-outlined">
Add Page
</button>
</a>
</div>
<div class="col-md-6">
<h3>CSS editor</h3>
<form method="POST">
<textarea id="pages-editor" name="css" style="padding-left:20px;">{{ css }}</textarea>
<button onclick="save_css()" type="button" id="submit" class="btn btn-md btn-primary btn-theme btn-outlined">
Update CSS
</button>
</form>
</div>
<div class="col-md-6">
<h3>CSS editor</h3>
<form method="POST">
<textarea id="pages-editor" name="css" style="padding-left:20px; visibility: hidden;">{{ css }}</textarea>
<button onclick="save_css()" type="button" id="submit" class="btn btn-md btn-primary btn-theme btn-outlined">
Update CSS
</button>
</form>
</div>
</div>
{% endblock %}
@ -81,44 +81,44 @@
<script src="{{ request.script_root }}/static/admin/js/vendor/codemirror.min.js"></script>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("pages-editor"), {
lineNumbers: true,
lineWrapping: true,
mode: "xml",
htmlMode: true,
theme: 'elegant'
lineNumbers: true,
lineWrapping: true,
mode: "css",
htmlMode: false,
theme: 'elegant'
});
$('#delete-route').click(function(e){
e.preventDefault();
var route = $('#confirm input[name="route"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
e.preventDefault();
var route = $('#confirm input[name="route"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
});
function load_confirm_modal(route){
var modal = $('#confirm')
modal.find('input[name=route]').val(route)
modal.find('#confirm-route-name').text(route)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/page/'+route+'/delete');
$('#confirm').modal();
var modal = $('#confirm')
modal.find('input[name=route]').val(route)
modal.find('#confirm-route-name').text(route)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/page/'+route+'/delete');
$('#confirm').modal();
}
function save_css(){
var css = editor.getValue();
var nonce = $('#nonce').val();
$.post(script_root + '/admin/css', {'css':css, 'nonce':nonce}, function(){
console.log('saved');
});
var css = editor.getValue();
var nonce = $('#nonce').val();
$.post(script_root + '/admin/css', {'css':css, 'nonce':nonce}, function(){
location.reload();
});
}
$('.fa-times').click(function(){
var elem = $(this).parent().parent();
var name = elem.find('.route-name').text().trim();
load_confirm_modal(name)
var elem = $(this).parent().parent();
var name = elem.find('.route-name').text().trim();
load_confirm_modal(name)
});
</script>

View File

@ -2,40 +2,40 @@
{% block content %}
<div class="row">
<br>
<h1>Scoreboard</h1>
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b></td>
<td><b>Team</b></td>
<td><b>Score</b></td>
<td><b>Status</b></td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td>{{ loop.index }}</td>
<td><a href="{{ request.script_root }}/admin/team/{{ team.teamid }}">{{ team.name }}</a></td>
<td>{{ team.score }}</td>
<td>
{% if not team.banned %}
<form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/ban">
<a onclick="$(this).parent().submit()">Ban</a>
<input type="hidden" value="{{ nonce }}" name="nonce">
</form>
{%else %}
<form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/unban">
<a onclick="$(this).parent().submit()">Unban</a>
<input type="hidden" value="{{ nonce }}" name="nonce">
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
<h1>Scoreboard</h1>
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b></td>
<td><b>Team</b></td>
<td><b>Score</b></td>
<td><b>Status</b></td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td>{{ loop.index }}</td>
<td><a href="{{ request.script_root }}/admin/team/{{ team.teamid }}">{{ team.name }}</a></td>
<td>{{ team.score }}</td>
<td>
{% if not team.banned %}
<form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/ban">
<a onclick="$(this).parent().submit()">Hide</a>
<input type="hidden" value="{{ nonce }}" name="nonce">
</form>
{%else %}
<form method="POST" style="margin:0;" action="{{ request.script_root }}/admin/team/{{ team.teamid }}/unban">
<a onclick="$(this).parent().submit()">Unhide</a>
<input type="hidden" value="{{ nonce }}" name="nonce">
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

View File

@ -3,19 +3,19 @@
{% block content %}
<div class="row" style="text-align:center">
<br>
<h1>Statistics</h1>
<br>
<h1>Statistics</h1>
<h3><b>{{ team_count }}</b> teams registered</h3>
<h3><b>{{ wrong_count }}</b> <a href="{{ request.script_root }}/admin/wrong_keys/1">wrong keys</a> submitted</h3>
<h3><b>{{ solve_count }}</b> <a href="{{ request.script_root }}/admin/correct_keys/1">right keys</a> submitted</h3>
<h3><b>{{ challenge_count }}</b> challenges</h3>
{% if most_solved %}
<h3>Most solved: <b>{{ most_solved }}</b> with {{ solve_data[most_solved] }}</b> solves</h3>
{% endif %}
{% if least_solved %}
<h3>Least solved: <b>{{ least_solved }}</b> with {{ solve_data[least_solved] }}</b> solves</h3>
{% endif %}
<h3><b>{{ team_count }}</b> teams registered</h3>
<h3><b>{{ wrong_count }}</b> <a href="{{ request.script_root }}/admin/wrong_keys/1">wrong keys</a> submitted</h3>
<h3><b>{{ solve_count }}</b> <a href="{{ request.script_root }}/admin/correct_keys/1">right keys</a> submitted</h3>
<h3><b>{{ challenge_count }}</b> challenges</h3>
{% if most_solved %}
<h3>Most solved: <b>{{ most_solved }}</b> with {{ solve_data[most_solved] }}</b> solves</h3>
{% endif %}
{% if least_solved %}
<h3>Least solved: <b>{{ least_solved }}</b> with {{ solve_data[least_solved] }}</b> solves</h3>
{% endif %}
</div>

View File

@ -2,355 +2,355 @@
{% block stylesheets %}
<style>
.btn-primary {
background-color: #337ab7;
}
.btn-primary {
background-color: #337ab7;
}
.btn-danger {
background-color: #d9534f;
}
.btn-danger {
background-color: #d9534f;
}
</style>
{% endblock %}
{% block content %}
<div class="modal fade" id="create-award-modal" tabindex="-1" role="dialog" aria-labelledby="create-award-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="create-award-label">Create Award</h4>
</div>
<div class="modal-body">
<form id="award-create-form" method="POST" action="{{ request.script_root }}/admin/awards/add">
<div class="form-group">
<label for="award-name-input">Name</label>
<input type="text" class="form-control" id="award-name-input" name="name" placeholder="Enter award name">
</div>
<div class="form-group">
<label for="award-value-input">Value</label>
<input type="number" class="form-control" id="award-value-input" name="value" placeholder="Enter award value">
</div>
<div class="form-group">
<label for="award-category-input">Category</label>
<input type="text" class="form-control" id="award-category-input" name="category" placeholder="Enter award category">
</div>
<div class="form-group">
<label for="award-description-input" class="control-label">Description</label>
<textarea id="award-description-input" class="form-control" name="description" rows="10" placeholder="Description of what the award is for"></textarea>
</div>
<div class="form-group">
<label for="award-icon-input">Award Icon</label>
<input type="file" id="award-icon-input" name="icon">
</div>
<input type="hidden" value="{{ team.id }}" name="teamid" id="teamid">
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
<div class="modal-footer">
<button type="submit" id="award-create-button" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="create-award-label">Create Award</h4>
</div>
<div class="modal-body">
<form id="award-create-form" method="POST" action="{{ request.script_root }}/admin/awards/add">
<div class="form-group">
<label for="award-name-input">Name</label>
<input type="text" class="form-control" id="award-name-input" name="name" placeholder="Enter award name">
</div>
<div class="form-group">
<label for="award-value-input">Value</label>
<input type="number" class="form-control" id="award-value-input" name="value" placeholder="Enter award value">
</div>
<div class="form-group">
<label for="award-category-input">Category</label>
<input type="text" class="form-control" id="award-category-input" name="category" placeholder="Enter award category">
</div>
<div class="form-group">
<label for="award-description-input" class="control-label">Description</label>
<textarea id="award-description-input" class="form-control" name="description" rows="10" placeholder="Description of what the award is for"></textarea>
</div>
<div class="form-group">
<label for="award-icon-input">Award Icon</label>
<input type="file" id="award-icon-input" name="icon">
</div>
<input type="hidden" value="{{ team.id }}" name="teamid" id="teamid">
<input type="hidden" value="{{ nonce }}" name="nonce" id="nonce">
<div class="modal-footer">
<button type="submit" id="award-create-button" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="row container-fluid">
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3 id="confirm-title">Delete Key</h3>
</div>
<div class="modal-body">
<form method="POST" action="{{ request.script_root }}/admin/chal/delete">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p id="confirm-description"></p>
<a onclick="$('#confirm').modal('hide')" class="btn btn-primary">No</a>
<button class="btn btn-danger" id="delete-solve" type="button">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<h3 id="confirm-title">Delete Key</h3>
</div>
<div class="modal-body">
<form method="POST" action="{{ request.script_root }}/admin/chal/delete">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p id="confirm-description"></p>
<a onclick="$('#confirm').modal('hide')" class="btn btn-primary">No</a>
<button class="btn btn-danger" id="delete-solve" type="button">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<h1 id="team-id">{{ team.name }}</h1>
<h2 id="team-email" class="text-center">{{ team.email }}</h2>
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
<h1 id="team-id">{{ team.name }}</h1>
<h2 id="team-email" class="text-center">{{ team.email }}</h2>
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<div id="score-graph"></div>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<div id="score-graph"></div>
<table class="table table-striped">
<h3>IP Addresses</h3>
<thead>
<tr>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">{{ addr[0]|long2ip }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ addr[1]|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>IP Addresses</h3>
<thead>
<tr>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">{{ addr[0]|long2ip }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ addr[1]|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Awards</h3>
<thead>
<tr>
<td class="text-center"><b>Name</b></td>
<td class="text-center"><b>Description</b></td>
<td class="text-center"><b>Date</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Icon</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody id="awards-body">
{% for award in awards %}
<tr class="award-row">
<td class="text-center chal" id="{{ award.id }}">{{ award.name }}</td>
<td class="text-center">{{ award.description }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ award.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center">{{ award.value }}</td>
<td class="text-center">{{ award.category }}</td>
<td class="text-center">{{ award.icon }}</td>
<table class="table table-striped">
<h3>Awards</h3>
<thead>
<tr>
<td class="text-center"><b>Name</b></td>
<td class="text-center"><b>Description</b></td>
<td class="text-center"><b>Date</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Icon</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody id="awards-body">
{% for award in awards %}
<tr class="award-row">
<td class="text-center chal" id="{{ award.id }}">{{ award.name }}</td>
<td class="text-center">{{ award.description }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ award.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center">{{ award.value }}</td>
<td class="text-center">{{ award.category }}</td>
<td class="text-center">{{ award.icon }}</td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row container-fluid">
<button type="button" data-toggle="modal" data-target="#create-award-modal" class="btn btn-primary pull-right">Create Award</button>
</div>
<div class="row container-fluid">
<button type="button" data-toggle="modal" data-target="#create-award-modal" class="btn btn-primary pull-right">Create Award</button>
</div>
<table class="table table-striped">
<h3>Solves</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Submitted</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Time</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr class="chal-solve">
<td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal.name }}</td>
<td class="text-center flag" id="{{ solve.id }}">{{ solve.flag }}</td>
<td class="text-center">{{ solve.chal.category }}</td>
<td class="text-center">{{ solve.chal.value }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Solves</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Submitted</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Time</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr class="chal-solve">
<td class="text-center chal" id="{{ solve.chalid }}">{{ solve.chal.name }}</td>
<td class="text-center flag" id="{{ solve.id }}">{{ solve.flag }}</td>
<td class="text-center">{{ solve.chal.category }}</td>
<td class="text-center">{{ solve.chal.value }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Missing</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Mark Solved</b></td>
</tr>
</thead>
<tbody>
{% for chal in missing %}
<tr class="chal-solve">
<td class="text-center chal" id="{{ chal.id }}">{{ chal.name }}</td>
<td class="text-center">{{ chal.category }}</td>
<td class="text-center">{{ chal.value }}</td>
<td class="text-center"><i class="fa fa-check"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Missing</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Category</b></td>
<td class="text-center"><b>Value</b></td>
<td class="text-center"><b>Mark Solved</b></td>
</tr>
</thead>
<tbody>
{% for chal in missing %}
<tr class="chal-solve">
<td class="text-center chal" id="{{ chal.id }}">{{ chal.name }}</td>
<td class="text-center">{{ chal.category }}</td>
<td class="text-center">{{ chal.value }}</td>
<td class="text-center"><i class="fa fa-check"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Wrong Keys</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Submitted</b></td>
<td class="text-center"><b>Time</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody>
{% for wrong_key in wrong_keys %}
<tr class="chal-wrong">
<td class="text-center chal" id="{{ wrong_key.chalid }}">{{ wrong_key.chal.name }}</td>
<td class="text-center flag" id="{{ wrong_key.id }}">{{ wrong_key.flag }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ wrong_key.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="table table-striped">
<h3>Wrong Keys</h3>
<thead>
<tr>
<td class="text-center"><b>Challenge</b></td>
<td class="text-center"><b>Submitted</b></td>
<td class="text-center"><b>Time</b></td>
<td class="text-center"><b>Delete</b></td>
</tr>
</thead>
<tbody>
{% for wrong_key in wrong_keys %}
<tr class="chal-wrong">
<td class="text-center chal" id="{{ wrong_key.chalid }}">{{ wrong_key.chal.name }}</td>
<td class="text-center flag" id="{{ wrong_key.id }}">{{ wrong_key.flag }}</td>
<td class="text-center solve-time"><script>document.write( moment({{ wrong_key.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
<td class="text-center"><i class="fa fa-times"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/team.js"></script>
<script>
$('#delete-solve').click(function (e) {
e.preventDefault();
var solve = $('#confirm input[name="solve"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function (data) {
var data = $.parseJSON(JSON.stringify(data))
if (data == "1") {
location.reload()
}
})
});
<script src="{{ request.script_root }}/static/admin/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/admin/js/utils.js"></script>
<script src="{{ request.script_root }}/static/admin/js/team.js"></script>
<script>
$('#delete-solve').click(function (e) {
e.preventDefault();
var solve = $('#confirm input[name="solve"]').val()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function (data) {
var data = $.parseJSON(JSON.stringify(data))
if (data == "1") {
location.reload()
}
})
});
function load_confirm_modal(msg) {
var title = msg.title;
var description = msg.description;
var action = msg.action;
$('#confirm-title').text(title);
$('#confirm-description').html(description);
$('#confirm form').attr('action', action);
$('#confirm').modal('show');
}
function load_confirm_modal(msg) {
var title = msg.title;
var description = msg.description;
var action = msg.action;
$('#confirm-title').text(title);
$('#confirm-description').html(description);
$('#confirm form').attr('action', action);
$('#confirm').modal('show');
}
$('.fa-times').click(function () {
var elem = $(this).parent().parent();
var type = elem.attr('class');
var chal_name = elem.find('.chal').text().trim();
var team_name = $("#team-id").text();
var key_id = elem.find('.flag').attr('id');
$('.fa-times').click(function () {
var elem = $(this).parent().parent();
var type = elem.attr('class');
var chal_name = elem.find('.chal').text().trim();
var team_name = $("#team-id").text();
var key_id = elem.find('.flag').attr('id');
if (type == 'chal-solve'){
var title = 'Delete Solve';
var description = "<span>Are you sure you want to delete " +
"<strong>correct</strong> " +
"key submission for team: " +
"<strong id='confirm-team-name'></strong> " +
"in challenge: " +
"<strong id='confirm-chal-name'></strong>?</span>"
if (type == 'chal-solve'){
var title = 'Delete Solve';
var description = "<span>Are you sure you want to delete " +
"<strong>correct</strong> " +
"key submission for team: " +
"<strong id='confirm-team-name'></strong> " +
"in challenge: " +
"<strong id='confirm-chal-name'></strong>?</span>"
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var action = '{{ request.script_root }}/admin/solves/' + key_id + '/delete';
} else if (type == 'chal-wrong') {
var title = 'Delete Wrong Key';
var description = "<span>Are you sure you want to delete " +
"<strong>incorrect</strong> " +
"key submission for team: " +
"<strong id='confirm-team-name'></strong> " +
"in challenge: " +
"<strong id='confirm-chal-name'></strong>?</span>"
var action = '{{ request.script_root }}/admin/solves/' + key_id + '/delete';
} else if (type == 'chal-wrong') {
var title = 'Delete Wrong Key';
var description = "<span>Are you sure you want to delete " +
"<strong>incorrect</strong> " +
"key submission for team: " +
"<strong id='confirm-team-name'></strong> " +
"in challenge: " +
"<strong id='confirm-chal-name'></strong>?</span>"
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var action = '{{ request.script_root }}/admin/wrong_keys/' + key_id + '/delete';
} else if (type == 'award-row') {
var title = 'Delete Award';
var award_id = elem.find('.chal').attr('id');
var description = "<span>Are you sure you want to delete the " +
"<strong>{0}</strong> award?</span>".format(chal_name);
var action = '{{ request.script_root }}/admin/awards/{0}/delete'.format(award_id);
}
var action = '{{ request.script_root }}/admin/wrong_keys/' + key_id + '/delete';
} else if (type == 'award-row') {
var title = 'Delete Award';
var award_id = elem.find('.chal').attr('id');
var description = "<span>Are you sure you want to delete the " +
"<strong>{0}</strong> award?</span>".format(chal_name);
var action = '{{ request.script_root }}/admin/awards/{0}/delete'.format(award_id);
}
var msg = {
title : title,
description : description,
action : action,
}
var msg = {
title : title,
description : description,
action : action,
}
load_confirm_modal(msg)
});
load_confirm_modal(msg)
});
$('.fa-check').click(function () {
var elem = $(this).parent().parent();
var type = elem.attr('class');
var chal = elem.find('.chal').attr('id');
var chal_name = elem.find('.chal').text().trim();
var team = window.location.pathname.split('/').pop();
var team_name = $("#team-id").text();
$('.fa-check').click(function () {
var elem = $(this).parent().parent();
var type = elem.attr('class');
var chal = elem.find('.chal').attr('id');
var chal_name = elem.find('.chal').text().trim();
var team = window.location.pathname.split('/').pop();
var team_name = $("#team-id").text();
var title = 'Mark '+chal_name+' Solved';
var description = "<span>Are you sure you want to mark " +
"<strong id='confirm-chal-name'></strong> " +
"as solved for team " +
"<strong id='confirm-team-name'></strong> " +
"?</span>";
var title = 'Mark '+chal_name+' Solved';
var description = "<span>Are you sure you want to mark " +
"<strong id='confirm-chal-name'></strong> " +
"as solved for team " +
"<strong id='confirm-team-name'></strong> " +
"?</span>";
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var description = $($.parseHTML(description));
description.find('#confirm-team-name').text(team_name);
description.find('#confirm-chal-name').text(chal_name);
description = description.html()
var action = '{{request.script_root }}/admin/solves/' + team + '/' + chal + '/solve';
var action = '{{request.script_root }}/admin/solves/' + team + '/' + chal + '/solve';
var msg = {
title : title,
description : description,
action : action,
};
var msg = {
title : title,
description : description,
action : action,
};
load_confirm_modal(msg);
});
load_confirm_modal(msg);
});
$('#award-create-form').submit(function(e){
$.post($(this).attr('action'), $(this).serialize(), function(res){
if (res == '1'){
var award = $('#award-create-form').serializeObject();
var award_text = '<td class="text-center">{0}</td>'.format(award.name) +
'<td class="text-center">{0}</td>'.format(award.description) +
'<td class="text-center solve-time">{0}</td>'.format(moment().local().format('MMMM Do, h:mm:ss A')) +
'<td class="text-center">{0}</td>'.format(award.value) +
'<td class="text-center">{0}</td>'.format(award.category) +
'<td class="text-center">{0}</td>'.format('None') +
'<td class="text-center"><i class="fa fa-times"></i></td>'
$('#awards-body').append(award_text);
$('#create-award-modal').modal('hide');
}
})
e.preventDefault();
});
$('#award-create-form').submit(function(e){
$.post($(this).attr('action'), $(this).serialize(), function(res){
if (res == '1'){
var award = $('#award-create-form').serializeObject();
var award_text = '<td class="text-center">{0}</td>'.format(award.name) +
'<td class="text-center">{0}</td>'.format(award.description) +
'<td class="text-center solve-time">{0}</td>'.format(moment().local().format('MMMM Do, h:mm:ss A')) +
'<td class="text-center">{0}</td>'.format(award.value) +
'<td class="text-center">{0}</td>'.format(award.category) +
'<td class="text-center">{0}</td>'.format('None') +
'<td class="text-center"><i class="fa fa-times"></i></td>'
$('#awards-body').append(award_text);
$('#create-award-modal').modal('hide');
}
})
e.preventDefault();
});
</script>
</script>
{% endblock %}

View File

@ -10,299 +10,302 @@ input[type="checkbox"] { margin: 0px !important; position: relative; top: 5px; }
{% block content %}
<div class="row">
<br>
<h1>Teams</h1>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Delete User</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-team-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-user" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="email-user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Email User</h2>
</div>
<div class="modal-body">
<form method="POST">
<input type="hidden" name="id">
<input type="hidden" name="nonce" value="{{ nonce }}">
<textarea class="form-control" name="msg" placeholder="Enter your message here" rows="15"></textarea>
<br>
<div id="email-user-errors"></div>
<button type="button" id="send-user-email" class="btn btn-theme btn-outlined">Send Message</button>
</form>
</div>
</div>
</div>
</div>
<div id="user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="text-center">Edit User</h2>
</div>
<div class="modal-body" style="padding:20px; height:525px;">
<form method="POST" action="{{ request.script_root }}/admin/teams/">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name" placeholder="Enter new team name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email" placeholder="Enter new email" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password" />
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="text" class="form-control" name="website" id="website" placeholder="Enter website">
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation" placeholder="Enter affiliation">
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<input type="text" class="form-control" name="country" id="country" placeholder="Enter country">
</div>
<div id="results">
<br>
<h1>Teams</h1>
<div id="confirm" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h2 class="text-center">Delete User</h2>
</div>
<div class="modal-body" style="height:110px">
<div class="row-fluid">
<div class="col-md-12">
<form method="POST">
<input type="hidden" name="route">
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="small-6 small-centered text-center columns">
<p>Are you sure you want to delete <strong id="confirm-team-name"></strong>?</p>
<button type="button" data-dismiss="modal" class="btn btn-theme btn-outlined">No</button>
<button type="button" id="delete-user" class="btn btn-theme btn-outlined">Yes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="email-user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h2 class="text-center">Email User</h2>
</div>
<div class="modal-body">
<form method="POST">
<input type="hidden" name="id">
<input type="hidden" name="nonce" value="{{ nonce }}">
<textarea class="form-control" name="msg" placeholder="Enter your message here" rows="15"></textarea>
<br>
<div id="email-user-errors"></div>
<button type="button" id="send-user-email" class="btn btn-theme btn-outlined">Send Message</button>
</form>
</div>
</div>
</div>
</div>
<div id="user" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h2 class="text-center">Edit User</h2>
</div>
<div class="modal-body" style="padding:20px; height:525px;">
<form method="POST" action="{{ request.script_root }}/admin/teams/">
<input type="hidden" name="nonce" value="{{ nonce }}">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name" placeholder="Enter new team name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email" placeholder="Enter new email" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password" />
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="text" class="form-control" name="website" id="website" placeholder="Enter website">
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation" placeholder="Enter affiliation">
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<input type="text" class="form-control" name="country" id="country" placeholder="Enter country">
</div>
<div id="results">
</div>
<button id="update-user" type="submit" class="btn btn-theme btn-outlined pull-right">Update</button>
</form>
</div>
</div>
</div>
</div>
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td width="10px" class="text-center"><b>ID</b>
</td>
<td class="text-center"><b>Team</b>
</td>
<td class="text-center"><b>Email</b>
</td>
<td class="text-center"><b>Website</b>
</td>
<td class="text-center"><b>Affiliation</b>
</td>
<td class="text-center"><b>Country</b>
</td>
<td class="text-center"><b>Admin</b>
</td>
<td class="text-center"><b>Verified</b>
</td>
<td class="text-center"><b>Settings</b>
</td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr name="{{ team.id }}">
<td class="team-id" value="{{ team.id }}">{{ team.id }}</td>
<td class="team-name" value="{{ team.name }}"><a href="{{ request.script_root }}/admin/team/{{ team.id }}">{{ team.name | truncate(32) }}</a>
</td>
<td class="team-email">{{ team.email | truncate(32) }}</td>
<td class="team-website">{% if team.website and (team.website.startswith('http://') or team.website.startswith('https://')) %}<a href="{{ team.website }}">{{ team.website | truncate(32) }}</a>{% endif %}
</td>
<td class="team-affiliation" value="{{ team.affiliation if team.affiliation is not none }}"><span>{% if team.affiliation %}{{ team.affiliation | truncate(20) }}{% endif %}</span>
</td>
<td class="team-country" value="{{ team.country if team.country is not none }}"><span>{% if team.country %}{{ team.country }}{% endif %}</span>
</td>
<td class="team-admin">
<div class="center-block checkbox text-center">
<input type="checkbox" {% if team.admin %}checked{% endif %}>
</div>
</td>
<td class="team-verified">
<div class="center-block checkbox text-center">
<input type="checkbox" {% if team.verified %}checked{% endif %}>
</div>
</td>
<td class="text-center"><span>
<i class="fa fa-pencil-square-o"></i>
{% if can_send_mail() %}<i class="fa fa-envelope"></i>{% endif %}
<i class="fa fa-times"></i>
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/admin/teams/{{ page }}">{{ page }}</a>
{% else %}
<b>{{ page }}</b>
{% endif %}
{% endfor %}
{% if curr_page != pages %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
</div>
{% endif %}
</div>
<button id="update-user" type="submit" class="btn btn-theme btn-outlined pull-right">Update</button>
</form>
</div>
</div>
</div>
</div>
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td width="10px" class="text-center"><b>ID</b>
</td>
<td class="text-center"><b>Team</b>
</td>
<td class="text-center"><b>Email</b>
</td>
<td class="text-center"><b>Website</b>
</td>
<td class="text-center"><b>Affiliation</b>
</td>
<td class="text-center"><b>Country</b>
</td>
<td class="text-center"><b>Admin</b>
</td>
<td class="text-center"><b>Verified</b>
</td>
<td class="text-center"><b>Settings</b>
</td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr name="{{ team.id }}">
<td class="team-id" value="{{ team.id }}">{{ team.id }}</td>
<td class="team-name" value="{{ team.name }}"><a href="{{ request.script_root }}/admin/team/{{ team.id }}">{{ team.name | truncate(32) }}</a>
</td>
<td class="team-email">{{ team.email | truncate(32) }}</td>
<td class="team-website">{% if team.website and (team.website.startswith('http://') or team.website.startswith('https://')) %}<a href="{{ team.website }}">{{ team.website | truncate(32) }}</a>{% endif %}
</td>
<td class="team-affiliation" value="{{ team.affiliation if team.affiliation is not none }}"><span>{% if team.affiliation %}{{ team.affiliation | truncate(20) }}{% endif %}</span>
</td>
<td class="team-country" value="{{ team.country if team.country is not none }}"><span>{% if team.country %}{{ team.country }}{% endif %}</span>
</td>
<td class="team-admin">
<div class="center-block checkbox text-center">
<input type="checkbox" {% if team.admin %}checked{% endif %}>
</div>
</td>
<td class="team-verified">
<div class="center-block checkbox text-center">
<input type="checkbox" {% if team.verified %}checked{% endif %}>
</div>
</td>
<td class="text-center"><span>
<i class="fa fa-pencil-square-o" data-toggle="tooltip" data-placement="top" title="Modify {{ team.name }}"></i>
{% if can_send_mail() %}<i class="fa fa-envelope"></i>{% endif %}
<i class="fa fa-times" data-toggle="tooltip" data-placement="top" title="Delete {{ team.name }}"></i>
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/admin/teams/{{ page }}">{{ page }}</a>
{% else %}
<b>{{ page }}</b>
{% endif %}
{% endfor %}
{% if curr_page != pages %}<a href="{{ request.script_root }}/admin/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script>
function load_update_modal(id, name, email, website, affiliation, country){
var modal_form = $('#user form');
var modal_form = $('#user form');
modal_form.find('input[name=name]').val(name)
modal_form.find('input[name=id]').val(id)
modal_form.find('input[name=email]').val(email)
modal_form.find('input[name=website]').val(website)
modal_form.find('input[name=affiliation]').val(affiliation)
modal_form.find('input[name=country]').val(country)
$('#user form').attr('action', '{{ request.script_root }}/admin/team/'+id)
$('#user').modal("show");
modal_form.find('input[name=name]').val(name)
modal_form.find('input[name=id]').val(id)
modal_form.find('input[name=email]').val(email)
modal_form.find('input[name=website]').val(website)
modal_form.find('input[name=affiliation]').val(affiliation)
modal_form.find('input[name=country]').val(country)
$('#user form').attr('action', '{{ request.script_root }}/admin/team/'+id)
$('#user').modal("show");
}
$('#update-user').click(function(e){
e.preventDefault();
var id = $('#user input[name="id"]').val()
var user_data = $('#user form').serializeArray()
$.post($('#user form').attr('action'), $('#user form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
for (var i = 0; i < data['data'].length; i++) {
if (data['data'][i] == 'success'){
var row = $('tr[name='+id+']')
console.log($.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'])
console.log(row.find('.team-name > a'))
row.find('.team-name > a').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] );
var new_email = $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'];
if (new_email){
row.find('.team-email').text( new_email );
}
row.find('.team-website > a').empty()
var website = $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value']
row.find('.team-website').append($('<a>').attr('href', website).text(website));
e.preventDefault();
var id = $('#user input[name="id"]').val()
var user_data = $('#user form').serializeArray()
$.post($('#user form').attr('action'), $('#user form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
for (var i = 0; i < data['data'].length; i++) {
if (data['data'][i] == 'success'){
var row = $('tr[name='+id+']')
console.log($.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'])
console.log(row.find('.team-name > a'))
row.find('.team-name > a').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] );
var new_email = $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'];
if (new_email){
row.find('.team-email').text( new_email );
}
row.find('.team-website > a').empty()
var website = $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value']
row.find('.team-website').append($('<a>').attr('href', website).text(website));
row.find('.team-affiliation').text( $.grep(user_data, function(e){ return e.name == 'affiliation'; })[0]['value'] );
row.find('.team-country').text( $.grep(user_data, function(e){ return e.name == 'country'; })[0]['value'] );
$('#user').modal('hide');
}
else{
$('#results').append($('p').text( data['data'][i] ))
}
};
})
row.find('.team-affiliation').text( $.grep(user_data, function(e){ return e.name == 'affiliation'; })[0]['value'] );
row.find('.team-country').text( $.grep(user_data, function(e){ return e.name == 'country'; })[0]['value'] );
$('#user').modal('hide');
}
else{
$('#results').append($('p').text( data['data'][i] ))
}
};
})
});
$('.team-admin input').on('change', function(){
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var admin = $(this).prop('checked');
var nonce = $('#nonce').val();
console.log(admin);
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var admin = $(this).prop('checked');
var nonce = $('#nonce').val();
console.log(admin);
$.post('{{ request.script_root }}/admin/team/'+id, {'admin':admin, 'nonce':nonce});
$.post('{{ request.script_root }}/admin/team/'+id, {'admin':admin, 'nonce':nonce});
});
$('.team-verified input').on('change', function () {
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var verified = $(this).prop('checked');
var nonce = $('#nonce').val();
console.log(verified);
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var verified = $(this).prop('checked');
var nonce = $('#nonce').val();
console.log(verified);
$.post('{{ request.script_root }}/admin/team/' + id, {'verified': verified, 'nonce': nonce});
$.post('{{ request.script_root }}/admin/team/' + id, {'verified': verified, 'nonce': nonce});
})
$('#send-user-email').click(function(e){
e.preventDefault();
var id = $('#email-user input[name="id"]').val();
var email_data = $('#email-user form').serializeArray();
$.post($('#email-user form').attr('action'), $('#email-user form').serialize(), function(data){
if (data == "1"){
$('#email-user').modal('hide');
}
else{
$('#email-user-errors').append("<b>Failed to send email</b>");
}
});
e.preventDefault();
var id = $('#email-user input[name="id"]').val();
var email_data = $('#email-user form').serializeArray();
$.post($('#email-user form').attr('action'), $('#email-user form').serialize(), function(data){
if (data == "1"){
$('#email-user').modal('hide');
}
else{
$('#email-user-errors').append("<b>Failed to send email</b>");
}
});
});
$('#delete-user').click(function(e){
e.preventDefault();
var id = $('#confirm input[name="id"]').val()
var user_data = $('#confirm form').serializeArray()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
e.preventDefault();
var id = $('#confirm input[name="id"]').val()
var user_data = $('#confirm form').serializeArray()
$.post($('#confirm form').attr('action'), $('#confirm form').serialize(), function(data){
var data = $.parseJSON(JSON.stringify(data))
if (data == "1"){
location.reload()
}
})
});
$('.fa-pencil-square-o').click(function(){
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').attr('value') || '';
var name = elem.find('.team-name').attr('value') || '';
var email = elem.find('.team-email').attr('value') || '';
var website = elem.find('.team-website > a').attr('href') || '';
var affiliation = elem.find('.team-affiliation').attr('value') || '';
var country = elem.find('.team-country').attr('value') || '';
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').attr('value') || '';
var name = elem.find('.team-name').attr('value') || '';
var email = elem.find('.team-email').attr('value') || '';
var website = elem.find('.team-website > a').attr('href') || '';
var affiliation = elem.find('.team-affiliation').attr('value') || '';
var country = elem.find('.team-country').attr('value') || '';
load_update_modal(id, name, email, website, affiliation, country);
load_update_modal(id, name, email, website, affiliation, country);
});
function load_confirm_modal(id, name){
var modal = $('#confirm')
modal.find('input[name=id]').val(id)
modal.find('#confirm-team-name').text(name)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/delete');
$('#confirm').modal();
var modal = $('#confirm')
modal.find('input[name=id]').val(id)
modal.find('#confirm-team-name').text(name)
$('#confirm form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/delete');
$('#confirm').modal();
}
$('.fa-times').click(function(){
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var name = elem.find('.team-name').text().trim();
load_confirm_modal(id, name)
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
var name = elem.find('.team-name').text().trim();
load_confirm_modal(id, name)
});
function load_email_modal(id){
var modal = $('#email-user')
modal.find('textarea').val("")
modal.find('input[name=id]').val(id)
$('#email-user-errors').empty()
$('#email-user form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/mail');
$('#email-user').modal();
var modal = $('#email-user')
modal.find('textarea').val("")
modal.find('input[name=id]').val(id)
$('#email-user-errors').empty()
$('#email-user form').attr('action', '{{ request.script_root }}/admin/team/'+id+'/mail');
$('#email-user').modal();
}
$('.fa-envelope').click(function(){
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
load_email_modal(id);
var elem = $(this).parent().parent().parent();
var id = elem.find('.team-id').text().trim();
load_email_modal(id);
});
</script>
{% endblock %}

View File

@ -1,78 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ ctf_name() }}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/{{ ctf_theme() }}/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/{{ ctf_theme() }}/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/font-awesome/css/font-awesome.min.css" />
<link href='{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/style.css">
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/user.css">
{% block stylesheets %}{% endblock %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/original/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
<title>{{ ctf_name() }}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="{{ request.script_root }}/static/{{ ctf_theme() }}/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="{{ request.script_root }}/static/{{ ctf_theme() }}/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/bootstrap.min.css">
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/font-awesome/css/font-awesome.min.css" />
<link href='{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/lato.css' rel='stylesheet' type='text/css'>
<link href='{{ request.script_root }}/static/{{ ctf_theme() }}/css/vendor/raleway.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{{ request.script_root }}/static/{{ ctf_theme() }}/css/style.css">
<link rel="stylesheet" type="text/css" href="{{ request.script_root }}/static/user.css">
{% block stylesheets %}{% endblock %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/moment.min.js"></script>
<script src="{{ request.script_root }}/static/original/js/vendor/handlebars.min.js"></script>
<script type="text/javascript">
var script_root = "{{ request.script_root }}";
</script>
</head>
<body>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">{{ ctf_name() }}</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav">
{% for page in pages() %}
<li><a href="{{ request.script_root }}/{{ page.route }}">{{ page.route|title }}</a></li>
{% endfor %}
<li><a href="{{ request.script_root }}/teams">Teams</a></li>
{% if not hide_scores() %}
<li><a href="{{ request.script_root }}/scoreboard">Scoreboard</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/challenges">Challenges</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{% if username is defined %}
{% if admin %}
<li><a href="{{ request.script_root }}/admin">Admin</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/team/{{ id }}">Team</a></li>
<li><a href="{{ request.script_root }}/profile">Profile</a></li>
<li><a href="{{ request.script_root }}/logout">Logout</a></li>
{% else %}
{% if can_register() %}
<li><a href="{{ request.script_root }}/register">Register</a></li>
<li><a style="padding-left:0px;padding-right:0px;">|</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/login">Login</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
<div class="body-container">
<div class="navbar navbar-inverse home">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" data-target=".navbar-collapse" data-toggle="collapse" type="button">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="{{ request.script_root }}/" class="navbar-brand">{{ ctf_name() }}</a>
</div>
<div class="navbar-collapse collapse" aria-expanded="false" style="height: 0px">
<ul class="nav navbar-nav">
{% for page in pages() %}
<li><a href="{{ request.script_root }}/{{ page.route }}">{{ page.route|title }}</a></li>
{% endfor %}
<li><a href="{{ request.script_root }}/teams">Teams</a></li>
{% if not hide_scores() %}
<li><a href="{{ request.script_root }}/scoreboard">Scoreboard</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/challenges">Challenges</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
{% if username is defined %}
{% if admin %}
<li><a href="{{ request.script_root }}/admin">Admin</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/team/{{ id }}">Team</a></li>
<li><a href="{{ request.script_root }}/profile">Profile</a></li>
<li><a href="{{ request.script_root }}/logout">Logout</a></li>
{% else %}
{% if can_register() %}
<li><a href="{{ request.script_root }}/register">Register</a></li>
<li><a style="padding-left:0px;padding-right:0px;">|</a></li>
{% endif %}
<li><a href="{{ request.script_root }}/login">Login</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
{% block content %}
{% endblock %}
{% block content %}
{% endblock %}
<div class="navbar navbar-bottom footer">
<p class="text-muted text-center"><a style="text-decoration:none;" href="https://ctfd.io"><sub>Powered by CTFd</sub></p>
</div>
</div>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/bootstrap.min.js"></script>
{% block scripts %}
{% endblock %}
<div class="navbar navbar-bottom footer">
<p class="text-muted text-center"><a style="text-decoration:none;" href="https://ctfd.io"><sub>Powered by CTFd</sub></p>
</div>
</div>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/jquery.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/marked.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/bootstrap.min.js"></script>
{% block scripts %}
{% endblock %}
</body>
</html>

View File

@ -2,80 +2,80 @@
{% block stylesheets %}
<style>
.hide-text { text-overflow: ellipsis; overflow: hidden; }
.dialog-inner {padding-bottom: 30px;}
.alert {display: none}
.category-header {text-align: center}
.challenge-wrapper {padding: 5px;}
.challenge-button {width: 100%; height:100px;}
.submit-row {padding-top: 0px; padding-right: 0px; padding-left: 0px;}
.disabled-button {background-color: #EEEEEE}
.hide-text { text-overflow: ellipsis; overflow: hidden; }
.dialog-inner {padding-bottom: 30px;}
.alert {display: none}
.category-header {text-align: center}
.challenge-wrapper {padding: 5px;}
.challenge-button {width: 100%; height:100px;}
.submit-row {padding-top: 0px; padding-right: 0px; padding-left: 0px;}
.disabled-button {background-color: #EEEEEE}
.file-button {text-decoration: none; color: #fff;}
.file-button:hover {text-decoration: none; color: #fff;}
.file-wrapper {padding: 10px; transition: all 0.5s ease; cursor: pointer; color: #fff; width: 100%; text-overflow: ellipsis; overflow: hidden;}
.file-button {cursor: pointer;}
.file-button-wrapper {padding: 0px 10px;}
.file-button {text-decoration: none; color: #fff;}
.file-button:hover {text-decoration: none; color: #fff;}
.file-wrapper {padding: 10px; transition: all 0.5s ease; cursor: pointer; color: #fff; width: 100%; text-overflow: ellipsis; overflow: hidden;}
.file-button {cursor: pointer;}
.file-button-wrapper {padding: 0px 10px;}
.close-text {color: #ccc;position: relative;top: -25px;right: -15px;cursor: pointer;}
.chal-desc {padding-left: 30px; padding-right: 30px;}
.key-submit {padding-top: 14px; padding-right: 10px;}
.notification-row {padding-left: 10px;padding-right: 10px;}
.input {padding-right: 5px;}
.input-field:focus + .input-field,
.input--filled .input-field {
border-color: rgb(238, 238, 238);
}
.input-field:focus + .input-field,
.input--filled .correct {
border-color: rgb(223, 240, 216);
}
.input-field:focus + .input-field,
.input--filled .wrong {
border-color: rgb(255, 190, 190);
}
.close-text {color: #ccc;position: relative;top: -25px;right: -15px;cursor: pointer;}
.chal-desc {padding-left: 30px; padding-right: 30px;}
.key-submit {padding-top: 14px; padding-right: 10px;}
.notification-row {padding-left: 10px;padding-right: 10px;}
.input {padding-right: 5px;}
.input-field:focus + .input-field,
.input--filled .input-field {
border-color: rgb(238, 238, 238);
}
.input-field:focus + .input-field,
.input--filled .correct {
border-color: rgb(223, 240, 216);
}
.input-field:focus + .input-field,
.input--filled .wrong {
border-color: rgb(255, 190, 190);
}
.input-field:focus + .input-field,
.input--filled .too-fast {
border-color: rgb(252, 248, 227);
}
a, button {
color: #74716D;
text-decoration: none;
outline: none;
}
.input-field:focus + .input-field,
.input--filled .too-fast {
border-color: rgb(252, 248, 227);
}
a, button {
color: #74716D;
text-decoration: none;
outline: none;
}
a:hover, a:focus {
color: #c94e50;
outline: none;
}
a:hover, a:focus {
color: #c94e50;
outline: none;
}
button {
padding: 1em 2em;
outline: none;
font-weight: 600;
border: none;
color: #fff;
background: #c94e50;
}
button {
padding: 1em 2em;
outline: none;
font-weight: 600;
border: none;
color: #fff;
background: #c94e50;
}
.content {
max-width: 1000px;
padding: 2em;
margin: 0 auto;
text-align: center;
}
.content {
max-width: 1000px;
padding: 2em;
margin: 0 auto;
text-align: center;
}
.button-wrap {
padding: 2.5em 0 0;
font-size: 1.25em;
}
.button-wrap {
padding: 2.5em 0 0;
font-size: 1.25em;
}
button.trigger {
background: #c94e50;
color: #fff;
border: none;
}
button.trigger {
background: #c94e50;
color: #fff;
border: none;
}
</style>
{% endblock %}
@ -83,37 +83,37 @@
{% if errors %}
<div class="container main-container">
<div id='errors' class="row">
<div id='errors' class="row">
{% for error in errors %}
<h1>{{ error }}</h1>
<h1>{{ error }}</h1>
{% endfor %}
</div>
</div>
</div>
{% else %}
<div class="jumbotron home">
<div class="container">
<h1>Challenges</h1>
</div>
<div class="container">
<h1>Challenges</h1>
</div>
</div>
<div class="container main-container">
<div id='challenges-board' class="row">
</div>
<div id='challenges-board' class="row">
</div>
</div>
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
<div class="modal fade" id="hint-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3>Hint</h3>
</div>
<div class="modal-body" id="hint-modal-body">
</div>
</div>
</div>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3>Hint</h3>
</div>
<div class="modal-body" id="hint-modal-body">
</div>
</div>
</div>
</div>
<div class="modal fade" id="chal-window" tabindex="-1" role="dialog">
@ -122,8 +122,8 @@
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/multi-modal.js"></script>
{% if not errors %}<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/chalboard.js"></script>{% endif %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/multi-modal.js"></script>
{% if not errors %}<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/chalboard.js"></script>{% endif %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -1,49 +1,49 @@
{% extends "base.html" %}
{% block stylesheets %}
<style>
#login-container {
padding-left: 60px;
padding-right: 60px;
}
<style>
#login-container {
padding-left: 60px;
padding-right: 60px;
}
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
{% endblock %}
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Confirm</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
</div>
{% endfor %}
<h3 class="text-center">
We've sent a confirmation email to {{ team.email }}
</h3>
<div class="jumbotron home">
<div class="container">
<h1>Confirm</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
</div>
{% endfor %}
<h3 class="text-center">
We've sent a confirmation email to {{ team.email }}
</h3>
<h3 class="text-center">
Please click the link in that email to confirm your account and access the rest of the CTF.
</h3>
</div>
</div>
</div>
<h3 class="text-center">
Please click the link in that email to confirm your account and access the rest of the CTF.
</h3>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -3,9 +3,9 @@
{% block content %}
<div class="row">
<h1 class="text-center">403</h1>
<h2 class="text-center">An authorization error has occured</h2>
<h2 class="text-center">Please try again</h2>
<h1 class="text-center">403</h1>
<h2 class="text-center">An authorization error has occured</h2>
<h2 class="text-center">Please try again</h2>
</div>

View File

@ -3,9 +3,9 @@
{% block content %}
<div class="row">
<h1 class="text-center">404</h1>
<h2 class="text-center">Whoops, looks like we can't find that.</h2>
<h2 class="text-center">Sorry about that</h2>
<h1 class="text-center">404</h1>
<h2 class="text-center">Whoops, looks like we can't find that.</h2>
<h2 class="text-center">Sorry about that</h2>
</div>

View File

@ -3,8 +3,8 @@
{% block content %}
<div class="row">
<h1 class="text-center">500</h1>
<h2 class="text-center">An Internal Server Error has occured</h2>
<h1 class="text-center">500</h1>
<h2 class="text-center">An Internal Server Error has occured</h2>
</div>

View File

@ -3,8 +3,8 @@
{% block content %}
<div class="row">
<h1 class="text-center">502</h1>
<h2 class="text-center">That action isn't allowed</h2>
<h1 class="text-center">502</h1>
<h2 class="text-center">That action isn't allowed</h2>
</div>

View File

@ -1,72 +1,72 @@
{% extends "base.html" %}
{% block stylesheets %}
<style>
#login-container {
padding-left: 60px;
padding-right: 60px;
}
<style>
#login-container {
padding-left: 60px;
padding-right: 60px;
}
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
.done-row {
padding-top: 15px;
margin: 0px;
}
</style>
{% endblock %}
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Login</h1>
</div>
<div class="container">
<h1>Login</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" />
<label class="input-label" for="name-input">
<span class="label-content">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6" style="padding-left:0px">
<a class="pull-left align-text-to-button" href="{{ request.script_root }}/reset_password">Forgot your password?</a>
</div>
<div class="col-md-6">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" />
<label class="input-label" for="name-input">
<span class="label-content">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6" style="padding-left:0px">
<a class="pull-left align-text-to-button" href="{{ request.script_root }}/reset_password">Forgot your password?</a>
</div>
<div class="col-md-6">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block content %}
<div class="container main-container">
{{ content | safe }}
</div>
<div class="container main-container">
{{ content | safe }}
</div>
{% endblock %}

View File

@ -1,140 +1,140 @@
{% extends "base.html" %}
{% block stylesheets %}
<style>
hr {
margin-top: 0px;
padding-bottom: 10px;
}
.row {
margin-bottom: 10px;
}
</style>
<style>
hr {
margin-top: 0px;
padding-bottom: 10px;
}
.row {
margin-bottom: 10px;
}
</style>
{% endblock %}
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Profile</h1>
</div>
<div class="container">
<h1>Profile</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% if success %}
<div class="alert alert-success alert-dismissable submit-row" role="alert">
<strong>Success!</strong>
Your profile has been updated
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% else %}
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
{% endif %}
{% if confirm_email %}
<div class="alert alert-info alert-dismissable submit-row" role="alert">
Your email address isn't confirmed!
Please check your email to confirm your email address.
<br>
<br>
To have the confirmation email resent please <a href="{{ request.script_root }}/confirm">click
here.</a>
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
</div>
{% endif %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" value="{{name}}"/>
<label class="input-label" for="name-input">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="email-input" value="{{email}}"/>
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="confirm" id="confirm-input" />
<label class="input-label" for="confirm-input">
<span class="label-content" data-content="Password">Current Password</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="New Password">New Password</span>
</label>
</span>
</div>
</div>
<hr />
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="affiliation" id="affiliation-input" value="{% if affiliation %}{{affiliation}}{% endif %}" />
<label class="input-label" for="affiliation-input">
<span class="label-content" data-content="Affiliation">Affiliation</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="website" id="website-input" value="{% if website %}{{website}}{% endif %}" />
<label class="input-label" for="website-input">
<span class="label-content" data-content="Website">Website</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="country" id="country-input" value="{% if country %}{{country}}{% endif %}" />
<label class="input-label" for="country-input">
<span class="label-content" data-content="Country">Country</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="submit-row">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-primary btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% if success %}
<div class="alert alert-success alert-dismissable submit-row" role="alert">
<strong>Success!</strong>
Your profile has been updated
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% else %}
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
{% endif %}
{% if confirm_email %}
<div class="alert alert-info alert-dismissable submit-row" role="alert">
Your email address isn't confirmed!
Please check your email to confirm your email address.
<br>
<br>
To have the confirmation email resent please <a href="{{ request.script_root }}/confirm">click
here.</a>
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
</div>
{% endif %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="name-input" value="{{name}}"/>
<label class="input-label" for="name-input">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="email-input" value="{{email}}"/>
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="confirm" id="confirm-input" />
<label class="input-label" for="confirm-input">
<span class="label-content" data-content="Password">Current Password</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="New Password">New Password</span>
</label>
</span>
</div>
</div>
<hr />
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="affiliation" id="affiliation-input" value="{% if affiliation %}{{affiliation}}{% endif %}" />
<label class="input-label" for="affiliation-input">
<span class="label-content" data-content="Affiliation">Affiliation</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="website" id="website-input" value="{% if website %}{{website}}{% endif %}" />
<label class="input-label" for="website-input">
<span class="label-content" data-content="Website">Website</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="country" id="country-input" value="{% if country %}{{country}}{% endif %}" />
<label class="input-label" for="country-input">
<span class="label-content" data-content="Country">Country</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="submit-row">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-primary btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -5,60 +5,60 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Register</h1>
</div>
<div class="container">
<h1>Register</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="name" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Team Name">Team Name</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Password">Password</span>
</label>
</span>
</div>
</div>
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -5,55 +5,55 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Reset Password</h1>
</div>
<div class="container">
<h1>Reset Password</h1>
</div>
</div>
<div class="container main-container">
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-info alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input name='nonce' type='hidden' value="{{ nonce }}">
{% if mode %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</div>
</div>
{% else %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
{% endif %}
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div id="login-container" class="col-md-6 col-md-offset-3">
{% for error in errors %}
<div class="alert alert-info alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input name='nonce' type='hidden' value="{{ nonce }}">
{% if mode %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Password</span>
</label>
</div>
</div>
{% else %}
<div class="row">
<div class="col-md-12">
<span class="input">
<input class="input-field" type="text" name="email" id="input-10" />
<label class="input-label" for="input-10">
<span class="label-content" data-content="Email">Email</span>
</label>
</span>
</div>
</div>
{% endif %}
<div class="done-row row">
<div class="col-md-6 col-md-offset-6" style="margin-top:10px">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined pull-right">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -2,55 +2,55 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Scoreboard</h1>
</div>
<div class="container">
<h1>Scoreboard</h1>
</div>
</div>
<div class="container main-container">
{% if errors %}
<div class="container main-container">
<div id='errors' class="row">
{% for error in errors %}
<h1>{{ error }}</h1>
{% endfor %}
</div>
</div>
{% else %}
{% if errors %}
<div class="container main-container">
<div id='errors' class="row">
{% for error in errors %}
<h1>{{ error }}</h1>
{% endfor %}
</div>
</div>
{% else %}
{% if score_frozen %}
<div class="container main-container">
<div class="row">
<h1>Scoreboard has been frozen.</h1>
</div>
</div>
{% endif %}
{% if score_frozen %}
<div class="container main-container">
<div class="row">
<h1>Scoreboard has been frozen.</h1>
</div>
</div>
{% endif %}
<div id="score-graph"></div>
<br>
<div id="score-graph"></div>
<br>
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b>
</td>
<td><b>Team</b>
</td>
<td><b>Score</b>
</td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr><td>{{ loop.index }}</td><td><a href="{{ request.script_root }}/team/{{ team.teamid }}">{{ team.name }}</a></td><td>{{ team.score }}</td></tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<table id="scoreboard" class="table table-striped">
<thead>
<tr>
<td width="10px"><b>Place</b>
</td>
<td><b>Team</b>
</td>
<td><b>Score</b>
</td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr><td>{{ loop.index }}</td><td><a href="{{ request.script_root }}/team/{{ team.teamid }}">{{ team.name }}</a></td><td>{{ team.score }}</td></tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/scoreboard.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/scoreboard.js"></script>
{% endblock %}

View File

@ -5,58 +5,58 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Setup</h1>
</div>
<div class="container">
<h1>Setup</h1>
</div>
</div>
<div class="container main-container">
<div id="login-container" class="col-md-6 col-md-offset-3">
<h2 class="text-center">CTF Settings</h2>
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input type="hidden" name="nonce" value="{{nonce}}"> {# This nonce is implemented specially in the route itself #}
<span class="input">
<input class="input-field" type="text" name="ctf_name" id="ctf_name-input"/>
<label class="input-label" for="ctf_name-input">
<span class="label-content" data-content="CTF Name">CTF Name</span>
</label>
</span>
<span class="input">
<input class="input-field" type="text" name="name" id="username-input" />
<label class="input-label" for="username-input">
<span class="label-content" data-content="Username">Admin Username</span>
</label>
</span>
<span class="input">
<input class="input-field" type="email" name="email" id="email-input" />
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Admin Email</span>
</label>
</span>
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Admin Password</span>
</label>
</span>
<br/>
<div class="submit-row text-center">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined">Submit</button>
</div>
</form>
</div>
<div id="login-container" class="col-md-6 col-md-offset-3">
<h2 class="text-center">CTF Settings</h2>
{% for error in errors %}
<div class="submit-row">
<div class="alert alert-danger alert-dismissable" role="alert">
<span class="sr-only">Error:</span>
{{ error }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
</div>
{% endfor %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input type="hidden" name="nonce" value="{{nonce}}"> {# This nonce is implemented specially in the route itself #}
<span class="input">
<input class="input-field" type="text" name="ctf_name" id="ctf_name-input"/>
<label class="input-label" for="ctf_name-input">
<span class="label-content" data-content="CTF Name">CTF Name</span>
</label>
</span>
<span class="input">
<input class="input-field" type="text" name="name" id="username-input" />
<label class="input-label" for="username-input">
<span class="label-content" data-content="Username">Admin Username</span>
</label>
</span>
<span class="input">
<input class="input-field" type="email" name="email" id="email-input" />
<label class="input-label" for="email-input">
<span class="label-content" data-content="Email">Admin Email</span>
</label>
</span>
<span class="input">
<input class="input-field" type="password" name="password" id="password-input" />
<label class="input-label" for="password-input">
<span class="label-content" data-content="Password">Admin Password</span>
</label>
</span>
<br/>
<div class="submit-row text-center">
<button type="submit" id="submit" tabindex="5" class="btn btn-md btn-theme btn-outlined">Submit</button>
</div>
</form>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/style.js"></script>
{% endblock %}

View File

@ -5,99 +5,99 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1 id="team-id">{{ team.name }}</h1>
</div>
<div class="container">
<h1 id="team-id">{{ team.name }}</h1>
</div>
</div>
<div class="container">
{% if errors %}
<div id='errors' class="row">
{% for error in errors %}
<h1>{{ error }}</h1>
{% endfor %}
</div>
{% else %}
{% if errors %}
<div id='errors' class="row">
{% for error in errors %}
<h1>{{ error }}</h1>
{% endfor %}
</div>
{% else %}
{% if score_frozen %}
<div class="container main-container">
<div class="row">
<h1>Scoreboard has been frozen.</h1>
</div>
</div>
{% endif %}
{% if score_frozen %}
<div class="container main-container">
<div class="row">
<h1>Scoreboard has been frozen.</h1>
</div>
</div>
{% endif %}
<div class="team-info">
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
</div>
<div class="team-info">
<h2 id="team-place" class="text-center">
{%if place %}
{{ place }} <small>place</small>
{% endif %}
</h2>
<h2 id="team-score" class="text-center">
{%if score %}
{{ score }} <small>points</small>
{% endif %}
</h2>
</div>
<br>
<br>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<br>
<div id="score-graph"></div>
<div id="keys-pie-graph"></div>
<div id="categories-pie-graph"></div>
<br>
<div id="score-graph"></div>
<div class="clearfix"></div>
<div class="clearfix"></div>
{% if awards %}
<div class="row">
<h3>Awards</h3>
{% for award in awards %}
{% set count= awards|length - loop.index %}
{% set rem = awards|length % 4 %}
{% if count < rem %}
<div class="col-xs-{{ (12//rem)|string }} col-md-{{ (12//rem)|string }}">
{% else %}
<div class="col-xs-3 col-md-3">
{% endif %}
<p class="text-center"><strong>{{ award.name }}</strong></p>
{% if award.category %}<p class="text-center">{{ award.category }}</p>{% endif %}
<p class="text-center">{{ award.description }}</p>
<p class="text-center">{{ award.value }}</p>
</div>
{% endfor %}
</div>
{% if awards %}
<div class="row">
<h3>Awards</h3>
{% for award in awards %}
{% set count= awards|length - loop.index %}
{% set rem = awards|length % 4 %}
{% if count < rem %}
<div class="col-xs-{{ (12//rem)|string }} col-md-{{ (12//rem)|string }}">
{% else %}
<div class="col-xs-3 col-md-3">
{% endif %}
<p class="text-center"><strong>{{ award.name }}</strong></p>
{% if award.category %}<p class="text-center">{{ award.category }}</p>{% endif %}
<p class="text-center">{{ award.description }}</p>
<p class="text-center">{{ award.value }}</p>
</div>
{% endfor %}
</div>
<br>
{% endif %}
<br>
{% endif %}
<div class="row">
<h3>Solves</h3>
<table class="table table-striped">
<thead>
<tr>
<td><b>Challenge</b></td>
<td class="hidden-xs"><b>Category</b></td>
<td><b>Value</b></td>
<td><b>Time</b></td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr>
<td><a href="{{ request.script_root }}/challenges#{{ solve.chal.name }}">{{ solve.chal.name }}</a></td>
<td class="hidden-xs">{{ solve.chal.category }}</td><td>{{ solve.chal.value }}</td>
<td class="solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<div class="row">
<h3>Solves</h3>
<table class="table table-striped">
<thead>
<tr>
<td><b>Challenge</b></td>
<td class="hidden-xs"><b>Category</b></td>
<td><b>Value</b></td>
<td><b>Time</b></td>
</tr>
</thead>
<tbody>
{% for solve in solves %}
<tr>
<td><a href="{{ request.script_root }}/challenges#{{ solve.chal.name }}">{{ solve.chal.name }}</a></td>
<td class="hidden-xs">{{ solve.chal.category }}</td><td>{{ solve.chal.value }}</td>
<td class="solve-time"><script>document.write( moment({{ solve.date|unix_time_millis }}).local().format('MMMM Do, h:mm:ss A'))</script></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/team.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/vendor/plotly.min.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/utils.js"></script>
<script src="{{ request.script_root }}/static/{{ ctf_theme() }}/js/team.js"></script>
{% endblock %}

View File

@ -5,52 +5,52 @@
{% block content %}
<div class="jumbotron home">
<div class="container">
<h1>Teams</h1>
</div>
<div class="container">
<h1>Teams</h1>
</div>
</div>
<div class="container main-container">
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td><b>Team</b></td>
<td><b>Website</b></td>
<td><b>Affiliation</b></td>
<td class="hidden-xs"><b>Country</b></td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td>
{% if hide_scores() %}
<span>{{ team.name }}</span>
{% else %}
<a href="{{ request.script_root }}/team/{{ team.id }}">{{ team.name }}</a>
{% endif %}
</td>
<td>{% if team.website and (team.website.startswith('http://') or team.website.startswith('https://')) %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td>
<td><span>{% if team.affiliation %}{{ team.affiliation }}{% endif %}</span></td>
<td class="hidden-xs"><span>{% if team.country %}{{ team.country }}{% endif %}</span></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if team_pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, team_pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/teams/{{ page }}">{{ page }}</a>
{% else %}
<b>{{page}}</b>
{% endif %}
{% endfor %}
{% if curr_page != team_pages %}<a href="{{ request.script_root }}/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href="{{ request.script_root }}">
</div>
{% endif %}
<table id="teamsboard" class="table table-striped">
<thead>
<tr>
<td><b>Team</b></td>
<td><b>Website</b></td>
<td><b>Affiliation</b></td>
<td class="hidden-xs"><b>Country</b></td>
</tr>
</thead>
<tbody>
{% for team in teams %}
<tr>
<td>
{% if hide_scores() %}
<span>{{ team.name }}</span>
{% else %}
<a href="{{ request.script_root }}/team/{{ team.id }}">{{ team.name }}</a>
{% endif %}
</td>
<td>{% if team.website and (team.website.startswith('http://') or team.website.startswith('https://')) %}<a href="{{ team.website }}">{{ team.website }}</a>{% endif %}</td>
<td><span>{% if team.affiliation %}{{ team.affiliation }}{% endif %}</span></td>
<td class="hidden-xs"><span>{% if team.country %}{{ team.country }}{% endif %}</span></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if team_pages > 1 %}
<div class="text-center">Page
<br>
{% if curr_page != 1 %}<a href="{{ request.script_root }}/teams/{{ curr_page-1 }}">&lt;&lt;&lt;</a>{% endif %}
{% for page in range(1, team_pages + 1) %}
{% if curr_page != page %}
<a href="{{ request.script_root }}/teams/{{ page }}">{{ page }}</a>
{% else %}
<b>{{page}}</b>
{% endif %}
{% endfor %}
{% if curr_page != team_pages %}<a href="{{ request.script_root }}/teams/{{ curr_page+1 }}">&gt;&gt;&gt;</a>{% endif %}
<a href="{{ request.script_root }}">
</div>
{% endif %}
</div>
{% endblock %}