diff --git a/abot.py b/abot.py index 2c08a28..8ea0713 100644 --- a/abot.py +++ b/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) diff --git a/manager.py b/manager.py index e0f3e63..ca18940 100644 --- a/manager.py +++ b/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) diff --git a/questions/multi_question.txt b/questions/multi_question.txt index e19d7fe..3f382ab 100644 --- a/questions/multi_question.txt +++ b/questions/multi_question.txt @@ -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 "<" diff --git a/templates/thank_you.html b/templates/thank_you.html index 18ceebc..d60d6da 100644 --- a/templates/thank_you.html +++ b/templates/thank_you.html @@ -8,20 +8,19 @@ Thank you for the vote!

Current report

-{% for question in questions %} - +{% for qa_item in qa %}
-

{{ question|safe }}

+

{{ qa_item[0]|safe }}

diff --git a/utils.py b/utils.py index b2091ea..9f560f8 100644 --- a/utils.py +++ b/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: