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 *
|
||||
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)
|
||||
|
||||
64
manager.py
64
manager.py
@@ -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)
|
||||
|
||||
|
||||
@@ -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 "<"
|
||||
|
||||
@@ -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
111
utils.py
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user