changed database structure

This commit is contained in:
Ville Rantanen
2018-12-05 10:47:58 +02:00
parent 2910cc2186
commit 59c371cd79
5 changed files with 108 additions and 112 deletions

24
abot.py
View File

@@ -6,19 +6,14 @@ from revprox import ReverseProxied
from utils import *
import manager
DATABASE = 'abot.sqlite'
DATABASE = 'abot.sqlite' # database file
DEBUG = True
SECRET_KEY = 'otwet6oi539iosf'
QUESTIONS = 'questions' # path to questions
# create our little application :)
app = Flask(__name__)
app.config.from_object(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)
def connect_db():
return sqlite3.connect(app.config['DATABASE'])
@app.before_request
def before_request():
g.db = connect_db()
@@ -78,15 +73,13 @@ def save_vote():
form = parse_form(key)
if not form:
return render_template('blank.html', message = "Error creating form")
create_voter_table(g.db, key)
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 has_voted(key, token):
return render_template('blank.html', message = "Token already used")
create_result_table(key)
#~ if is_closed_vote(form):
#~ if has_voted(key, token):
#~ return render_template('blank.html', message = "Token already used")
write_vote(key, token, request.form, form) # using request.
tokens = False
@@ -95,16 +88,17 @@ def save_vote():
answers = []
if is_show_results(form):
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)
print(answers)
return render_template(
'thank_you.html',
summary = summary,
tokens = tokens,
questions = questions,
answers = answers
qa = zip(questions, answers)
)
create_db(DATABASE)
if __name__ == "__main__":
manager.main(DATABASE, QUESTIONS)

View File

