diff options
-rw-r--r-- | pysite/tables.py | 2 | ||||
-rw-r--r-- | pysite/views/staff/jams/create.py | 12 | ||||
-rw-r--r-- | pysite/views/staff/jams/forms/preamble_edit.py | 45 | ||||
-rw-r--r-- | pysite/views/staff/jams/forms/view.py | 4 | ||||
-rw-r--r-- | templates/main/jams/join.html | 4 | ||||
-rw-r--r-- | templates/staff/jams/forms/preamble_edit.html | 148 | ||||
-rw-r--r-- | templates/staff/jams/forms/view.html | 1 |
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> Back + </a> + <button class="uk-button uk-button-secondary" type="button" id="preview"> + <i class="uk-icon fa-fw far fa-eye"></i> Preview + </button> + <button id="done" class="uk-button uk-button-primary" type="submit" disabled> + <i class="uk-icon fa-fw far fa-check"></i> 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> 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> 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> Edit Preamble</a> <button class="uk-button uk-button-primary" id="add-button"><i class="uk-icon fa-fw far fa-plus"></i> 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> Preview</a> #} |