diff --git a/abot.py b/abot.py index 2b842cf..91bcfeb 100644 --- a/abot.py +++ b/abot.py @@ -43,12 +43,14 @@ def preview(key): return render_template('blank.html', message = "Error creating form") if not is_draft(form): return render_template('blank.html', message = "Preview not enabled") - valid_for = time_to_expiry(form) + valid_for = time_to('expires', form) + opens = time_to('opens', form) return render_template( 'preview.html', key = key, form = form, - valid_for = valid_for + valid_for = valid_for, + opens = opens ) @@ -62,14 +64,19 @@ def vote(key, token = None): return render_template('blank.html', message = "Error creating form") if is_draft(form): return render_template('blank.html', message = "Not published") - if is_expired(form): - return render_template('blank.html', message = "Voting has closed") if is_closed_vote(form): if not is_voter(key, token): return render_template('blank.html', message = "Token invalid") if has_voted(key, token): - return render_template('blank.html', message = "Token already used") - valid_for = time_to_expiry(form) + form['can_submit'] = False + form['message'] = 'Token used. Can not submit anymore' + if not is_opened(form): + return render_template('blank.html', message = "Voting is not open yet. Opens at " + time_to('opens', form)) + + if is_expired(form): + form['can_submit'] = False + form['message'] = 'Voting has closed. Can not submit anymore' + valid_for = time_to('expires', form) return render_template( 'vote.html', @@ -98,6 +105,9 @@ def save_vote(): return render_template('blank.html', message = "Token invalid") if has_voted(key, token): return render_template('blank.html', message = "Token already used") + if not is_opened(form): + return render_template('blank.html', message = "Voting is not open yet. Opens at " + time_to('opens', form)) + write_vote(key, token, request.form, form) # using request. tokens = False diff --git a/questions/examples/multi_question.txt b/questions/examples/multi_question.txt index 9ec2896..7d59865 100644 --- a/questions/examples/multi_question.txt +++ b/questions/examples/multi_question.txt @@ -1,6 +1,8 @@ +title: My Vote # expiry format: YYYY-MM-DD HH:MM +z # z is the difference to UTC in HHMM, +0000, -0700, etc.. expires: 2028-12-12 21:20 +0200 +opens: 2010-12-12 21:20 +0200 # if "draft: true" voting is not possible. you can preview the form with address "/preview/example" draft: false diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000..edde4d2 Binary files /dev/null and b/static/favicon.png differ diff --git a/static/hk-grotesk.regular.ttf b/static/hk-grotesk.regular.ttf new file mode 100644 index 0000000..8e48d00 Binary files /dev/null and b/static/hk-grotesk.regular.ttf differ diff --git a/static/style.css b/static/style.css index 1c660d5..b1251dd 100644 --- a/static/style.css +++ b/static/style.css @@ -1,12 +1,28 @@ -body { font-family: sans-serif; background: #eee; } -a, h1, h2 { color: #227b64; } -h1, h2 { font-family: 'Georgia', serif; margin: 0; margin-top: 0.9em; } -h1 { border-bottom: 2px solid #eee; } -h2 { font-size: 1.2em; } -input { margin-top: 0.5em; border: 1px solid gray;} +@font-face { + font-family: HK Grotesk; + src: url('hk-grotesk.regular.ttf'); +} -.page { margin: 2em auto; width: 90%; border: 3px solid #ccc; - padding: 0.8em; background: white; } +body { font-family: 'HK Grotesk', sans-serif; background: #eee; } +a, h1, h2 { color: #227b64; } +h1, h2 { font-family: 'HK Grotesk', sans-serif; margin: 0; margin-top: 0.9em; } +h1 { border-bottom: 2px solid #eee; text-align: center; } +h2 { font-size: 1.2em; } + +input { + margin-top: 0.8em; +} +input[type=submit] { + border: 1px solid #333; + border-radius: 2px; + font-size: 1.0em; + padding: 8px; +} + +.page { + margin: 2em auto; width: 90%; border: 1px solid #ccc; + padding: 0.8em; background: white; +} .index { margin-top: 1em; } @@ -18,7 +34,7 @@ input { margin-top: 0.5em; border: 1px solid gray;} padding-bottom: 0.5em; } .autoformat { - border-bottom: 1px solid gray; + border-bottom: 1px solid #ccc; } .warning { font-size: small; @@ -29,6 +45,13 @@ input { margin-top: 0.5em; border: 1px solid gray;} color: red; margin-top: 1em; margin-bottom: 1em; + width: 100%; + background-color: #eee; + text-align: center; + padding: 8px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } textarea { @@ -72,3 +95,6 @@ textarea { text-align: center; padding: 3px; } +.submit { + text-align: center; +} diff --git a/templates/layout.html b/templates/layout.html index 9182972..70e9495 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -2,8 +2,8 @@ aBot // {{ g.title|safe }} + - diff --git a/templates/preview.html b/templates/preview.html index 4858fed..5f862ba 100644 --- a/templates/preview.html +++ b/templates/preview.html @@ -1,8 +1,12 @@ {% extends "layout.html" %} {% block body %} -
+
Preview for: {{ key|safe }}
- Expires: {{ valid_for }}
+ Voting ends at: {{ valid_for }}
+ Voting starts at: {{ opens }}
+ Style (open/closed): {{ form.vote_style }}
+ Show results after voting: {{ form.show_results }}
+ Title: {{ form.title }}
{% include "questions.html" %} diff --git a/templates/vote.html b/templates/vote.html index 0d49060..91e17a1 100644 --- a/templates/vote.html +++ b/templates/vote.html @@ -1,21 +1,33 @@ {% extends "layout.html" %} {% block body %} + {% if not form.can_submit %} +
{{ form.message }}
+ {% endif %} + + {% if valid_for != 'Never' %}
Voting ends at: {{ valid_for }}
+ {% endif %}
{% include "questions.html" %}

-
- {% if form.vote_style == 'closed' %} -

- You can only vote once! -
    -
  • Votes can not be edited later
  • -
  • Empty choices counts as empty, used vote
  • -
-
+ {% if form.can_submit %} +
+ +
+ {% if form.vote_style == 'closed' %} +
+ You can only vote once! +
    +
  • Votes can not be edited later
  • +
  • Empty choices counts as empty, used vote
  • +
+
+ {% endif %} + {% else %} +
{{ form.message }}
{% endif %}

diff --git a/utils.py b/utils.py index 9ebde5c..fca63c3 100644 --- a/utils.py +++ b/utils.py @@ -131,10 +131,15 @@ def is_draft(form): def is_expired(form): if form['expires'] == None: return False - return datetime.now(timezone.utc) > form['expires'] +def is_opened(form): + if form['opens'] == None: + return True + return datetime.now(timezone.utc) > form['opens'] + + def is_key(key, cli_opts = False): key = secure_filename(key) @@ -171,11 +176,14 @@ def is_voter(key, token): def parse_form(key): form = { 'expires': None, + 'opens': None, 'draft': False, 'vote_style': "closed", 'show_results': False, 'questions': [], - 'title': "" + 'title': "", + 'can_submit': True, + 'message': '' } key = secure_filename(key) try: @@ -194,6 +202,9 @@ def parse_form(key): if rowsl.startswith("expires: "): form['expires'] = parse_row_date(row) continue + if rowsl.startswith("opens: "): + form['opens'] = parse_row_date(row) + continue if rowsl.startswith("draft: "): if rowsl == "draft: true": form['draft'] = True @@ -225,7 +236,7 @@ def parse_form(key): 'choices': [], 'multichoices': [], 'index': current_question + 1, - 'name': row.strip().rstrip("_:").rstrip(), + 'name': row.strip().rstrip("_").rstrip(), 'open_question': row.strip().endswith("___"), 'autoformat': not rowsl.startswith("<") }) @@ -237,7 +248,7 @@ def parse_form(key): def parse_row_date(row): - row = row[9:].strip() + row = " ".join(row.split(" ")[1:]).strip() if row.lower() == "none": return None try: @@ -304,12 +315,18 @@ def sort_summary(questions, answers): return questions, sorted_answer_list -def time_to_expiry(form): - if form['expires'] == None: - return "Never" +def time_to(what, form): + if not what in ('expires','opens'): + raise AttributeError("Dont know that attribute") - time_to_go = form['expires'] - datetime.now(timezone.utc) + if form[what] == None: + if what == 'expires': + return "Never" + if what == 'opens': + return "None" + + time_to_go = form[what] - datetime.now(timezone.utc) time_to_go = ".".join(str(time_to_go).split('.')[0:-1])[0:-3] #time_to_go.microseconds = 0 - return "%s (%s to go)"%( form['expires'], time_to_go ) + return "%s (%s to go)"%( form[what], time_to_go )