support for delayed opening. css changes
This commit is contained in:
22
abot.py
22
abot.py
@@ -43,12 +43,14 @@ def preview(key):
|
|||||||
return render_template('blank.html', message = "Error creating form")
|
return render_template('blank.html', message = "Error creating form")
|
||||||
if not is_draft(form):
|
if not is_draft(form):
|
||||||
return render_template('blank.html', message = "Preview not enabled")
|
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(
|
return render_template(
|
||||||
'preview.html',
|
'preview.html',
|
||||||
key = key,
|
key = key,
|
||||||
form = form,
|
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")
|
return render_template('blank.html', message = "Error creating form")
|
||||||
if is_draft(form):
|
if is_draft(form):
|
||||||
return render_template('blank.html', message = "Not published")
|
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 is_closed_vote(form):
|
||||||
if not is_voter(key, token):
|
if not is_voter(key, token):
|
||||||
return render_template('blank.html', message = "Token invalid")
|
return render_template('blank.html', message = "Token invalid")
|
||||||
if has_voted(key, token):
|
if has_voted(key, token):
|
||||||
return render_template('blank.html', message = "Token already used")
|
form['can_submit'] = False
|
||||||
valid_for = time_to_expiry(form)
|
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(
|
return render_template(
|
||||||
'vote.html',
|
'vote.html',
|
||||||
@@ -98,6 +105,9 @@ def save_vote():
|
|||||||
return render_template('blank.html', message = "Token invalid")
|
return render_template('blank.html', message = "Token invalid")
|
||||||
if has_voted(key, token):
|
if has_voted(key, token):
|
||||||
return render_template('blank.html', message = "Token already used")
|
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.
|
write_vote(key, token, request.form, form) # using request.
|
||||||
tokens = False
|
tokens = False
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
title: My Vote
|
||||||
# expiry format: YYYY-MM-DD HH:MM +z
|
# expiry format: YYYY-MM-DD HH:MM +z
|
||||||
# z is the difference to UTC in HHMM, +0000, -0700, etc..
|
# z is the difference to UTC in HHMM, +0000, -0700, etc..
|
||||||
expires: 2028-12-12 21:20 +0200
|
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"
|
# if "draft: true" voting is not possible. you can preview the form with address "/preview/example"
|
||||||
draft: false
|
draft: false
|
||||||
|
|||||||
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
static/hk-grotesk.regular.ttf
Normal file
BIN
static/hk-grotesk.regular.ttf
Normal file
Binary file not shown.
@@ -1,12 +1,28 @@
|
|||||||
body { font-family: sans-serif; background: #eee; }
|
@font-face {
|
||||||
a, h1, h2 { color: #227b64; }
|
font-family: HK Grotesk;
|
||||||
h1, h2 { font-family: 'Georgia', serif; margin: 0; margin-top: 0.9em; }
|
src: url('hk-grotesk.regular.ttf');
|
||||||
h1 { border-bottom: 2px solid #eee; }
|
}
|
||||||
h2 { font-size: 1.2em; }
|
|
||||||
input { margin-top: 0.5em; border: 1px solid gray;}
|
|
||||||
|
|
||||||
.page { margin: 2em auto; width: 90%; border: 3px solid #ccc;
|
body { font-family: 'HK Grotesk', sans-serif; background: #eee; }
|
||||||
padding: 0.8em; background: white; }
|
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 {
|
.index {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
@@ -18,7 +34,7 @@ input { margin-top: 0.5em; border: 1px solid gray;}
|
|||||||
padding-bottom: 0.5em;
|
padding-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
.autoformat {
|
.autoformat {
|
||||||
border-bottom: 1px solid gray;
|
border-bottom: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
.warning {
|
.warning {
|
||||||
font-size: small;
|
font-size: small;
|
||||||
@@ -29,6 +45,13 @@ input { margin-top: 0.5em; border: 1px solid gray;}
|
|||||||
color: red;
|
color: red;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
margin-bottom: 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 {
|
textarea {
|
||||||
@@ -72,3 +95,6 @@ textarea {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
.submit {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>aBot // {{ g.title|safe }}</title>
|
<title>aBot // {{ g.title|safe }}</title>
|
||||||
<meta name="viewport" content="width=440" />
|
<meta name="viewport" content="width=440" />
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='favicon.png') }}">
|
||||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||||
<script src="{{ url_for('static', filename='script.js') }}" type="text/javascript"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div id="preview_header">
|
<div id="preview_header" class=autoformat>
|
||||||
Preview for: {{ key|safe }}<br>
|
Preview for: {{ key|safe }}<br>
|
||||||
Expires: {{ valid_for }}<br>
|
Voting ends at: {{ valid_for }}<br>
|
||||||
|
Voting starts at: {{ opens }}<br>
|
||||||
|
Style (open/closed): {{ form.vote_style }}<br>
|
||||||
|
Show results after voting: {{ form.show_results }}<br>
|
||||||
|
Title: {{ form.title }}<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include "questions.html" %}
|
{% include "questions.html" %}
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
{% if not form.can_submit %}
|
||||||
|
<div class=message>{{ form.message }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if valid_for != 'Never' %}
|
||||||
<div id="vote_header">Voting ends at: {{ valid_for }}</div>
|
<div id="vote_header">Voting ends at: {{ valid_for }}</div>
|
||||||
|
{% endif %}
|
||||||
<form id="vote_form" action="{{ url_for('save_vote') }}" method=post >
|
<form id="vote_form" action="{{ url_for('save_vote') }}" method=post >
|
||||||
<input type=hidden value="{{ key|safe }}" name=key />
|
<input type=hidden value="{{ key|safe }}" name=key />
|
||||||
<input type=hidden value="{{ token|safe }}" name=token />
|
<input type=hidden value="{{ token|safe }}" name=token />
|
||||||
|
|
||||||
{% include "questions.html" %}
|
{% include "questions.html" %}
|
||||||
<p>
|
<p>
|
||||||
<input type=submit name=submit value="Submit"/><br>
|
{% if form.can_submit %}
|
||||||
|
<div class=submit>
|
||||||
|
<input type=submit name=submit value="Submit"/>
|
||||||
|
</div>
|
||||||
{% if form.vote_style == 'closed' %}
|
{% if form.vote_style == 'closed' %}
|
||||||
<div class = "warning">
|
<div class = "warning">
|
||||||
You can only vote once!
|
You can only vote once!
|
||||||
@@ -17,6 +26,9 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<div class=message>{{ form.message }}</div>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
35
utils.py
35
utils.py
@@ -131,10 +131,15 @@ def is_draft(form):
|
|||||||
def is_expired(form):
|
def is_expired(form):
|
||||||
if form['expires'] == None:
|
if form['expires'] == None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return datetime.now(timezone.utc) > form['expires']
|
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):
|
def is_key(key, cli_opts = False):
|
||||||
key = secure_filename(key)
|
key = secure_filename(key)
|
||||||
|
|
||||||
@@ -171,11 +176,14 @@ def is_voter(key, token):
|
|||||||
def parse_form(key):
|
def parse_form(key):
|
||||||
form = {
|
form = {
|
||||||
'expires': None,
|
'expires': None,
|
||||||
|
'opens': None,
|
||||||
'draft': False,
|
'draft': False,
|
||||||
'vote_style': "closed",
|
'vote_style': "closed",
|
||||||
'show_results': False,
|
'show_results': False,
|
||||||
'questions': [],
|
'questions': [],
|
||||||
'title': ""
|
'title': "",
|
||||||
|
'can_submit': True,
|
||||||
|
'message': ''
|
||||||
}
|
}
|
||||||
key = secure_filename(key)
|
key = secure_filename(key)
|
||||||
try:
|
try:
|
||||||
@@ -194,6 +202,9 @@ def parse_form(key):
|
|||||||
if rowsl.startswith("expires: "):
|
if rowsl.startswith("expires: "):
|
||||||
form['expires'] = parse_row_date(row)
|
form['expires'] = parse_row_date(row)
|
||||||
continue
|
continue
|
||||||
|
if rowsl.startswith("opens: "):
|
||||||
|
form['opens'] = parse_row_date(row)
|
||||||
|
continue
|
||||||
if rowsl.startswith("draft: "):
|
if rowsl.startswith("draft: "):
|
||||||
if rowsl == "draft: true":
|
if rowsl == "draft: true":
|
||||||
form['draft'] = True
|
form['draft'] = True
|
||||||
@@ -225,7 +236,7 @@ def parse_form(key):
|
|||||||
'choices': [],
|
'choices': [],
|
||||||
'multichoices': [],
|
'multichoices': [],
|
||||||
'index': current_question + 1,
|
'index': current_question + 1,
|
||||||
'name': row.strip().rstrip("_:").rstrip(),
|
'name': row.strip().rstrip("_").rstrip(),
|
||||||
'open_question': row.strip().endswith("___"),
|
'open_question': row.strip().endswith("___"),
|
||||||
'autoformat': not rowsl.startswith("<")
|
'autoformat': not rowsl.startswith("<")
|
||||||
})
|
})
|
||||||
@@ -237,7 +248,7 @@ def parse_form(key):
|
|||||||
|
|
||||||
|
|
||||||
def parse_row_date(row):
|
def parse_row_date(row):
|
||||||
row = row[9:].strip()
|
row = " ".join(row.split(" ")[1:]).strip()
|
||||||
if row.lower() == "none":
|
if row.lower() == "none":
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
@@ -304,12 +315,18 @@ def sort_summary(questions, answers):
|
|||||||
return questions, sorted_answer_list
|
return questions, sorted_answer_list
|
||||||
|
|
||||||
|
|
||||||
def time_to_expiry(form):
|
def time_to(what, form):
|
||||||
if form['expires'] == None:
|
if not what in ('expires','opens'):
|
||||||
return "Never"
|
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 = ".".join(str(time_to_go).split('.')[0:-1])[0:-3]
|
||||||
|
|
||||||
#time_to_go.microseconds = 0
|
#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 )
|
||||||
|
|||||||
Reference in New Issue
Block a user