aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pysite/tables.py2
-rw-r--r--pysite/views/staff/jams/create.py12
-rw-r--r--pysite/views/staff/jams/forms/preamble_edit.py45
-rw-r--r--pysite/views/staff/jams/forms/view.py4
-rw-r--r--templates/main/jams/join.html4
-rw-r--r--templates/staff/jams/forms/preamble_edit.html148
-rw-r--r--templates/staff/jams/forms/view.html1
7 files changed, 215 insertions, 1 deletions
diff --git a/pysite/tables.py b/pysite/tables.py
index e99ca989..a9a0dc88 100644
--- a/pysite/tables.py
+++ b/pysite/tables.py
@@ -60,6 +60,8 @@ TABLES = {
primary_key="number",
keys=sorted([
"number", # int
+ "preamble_rst", # str
+ "preamble_html", # str
"questions" # list[dict[str, str]] {title, type, input_type, options?}
])
),
diff --git a/pysite/views/staff/jams/create.py b/pysite/views/staff/jams/create.py
index e88056c5..ef61cbef 100644
--- a/pysite/views/staff/jams/create.py
+++ b/pysite/views/staff/jams/create.py
@@ -1,3 +1,5 @@
+import datetime
+
from flask import redirect, request, url_for
from werkzeug.exceptions import BadRequest
@@ -35,6 +37,16 @@ class StaffView(RouteView, DBMixin):
data["state"] = "planning"
data["number"] = self.get_next_number()
+ # Convert given datetime strings into actual objects, adding timezones to keep rethinkdb happy
+ date_start = datetime.datetime.strptime(data["date_start"], "%Y-%m-%d %H:%M")
+ date_start = date_start.replace(tzinfo=datetime.timezone.utc)
+
+ date_end = datetime.datetime.strptime(data["date_end"], "%Y-%m-%d %H:%M")
+ date_end = date_end.replace(tzinfo=datetime.timezone.utc)
+
+ data["date_start"] = date_start
+ data["date_end"] = date_end
+
self.db.insert(self.table_name, data)
return redirect(url_for("staff.jams.index"))
diff --git a/pysite/views/staff/jams/forms/preamble_edit.py b/pysite/views/staff/jams/forms/preamble_edit.py
new file mode 100644
index 00000000..c17692d3
--- /dev/null
+++ b/pysite/views/staff/jams/forms/preamble_edit.py
@@ -0,0 +1,45 @@
+import datetime
+
+from flask import redirect, request, url_for
+from werkzeug.exceptions import BadRequest, NotFound
+
+from pysite.base_route import RouteView
+from pysite.constants import ALL_STAFF_ROLES
+from pysite.decorators import csrf, require_roles
+from pysite.mixins import DBMixin
+from pysite.rst import render
+
+
+class StaffView(RouteView, DBMixin):
+ path = "/jams/form/<int:jam>/preamble"
+ name = "jams.forms.preamble.edit"
+
+ table_name = "code_jam_forms"
+ jams_table = "code_jams"
+
+ @require_roles(*ALL_STAFF_ROLES)
+ def get(self, jam):
+ jam_obj = self.db.get(self.jams_table, jam)
+
+ if not jam_obj:
+ return NotFound()
+
+ form_obj = self.db.get(self.table_name, jam)
+ return self.render("staff/jams/forms/preamble_edit.html", jam=jam_obj, form=form_obj)
+
+ @require_roles(*ALL_STAFF_ROLES)
+ @csrf
+ def post(self, jam):
+ jam_obj = self.db.get(self.table_name, jam)
+
+ if not jam_obj:
+ return NotFound()
+
+ form_obj = self.db.get(self.table_name, jam)
+
+ preamble_rst = request.form.get("preamble_rst")
+
+ form_obj["preamble_rst"] = preamble_rst
+ form_obj["preamble_html"] = render(preamble_rst, link_headers=False)["html"]
+
+ return redirect(url_for("staff.jams.forms.view", jam=jam))
diff --git a/pysite/views/staff/jams/forms/view.py b/pysite/views/staff/jams/forms/view.py
index eaa910f2..8d4e16ad 100644
--- a/pysite/views/staff/jams/forms/view.py
+++ b/pysite/views/staff/jams/forms/view.py
@@ -28,7 +28,9 @@ class StaffView(RouteView, DBMixin):
if not form_obj:
form_obj = {
"number": jam,
- "questions": []
+ "questions": [],
+ "preamble_rst": "",
+ "preamble_html": ""
}
self.db.insert(self.forms_table, form_obj)
diff --git a/templates/main/jams/join.html b/templates/main/jams/join.html
index ffa80cb5..8e762ff2 100644
--- a/templates/main/jams/join.html
+++ b/templates/main/jams/join.html
@@ -118,6 +118,10 @@
</p>
<hr class="uk-divider-icon" />
+ {{ form.preamble_html }}
+
+ <hr class="uk-divider-icon" />
+
{% if jam.state != "announced" %}
<p class="uk-alert uk-alert-primary">
Unfortunately, we're not accepting applications for this code jam right now - but we appreciate your
diff --git a/templates/staff/jams/forms/preamble_edit.html b/templates/staff/jams/forms/preamble_edit.html
new file mode 100644
index 00000000..6e3fec0d
--- /dev/null
+++ b/templates/staff/jams/forms/preamble_edit.html
@@ -0,0 +1,148 @@
+{% extends "main/base.html" %}
+{% block title %}Staff | Forms | Edit Preamble{% endblock %}
+{% block og_title %}Staff | Forms | Edit Preamble{% endblock %}
+{% block extra_head %}
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ace.js" type="application/javascript"></script>
+{% endblock %}
+{% block content %}
+ <div class="uk-container uk-container-small uk-section">
+ <h1 class="uk-text-center">Form: Edit Preamble</h1>
+
+ <form action="{{ url_for("staff.jams.forms.preamble.edit", jam=jam.number) }}" method="post" class="uk-form-horizontal">
+ <div>
+ <div class="uk-form-label">
+ <label class="uk-form-label">Preamble (RST)</label>
+ </div>
+
+ <div class="uk-form-controls uk-form-controls-text">
+ <div id="editor" class="uk-textarea" style="resize: vertical; min-height: 15rem;">{{ form.preamble_rst }}</div>
+ </div>
+
+ <input type="hidden" name="preamble_rst" id="preamble_rst" value="{{ form.preamble_rst }}" />
+ </div>
+
+ <input type="hidden" name="csrf_token" id="csrf_token" value="{{ csrf_token() }}"/>
+
+ <div class="uk-align-center uk-text-center">
+ <a id="back" class="uk-button uk-button-default" href="{{ url_for("staff.jams.forms.view", jam=jam.number) }}">
+ <i class="uk-icon fa-fw far fa-arrow-left"></i> &nbsp;Back
+ </a>
+ <button class="uk-button uk-button-secondary" type="button" id="preview">
+ <i class="uk-icon fa-fw far fa-eye"></i> &nbsp;Preview
+ </button>
+ <button id="done" class="uk-button uk-button-primary" type="submit" disabled>
+ <i class="uk-icon fa-fw far fa-check"></i> &nbsp;Done
+ </button>
+ </div>
+ </form>
+ </div>
+
+ <div id="preview-modal" class="uk-flex-top" uk-modal>
+ <div class="uk-modal-dialog">
+ <button class="uk-modal-close-default" type="button" uk-close></button>
+
+ <div class="uk-modal-body">
+ <h2>Form: {{ jam.number }}</h2>
+
+ <div id="preview-div">
+ {{ jam.preamble_html | safe }}
+ </div>
+ </div>
+
+ <div class="uk-modal-footer">
+ <div class="uk-text-center">
+ <button class="uk-button uk-button-default uk-modal-close" type="button" id="state-cancel">
+ <i class="uk-icon fa-fw far fa-arrow-left"></i> &nbsp;Close
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <script type="application/javascript">
+ "use strict";
+
+ let csrf_token = "{{ csrf_token() }}";
+ let modal = UIkit.modal(document.getElementById("preview-modal"));
+ let preview_url = "{{ url_for("staff.render") }}";
+
+ function do_preview(callback) {
+ let oReq = new XMLHttpRequest();
+
+ oReq.addEventListener("load", function() {
+ let response = JSON.parse(this.responseText);
+
+ if (response.error !== undefined) {
+ document.getElementById("done").disabled = true;
+
+ if (response.error_lines !== undefined) {
+ editor.session.setAnnotations(response.error_lines);
+ document.getElementById("preview-div").innerHTML ="<h3>Error - see editor margin</h3>";
+ } else {
+ console.log("Error: " + response.error);
+ document.getElementById("preview-div").innerHTML ="<h3>Error</h3><p>" + response.error + "<p>";
+ }
+ } else {
+ document.getElementById("done").disabled = false;
+ document.getElementById("preview-div").innerHTML = response.data;
+
+ editor.session.setAnnotations([]);
+ }
+
+ if (callback !== undefined) {
+ callback();
+ }
+ });
+
+ let data = editor.getValue();
+
+ if (data.replace("\s", "").length < 1) {
+ document.getElementById("done").disabled = true;
+
+ if (callback !== undefined) {
+ UIkit.notification({
+ "message": "Please enter some text to preview",
+ "status": "danger",
+ "pos": "bottom-center",
+ "timeout": 5000
+ });
+ }
+ return false;
+ }
+
+ oReq.open("POST", preview_url);
+
+ oReq.setRequestHeader("Content-type", "application/json");
+ oReq.setRequestHeader("X-CSRFToken", csrf_token);
+
+ oReq.send(JSON.stringify({"data": editor.getValue()}));
+
+ return false;
+ }
+
+ document.getElementById("preview").onclick = function() {
+ do_preview(function() {
+ modal.show();
+ })
+ };
+
+ let editor = ace.edit("editor");
+ let timer;
+
+ editor.session.setMode("ace/mode/rst");
+ editor.session.setUseWrapMode(true);
+
+ editor.setTheme("ace/theme/iplastic");
+ editor.setShowPrintMargin(false);
+
+ editor.on("input", function() {
+ document.getElementById("done").disabled = true;
+ document.getElementById("preamble_rst").value = editor.getValue();
+
+ if (timer !== undefined) {
+ clearTimeout(timer);
+ }
+ timer = setTimeout(do_preview, 1000);
+ });
+ </script>
+{% endblock %}
diff --git a/templates/staff/jams/forms/view.html b/templates/staff/jams/forms/view.html
index 6d0a86af..46474ae9 100644
--- a/templates/staff/jams/forms/view.html
+++ b/templates/staff/jams/forms/view.html
@@ -10,6 +10,7 @@
<h1>Application Form {{ jam.number }}: {{ jam.title }}</h1>
<a class="uk-button uk-button-default" href="{{ url_for("staff.jams.index") }}"><i class="uk-icon fa-fw far fa-arrow-left"></i> &nbsp;Back</a>
+ <a class="uk-button uk-button-secondary" href="{{ url_for("staff.jams.forms.preamble.edit", jam=jam.number) }}" id="preamble-button"><i class="uk-icon fa-fw far fa-pencil"></i> &nbsp;Edit Preamble</a>
<button class="uk-button uk-button-primary" id="add-button"><i class="uk-icon fa-fw far fa-plus"></i> &nbsp;Add Question</button>
{# <a class="uk-button uk-button-secondary" target="_blank" href="{{ url_for("staff.index") }}"><i class="uk-icon fa-fw far fa-eye"></i> &nbsp;Preview</a> #}