@@ -11,17 +11,18 @@ import sys
def insert_token(db, name, token):
table_name = get_voter_table_name(name)
cur = db.cursor()
cur.execute("""
INSERT INTO `%s` VALUES (
INSERT INTO tokens (token, question_set, answered) VALUES (
?,
?,
'false'
);
"""%( table_name, ),
""",
(
token,
name
)
)
db.commit()
@@ -31,7 +32,6 @@ def add_token(options):
if not is_key(options.name, options):
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
db = open_db(options.db)
create_voter_table(db, options.name)
for i in range(options.number):
N = 32
token = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
@@ -42,6 +42,7 @@ def add_token(options):
token
))
def open_db(db):
return sqlite3.connect(db)
@@ -98,22 +99,29 @@ def parse_options(database, questions):
help = "Name of the question set"
)
## clear
parser_clear = subparsers.add_parser('clear', help = "Delete results")
parser_clear.add_argument(
parser_clear_votes = subparsers.add_parser('clear_votes', help = "Delete results")
parser_clear_votes.add_argument(
'--really',
action="store_true",
dest="really",
default = False,
help = "Really delete results for the vote"
)
parser_clear.add_argument(
'--tokens',
action="store_true",
dest="tokens",
default = False,
help = "Delete tokens too"
parser_clear_votes.add_argument(
dest = "name",
help = "Name of the question set"
)
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",
help = "Name of the question set"
)
@@ -141,7 +149,7 @@ def summary(options):
questions, answers = get_summary(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)
else:
out = summary_list(questions, answers, tokens)
@@ -203,29 +211,35 @@ def summary_tsv(questions, answers, tokens):
def clear_votes(options):
if not is_key(options.name, options):
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
summary(options)
try:
summary(options)
except Exception as err:
print("\nQuestions no longer available")
if not options.really:
print("\nNot really deleting results")
print("\nNot really deleting results. use --really")
sys.exit(0)
db = open_db(options.db)
cur = db.cursor()
cur.execute(
"DROP TABLE IF EXISTS `%s`"%( options.name, )
"DELETE FROM answers WHERE question_set = ?",
( options.name, )
)
db.commit()
print("\nDeleted votes for %s"%( options.name, ))
def clear_tokens(options):
if not is_key(options.name, options):
raise Exception("%s does not exist, or is not a valid question set name"%( options.name, ))
db = open_db(options.db)
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)
cur = db.cursor()
cur.execute(
"DROP TABLE IF EXISTS `%s`"%( get_voter_table_name(options.name,) )
"DELETE FROM tokens WHERE question_set = ?",
( options.name, )
)
db.commit()
print("\nDeleted tokens for %s"%( options.name, ))
@@ -238,8 +252,8 @@ def main(database, questions):
add_token(options)
if options.subparser_name == "summary":
summary(options)
if options.subparser_name == "clear":
if options.subparser_name == "clear_votes":
clear_votes(options)
if options.tokens:
clear_tokens(options)
if options.subparser_name == "clear_tokens":
clear_tokens(options)

View File

@@ -9,7 +9,7 @@ draft: false
# Create tokens with `./manager token multi_question`
vote_style: closed
# 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 "<"

View File

@@ -8,20 +8,19 @@ Thank you for the vote!
<h3>Current report</h3>
<div id="questions">
{% for question in questions %}
{% for qa_item in qa %}
<div class = "question autoformat">
<h2>{{ question|safe }}</h2>
<h2>{{ qa_item[0]|safe }}</h2>
<ul>
{% for choice in answers[question].answers %}
{% if answers[question].answer_type == "single" %}
<li class = "summary_single">{{ choice }}: {{ answers[question].answers[choice] }}
{% for answer in qa_item[1] %}
{% if answer.answer_type == "single" %}
<li class = "summary_single">{{ answer.answer }}: {{ answer.count }} ({{ answer.percent }}%)
{% endif %}
{% if answers[question].answer_type == "multiple" %}
<li class = "summary_multiple">{{ choice }}: {{ answers[question].answers[choice] }}
{% if answer.answer_type == "multiple" %}
<li class = "summary_multiple">{{ answer.answer }}: {{ answer.count }} ({{ answer.percent }}%)
{% endif %}
{% if answers[question].answer_type == "open" %}
<li class = "summary_open">"{{ choice }}"
{% if answer.answer_type == "open" %}
<li class = "summary_open">"{{ answer.answer }}"
{% endif %}
{% endfor %}
</ul>

111
utils.py
View File

@@ -3,65 +3,54 @@ from flask import current_app as app
from flask import g
import os
from werkzeug.utils import secure_filename
import html
import sqlite3
def create_result_table(key):
cur = g.db.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS `%s` (
question TEXT,
answer TEXT,
answer_type TEXT
);
"""%(key, )
)
g.db.commit()
def connect_db():
return sqlite3.connect(app.config['DATABASE'])
def create_voter_table(db, name):
table_name = get_voter_table_name(name)
def create_db(db_file):
db = sqlite3.connect(db_file)
cur = db.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS `%s` (
token TEXT PRIMARY KEY,
answered BOOLEAN
CREATE TABLE IF NOT EXISTS answers (
question_set TEXT,
question TEXT,
answer TEXT,
answer_type TEXT
);
"""%(table_name, )
""")
cur.execute("""
CREATE TABLE IF NOT EXISTS tokens (
token TEXT PRIMARY KEY,
question_set TEXT,
answered BOOLEAN
);
"""
)
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):
cur = db.cursor()
token_table = get_voter_table_name(key)
cur.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name=?;",
( token_table, )
"SELECT count(*) FROM tokens WHERE answered = 'true' and question_set = ?",
(
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]
cur.execute(
"SELECT count(*) FROM tokens WHERE answered = 'false' and question_set = ?",
(
key,
)
used_tokens = cur.fetchall()[0][0]
cur.execute(
"SELECT count(*) FROM `%s` WHERE answered = 'false'"%(
token_table,
)
)
unused_tokens = cur.fetchall()[0][0]
)
unused_tokens = cur.fetchall()[0][0]
tokens = {
'unused': unused_tokens,
'used': used_tokens,
@@ -76,15 +65,8 @@ def get_summary(db, key):
cur = db.cursor()
cur.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name=?;",
( key, )
)
matching_tables = cur.fetchall()
if len(matching_tables) == 0:
return questions, answers
cur.execute(
"SELECT question, answer, answer_type FROM `%s`"%(
"SELECT question, answer, answer_type FROM answers WHERE question_set = ?",
(
key,
)
)
@@ -108,11 +90,10 @@ def has_voted(key, token):
return True
cur = g.db.cursor()
cur.execute(
"SELECT token FROM %s WHERE token = ? AND answered = 'true'"%(
get_voter_table_name(key),
),
"SELECT token FROM tokens WHERE token = ? AND answered = 'true' AND question_set = ?",
(
token,
key
)
)
return len(cur.fetchall()) > 0
@@ -252,26 +233,34 @@ def write_vote(key, token, answers, form):
continue
for single in answer:
cur.execute(
"INSERT INTO `%s` VALUES (?, ?, ?)"%(
key,
),
"INSERT INTO answers (question_set, question, answer, answer_type) VALUES (?, ?, ?, ?)",
(
key,
question['name'],
single.strip(),
html.escape(single).strip(),
answer_type
)
)
if is_closed_vote(form):
cur.execute(
"UPDATE %s SET answered = 'true' WHERE token = ?"%(
get_voter_table_name(key),
),
"UPDATE tokens SET answered = 'true' WHERE token = ? AND question_set = ?",
(
token,
key
)
)
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):
if form['expires'] == None: