changed database structure
This commit is contained in:
24
abot.py
24
abot.py
@@ -6,19 +6,14 @@ from revprox import ReverseProxied
|
|||||||
from utils import *
|
from utils import *
|
||||||
import manager
|
import manager
|
||||||
|
|
||||||
DATABASE = 'abot.sqlite'
|
DATABASE = 'abot.sqlite' # database file
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
SECRET_KEY = 'otwet6oi539iosf'
|
|
||||||
QUESTIONS = 'questions' # path to questions
|
QUESTIONS = 'questions' # path to questions
|
||||||
|
|
||||||
# create our little application :)
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object(__name__)
|
app.config.from_object(__name__)
|
||||||
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||||
|
|
||||||
def connect_db():
|
|
||||||
return sqlite3.connect(app.config['DATABASE'])
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
g.db = connect_db()
|
g.db = connect_db()
|
||||||
@@ -78,15 +73,13 @@ def save_vote():
|
|||||||
form = parse_form(key)
|
form = parse_form(key)
|
||||||
if not form:
|
if not form:
|
||||||
return render_template('blank.html', message = "Error creating form")
|
return render_template('blank.html', message = "Error creating form")
|
||||||
create_voter_table(g.db, key)
|
|
||||||
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):
|
if is_expired(form):
|
||||||
return render_template('blank.html', message = "Voting has closed")
|
return render_template('blank.html', message = "Voting has closed")
|
||||||
if is_closed_vote(form):
|
#~ if is_closed_vote(form):
|
||||||
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")
|
||||||
create_result_table(key)
|
|
||||||
|
|
||||||
write_vote(key, token, request.form, form) # using request.
|
write_vote(key, token, request.form, form) # using request.
|
||||||
tokens = False
|
tokens = False
|
||||||
@@ -95,16 +88,17 @@ def save_vote():
|
|||||||
answers = []
|
answers = []
|
||||||
if is_show_results(form):
|
if is_show_results(form):
|
||||||
summary = True
|
summary = True
|
||||||
questions, answers = get_summary(g.db, key)
|
questions, answers = sort_summary(*get_summary(g.db, key))
|
||||||
tokens = get_token_counts(g.db, key)
|
tokens = get_token_counts(g.db, key)
|
||||||
|
print(answers)
|
||||||
return render_template(
|
return render_template(
|
||||||
'thank_you.html',
|
'thank_you.html',
|
||||||
summary = summary,
|
summary = summary,
|
||||||
tokens = tokens,
|
tokens = tokens,
|
||||||
questions = questions,
|
qa = zip(questions, answers)
|
||||||
answers = answers
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
create_db(DATABASE)
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
manager.main(DATABASE, QUESTIONS)
|
manager.main(DATABASE, QUESTIONS)
|
||||||
|
|||||||
60
manager.py
60
manager.py
@@ -11,17 +11,18 @@ import sys
|
|||||||
|
|
||||||
|
|
||||||
def insert_token(db, name, token):
|
def insert_token(db, name, token):
|
||||||
table_name = get_voter_table_name(name)
|
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
INSERT INTO `%s` VALUES (
|
INSERT INTO tokens (token, question_set, answered) VALUES (
|
||||||
|
?,
|
||||||
?,
|
?,
|
||||||
'false'
|
'false'
|
||||||
);
|
);
|
||||||
"""%( table_name, ),
|
""",
|
||||||
(
|
(
|
||||||
token,
|
token,
|
||||||
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
@@ -31,7 +32,6 @@ def add_token(options):
|
|||||||
if not is_key(options.name, options):
|
if not is_key(options.name, options):
|
||||||
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
|
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
|
||||||
db = open_db(options.db)
|
db = open_db(options.db)
|
||||||
create_voter_table(db, options.name)
|
|
||||||
for i in range(options.number):
|
for i in range(options.number):
|
||||||
N = 32
|
N = 32
|
||||||
token = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
|
token = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
|
||||||
@@ -42,6 +42,7 @@ def add_token(options):
|
|||||||
token
|
token
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
def open_db(db):
|
def open_db(db):
|
||||||
return sqlite3.connect(db)
|
return sqlite3.connect(db)
|
||||||
|
|
||||||
@@ -98,22 +99,29 @@ def parse_options(database, questions):
|
|||||||
help = "Name of the question set"
|
help = "Name of the question set"
|
||||||
)
|
)
|
||||||
## clear
|
## clear
|
||||||
parser_clear = subparsers.add_parser('clear', help = "Delete results")
|
parser_clear_votes = subparsers.add_parser('clear_votes', help = "Delete results")
|
||||||
parser_clear.add_argument(
|
parser_clear_votes.add_argument(
|
||||||
'--really',
|
'--really',
|
||||||
action="store_true",
|
action="store_true",
|
||||||
dest="really",
|
dest="really",
|
||||||
default = False,
|
default = False,
|
||||||
help = "Really delete results for the vote"
|
help = "Really delete results for the vote"
|
||||||
)
|
)
|
||||||
parser_clear.add_argument(
|
parser_clear_votes.add_argument(
|
||||||
'--tokens',
|
dest = "name",
|
||||||
action="store_true",
|
help = "Name of the question set"
|
||||||
dest="tokens",
|
|
||||||
default = False,
|
|
||||||
help = "Delete tokens too"
|
|
||||||
)
|
)
|
||||||
parser_clear.add_argument(
|
|
||||||
|
## clear tokens
|
||||||
|
parser_clear_tokens = subparsers.add_parser('clear_tokens', help = "Delete tokens")
|
||||||
|
parser_clear_tokens.add_argument(
|
||||||
|
'--really',
|
||||||
|
action="store_true",
|
||||||
|
dest="really",
|
||||||
|
default = False,
|
||||||
|
help = "Really delete tokens for the vote"
|
||||||
|
)
|
||||||
|
parser_clear_tokens.add_argument(
|
||||||
dest = "name",
|
dest = "name",
|
||||||
help = "Name of the question set"
|
help = "Name of the question set"
|
||||||
)
|
)
|
||||||
@@ -141,7 +149,7 @@ def summary(options):
|
|||||||
questions, answers = get_summary(db, options.name)
|
questions, answers = get_summary(db, options.name)
|
||||||
tokens = get_token_counts(db, options.name)
|
tokens = get_token_counts(db, options.name)
|
||||||
|
|
||||||
if options.tsv:
|
if hasattr(options, 'tsv') and options.tsv:
|
||||||
out = summary_tsv(questions, answers, tokens)
|
out = summary_tsv(questions, answers, tokens)
|
||||||
else:
|
else:
|
||||||
out = summary_list(questions, answers, tokens)
|
out = summary_list(questions, answers, tokens)
|
||||||
@@ -203,29 +211,35 @@ def summary_tsv(questions, answers, tokens):
|
|||||||
|
|
||||||
|
|
||||||
def clear_votes(options):
|
def clear_votes(options):
|
||||||
if not is_key(options.name, options):
|
try:
|
||||||
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
|
|
||||||
summary(options)
|
summary(options)
|
||||||
|
except Exception as err:
|
||||||
|
print("\nQuestions no longer available")
|
||||||
if not options.really:
|
if not options.really:
|
||||||
print("\nNot really deleting results")
|
print("\nNot really deleting results. use --really")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
db = open_db(options.db)
|
db = open_db(options.db)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"DROP TABLE IF EXISTS `%s`"%( options.name, )
|
"DELETE FROM answers WHERE question_set = ?",
|
||||||
|
( options.name, )
|
||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
print("\nDeleted votes for %s"%( options.name, ))
|
print("\nDeleted votes for %s"%( options.name, ))
|
||||||
|
|
||||||
|
|
||||||
def clear_tokens(options):
|
def clear_tokens(options):
|
||||||
if not is_key(options.name, options):
|
db = open_db(options.db)
|
||||||
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
|
print(get_token_counts(db, options.name))
|
||||||
|
if not options.really:
|
||||||
|
print("\nNot really deleting tokens. use --really")
|
||||||
|
sys.exit(0)
|
||||||
db = open_db(options.db)
|
db = open_db(options.db)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"DROP TABLE IF EXISTS `%s`"%( get_voter_table_name(options.name,) )
|
"DELETE FROM tokens WHERE question_set = ?",
|
||||||
|
( options.name, )
|
||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
print("\nDeleted tokens for %s"%( options.name, ))
|
print("\nDeleted tokens for %s"%( options.name, ))
|
||||||
@@ -238,8 +252,8 @@ def main(database, questions):
|
|||||||
add_token(options)
|
add_token(options)
|
||||||
if options.subparser_name == "summary":
|
if options.subparser_name == "summary":
|
||||||
summary(options)
|
summary(options)
|
||||||
if options.subparser_name == "clear":
|
if options.subparser_name == "clear_votes":
|
||||||
clear_votes(options)
|
clear_votes(options)
|
||||||
if options.tokens:
|
if options.subparser_name == "clear_tokens":
|
||||||
clear_tokens(options)
|
clear_tokens(options)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ draft: false
|
|||||||
# Create tokens with `./manager token multi_question`
|
# Create tokens with `./manager token multi_question`
|
||||||
vote_style: closed
|
vote_style: closed
|
||||||
# By default voters can not see the results
|
# By default voters can not see the results
|
||||||
show_results: false
|
show_results: true
|
||||||
|
|
||||||
|
|
||||||
# HTML can be added inline. The line needs to begin with "<"
|
# HTML can be added inline. The line needs to begin with "<"
|
||||||
|
|||||||
@@ -8,20 +8,19 @@ Thank you for the vote!
|
|||||||
<h3>Current report</h3>
|
<h3>Current report</h3>
|
||||||
|
|
||||||
<div id="questions">
|
<div id="questions">
|
||||||
{% for question in questions %}
|
{% for qa_item in qa %}
|
||||||
|
|
||||||
<div class = "question autoformat">
|
<div class = "question autoformat">
|
||||||
<h2>{{ question|safe }}</h2>
|
<h2>{{ qa_item[0]|safe }}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{% for choice in answers[question].answers %}
|
{% for answer in qa_item[1] %}
|
||||||
{% if answers[question].answer_type == "single" %}
|
{% if answer.answer_type == "single" %}
|
||||||
<li class = "summary_single">{{ choice }}: {{ answers[question].answers[choice] }}
|
<li class = "summary_single">{{ answer.answer }}: {{ answer.count }} ({{ answer.percent }}%)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if answers[question].answer_type == "multiple" %}
|
{% if answer.answer_type == "multiple" %}
|
||||||
<li class = "summary_multiple">{{ choice }}: {{ answers[question].answers[choice] }}
|
<li class = "summary_multiple">{{ answer.answer }}: {{ answer.count }} ({{ answer.percent }}%)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if answers[question].answer_type == "open" %}
|
{% if answer.answer_type == "open" %}
|
||||||
<li class = "summary_open">"{{ choice }}"
|
<li class = "summary_open">"{{ answer.answer }}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
95
utils.py
95
utils.py
@@ -3,62 +3,51 @@ from flask import current_app as app
|
|||||||
from flask import g
|
from flask import g
|
||||||
import os
|
import os
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
import html
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
def connect_db():
|
||||||
|
return sqlite3.connect(app.config['DATABASE'])
|
||||||
|
|
||||||
|
|
||||||
|
def create_db(db_file):
|
||||||
|
db = sqlite3.connect(db_file)
|
||||||
|
cur = db.cursor()
|
||||||
|
|
||||||
def create_result_table(key):
|
|
||||||
cur = g.db.cursor()
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS `%s` (
|
CREATE TABLE IF NOT EXISTS answers (
|
||||||
|
question_set TEXT,
|
||||||
question TEXT,
|
question TEXT,
|
||||||
answer TEXT,
|
answer TEXT,
|
||||||
answer_type TEXT
|
answer_type TEXT
|
||||||
);
|
);
|
||||||
"""%(key, )
|
""")
|
||||||
)
|
|
||||||
g.db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def create_voter_table(db, name):
|
|
||||||
table_name = get_voter_table_name(name)
|
|
||||||
cur = db.cursor()
|
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS `%s` (
|
CREATE TABLE IF NOT EXISTS tokens (
|
||||||
token TEXT PRIMARY KEY,
|
token TEXT PRIMARY KEY,
|
||||||
|
question_set TEXT,
|
||||||
answered BOOLEAN
|
answered BOOLEAN
|
||||||
);
|
);
|
||||||
"""%(table_name, )
|
"""
|
||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
def get_voter_table_name(key):
|
|
||||||
return key + "__voters"
|
|
||||||
|
|
||||||
|
|
||||||
def get_result_table_name(key):
|
|
||||||
return key
|
|
||||||
|
|
||||||
def get_token_counts(db, key):
|
def get_token_counts(db, key):
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
token_table = get_voter_table_name(key)
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name=?;",
|
"SELECT count(*) FROM tokens WHERE answered = 'true' and question_set = ?",
|
||||||
( token_table, )
|
(
|
||||||
)
|
key,
|
||||||
matching_tables = cur.fetchall()
|
|
||||||
if len(matching_tables) == 0:
|
|
||||||
used_tokens = 0
|
|
||||||
unused_tokens = 0
|
|
||||||
else:
|
|
||||||
cur.execute(
|
|
||||||
"SELECT count(*) FROM `%s` WHERE answered = 'true'"%(
|
|
||||||
token_table,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
used_tokens = cur.fetchall()[0][0]
|
used_tokens = cur.fetchall()[0][0]
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT count(*) FROM `%s` WHERE answered = 'false'"%(
|
"SELECT count(*) FROM tokens WHERE answered = 'false' and question_set = ?",
|
||||||
token_table,
|
(
|
||||||
|
key,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
unused_tokens = cur.fetchall()[0][0]
|
unused_tokens = cur.fetchall()[0][0]
|
||||||
@@ -76,15 +65,8 @@ def get_summary(db, key):
|
|||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name=?;",
|
"SELECT question, answer, answer_type FROM answers WHERE question_set = ?",
|
||||||
( key, )
|
(
|
||||||
)
|
|
||||||
matching_tables = cur.fetchall()
|
|
||||||
if len(matching_tables) == 0:
|
|
||||||
return questions, answers
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"SELECT question, answer, answer_type FROM `%s`"%(
|
|
||||||
key,
|
key,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -108,11 +90,10 @@ def has_voted(key, token):
|
|||||||
return True
|
return True
|
||||||
cur = g.db.cursor()
|
cur = g.db.cursor()
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT token FROM %s WHERE token = ? AND answered = 'true'"%(
|
"SELECT token FROM tokens WHERE token = ? AND answered = 'true' AND question_set = ?",
|
||||||
get_voter_table_name(key),
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
token,
|
token,
|
||||||
|
key
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return len(cur.fetchall()) > 0
|
return len(cur.fetchall()) > 0
|
||||||
@@ -252,26 +233,34 @@ def write_vote(key, token, answers, form):
|
|||||||
continue
|
continue
|
||||||
for single in answer:
|
for single in answer:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"INSERT INTO `%s` VALUES (?, ?, ?)"%(
|
"INSERT INTO answers (question_set, question, answer, answer_type) VALUES (?, ?, ?, ?)",
|
||||||
key,
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
|
key,
|
||||||
question['name'],
|
question['name'],
|
||||||
single.strip(),
|
html.escape(single).strip(),
|
||||||
answer_type
|
answer_type
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if is_closed_vote(form):
|
if is_closed_vote(form):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"UPDATE %s SET answered = 'true' WHERE token = ?"%(
|
"UPDATE tokens SET answered = 'true' WHERE token = ? AND question_set = ?",
|
||||||
get_voter_table_name(key),
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
token,
|
token,
|
||||||
|
key
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
|
def sort_summary(questions, answers):
|
||||||
|
sorted_answer_list = []
|
||||||
|
for q,a in zip(questions, answers):
|
||||||
|
sum_answers = sum([answers[q]['answers'][x] for x in answers[q]['answers']])
|
||||||
|
sorted_answers = sorted(
|
||||||
|
[{"answer_type": answers[q]['answer_type'] , "answer": x, "count": answers[q]['answers'][x], "percent": int(100 * float(answers[q]['answers'][x]) / sum_answers)} for x in answers[q]['answers']],
|
||||||
|
key = lambda i: -i['count']
|
||||||
|
)
|
||||||
|
sorted_answer_list.append(sorted_answers)
|
||||||
|
return questions, sorted_answer_list
|
||||||
|
|
||||||
def time_to_expiry(form):
|
def time_to_expiry(form):
|
||||||
if form['expires'] == None:
|
if form['expires'] == None:
|
||||||
|
|||||||
Reference in New Issue
Block a user