From e64bd60f3f456065f788f9edae8c1885eb4f30ba Mon Sep 17 00:00:00 2001 From: iou1name Date: Mon, 16 Jul 2018 11:38:33 -0400 Subject: [PATCH] refactoring --- anonkun.py | 35 +++++++++++-- anonkun.sql | 117 +++++++++++++++++++++++-------------------- database.py | 50 ++++++++++++++---- events.py | 22 ++++++-- templates/quest.html | 26 +++++++--- views.py | 26 +++++----- 6 files changed, 181 insertions(+), 95 deletions(-) diff --git a/anonkun.py b/anonkun.py index acc4be7..dfae295 100644 --- a/anonkun.py +++ b/anonkun.py @@ -2,6 +2,7 @@ """ A Flask-based questing platform. """ +#TODO: look into how cloudflare proxying interacts with nginx import os import time @@ -9,6 +10,7 @@ from flask import Flask from flask_paranoid import Paranoid from flask_session import Session from flask_socketio import SocketIO +from werkzeug.contrib.fixers import ProxyFix import database as db from views import views @@ -51,6 +53,7 @@ class ReverseProxied(object): app = Flask(__name__) app.wsgi_app = ReverseProxied(app.wsgi_app) +app.wsgi_app = ProxyFix(app.wsgi_app) app.register_blueprint(views) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 app.config['SESSION_TYPE'] = 'filesystem' @@ -96,14 +99,36 @@ def get_dice_challenge(post_id): return db.get_dice_call(post_id)[3] -@app.template_filter("num_ips") -def num_ips(ips_voted): +@app.template_filter("num_votes") +def num_votes(option_id): """ Returns the number of IPs who voted for this option. """ - if not ips_voted: - return 0 - return len(ips_voted.split(",")) + return db.get_num_votes(option_id) + + +@app.template_filter("split_options") +def split_options(options): + """ + Splits a polls options into a list. + """ + return options.split("\n") + + +@app.template_filter("get_rolls") +def get_rolls(post_id): + """ + Gets the dice rolls for the template. + """ + return db.get_dice_rolls(post_id=post_id) + + +@app.template_filter("get_options") +def get_options(post_id): + """ + Gets the poll options for the template. + """ + return db.get_poll_options(post_id=post_id) @app.after_request diff --git a/anonkun.sql b/anonkun.sql index ee155d6..dc84b12 100644 --- a/anonkun.sql +++ b/anonkun.sql @@ -6,60 +6,6 @@ CREATE TABLE `users` ( PRIMARY KEY (`user_id`) ) ENGINE=InnoDB CHARSET utf8mb4; -CREATE TABLE `quest_meta` ( - `quest_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, - `canon_title` VARCHAR(300) DEFAULT NULL, - `ident_title` VARCHAR(300) DEFAULT NULL, - `owner_id` SMALLINT UNSIGNED DEFAULT NULL, - `open_post_id` SMALLINT UNSIGNED DEFAULT NULL, - PRIMARY KEY (`quest_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - -CREATE TABLE `quest_data` ( - `post_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, - `quest_id` SMALLINT UNSIGNED NOT NULL, - `post_type` ENUM('text', 'dice', 'poll') NOT NULL, - `post` MEDIUMTEXT NOT NULL, - `timestamp` INT UNSIGNED NOT NULL, - PRIMARY KEY (`post_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - -CREATE TABLE `dice_calls` ( - `post_id` MEDIUMINT UNSIGNED NOT NULL, - `dice_roll` TEXT NOT NULL, - `strict` BOOLEAN DEFAULT FALSE, - `dice_challenge` SMALLINT UNSIGNED, - `rolls_taken` TINYINT UNSIGNED, - PRIMARY KEY (`post_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - -CREATE TABLE `dice_rolls` ( - `message_id` MEDIUMINT UNSIGNED NOT NULL, - `quest_id` SMALLINT UNSIGNED NOT NULL, - `post_id` MEDIUMINT UNSIGNED NOT NULL, - `roll_dice` TEXT NOT NULL, - `roll_results` TEXT NOT NULL, - `roll_total` SMALLINT UNSIGNED NOT NULL, - PRIMARY KEY (`message_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - -CREATE TABLE `polls` ( - `post_id` MEDIUMINT UNSIGNED NOT NULL, - `multi_choice` BOOLEAN DEFAULT FALSE, - `allow_writein` BOOLEAN DEFAULT FALSE, - `total_ips` TEXT DEFAULT NULL, - PRIMARY KEY (`post_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - -CREATE TABLE `poll_options` ( - `option_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, - `post_id` MEDIUMINT UNSIGNED NOT NULL, - `quest_id` SMALLINT UNSIGNED NOT NULL, - `option_text` VARCHAR(200) NOT NULL, - `ips_voted` TEXT DEFAULT NULL, - PRIMARY KEY (`option_id`) -) ENGINE=InnoDB CHARSET utf8mb4; - CREATE TABLE `chat_messages` ( `message_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, `room_id` MEDIUMINT UNSIGNED NOT NULL, @@ -68,3 +14,66 @@ CREATE TABLE `chat_messages` ( `message` TEXT NOT NULL, PRIMARY KEY (`message_id`) ) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `quest_meta` ( + `quest_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, + `canon_title` VARCHAR(300) DEFAULT NULL, + `ident_title` VARCHAR(300) DEFAULT NULL, + `owner_id` SMALLINT UNSIGNED DEFAULT NULL, + `open_post_id` SMALLINT UNSIGNED DEFAULT NULL, + PRIMARY KEY (`quest_id`), + FOREIGN KEY (`owner_id`) REFERENCES `users`(`user_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `quest_data` ( + `post_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, + `quest_id` SMALLINT UNSIGNED NOT NULL, + `post_type` ENUM('text', 'dice', 'poll') NOT NULL, + `post` MEDIUMTEXT NOT NULL, + `timestamp` INT UNSIGNED NOT NULL, + PRIMARY KEY (`post_id`), + FOREIGN KEY (`quest_id`) REFERENCES `quest_meta`(`quest_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `dice_calls` ( + `post_id` MEDIUMINT UNSIGNED NOT NULL, + `dice_roll` TEXT NOT NULL, + `strict` BOOLEAN DEFAULT FALSE, + `dice_challenge` SMALLINT UNSIGNED, + `rolls_taken` TINYINT UNSIGNED, + FOREIGN KEY (`post_id`) REFERENCES `quest_data`(`post_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `dice_rolls` ( + `message_id` MEDIUMINT UNSIGNED NOT NULL, + `quest_id` SMALLINT UNSIGNED NOT NULL, + `post_id` MEDIUMINT UNSIGNED NOT NULL, + `roll_dice` TEXT NOT NULL, + `roll_results` TEXT NOT NULL, + `roll_total` SMALLINT UNSIGNED NOT NULL, + FOREIGN KEY (`message_id`) REFERENCES `chat_messages`(`message_id`), + FOREIGN KEY (`post_id`) REFERENCES `dice_calls`(`post_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `polls` ( + `post_id` MEDIUMINT UNSIGNED NOT NULL, + `quest_id` SMALLINT UNSIGNED NOT NULL, + `multi_choice` BOOLEAN DEFAULT FALSE, + `allow_writein` BOOLEAN DEFAULT FALSE, + FOREIGN KEY (`post_id`) REFERENCES `quest_data`(`post_id`), + FOREIGN KEY (`quest_id`) REFERENCES `quest_meta`(`quest_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `poll_options` ( + `option_id` MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, + `post_id` MEDIUMINT UNSIGNED NOT NULL, + `option_text` VARCHAR(200) NOT NULL, + PRIMARY KEY (`option_id`), + FOREIGN KEY (`post_id`) REFERENCES `polls`(`post_id`) +) ENGINE=InnoDB CHARSET utf8mb4; + +CREATE TABLE `poll_votes` ( + `option_id` MEDIUMINT UNSIGNED NOT NULL, + `ip_address` VARCHAR(32) NOT NULL, + FOREIGN KEY (`option_id`) REFERENCES `poll_options`(`option_id`) +) ENGINE=InnoDB CHARSET utf8mb4; diff --git a/database.py b/database.py index adc8a81..1487942 100644 --- a/database.py +++ b/database.py @@ -272,28 +272,35 @@ def get_dice_rolls(quest_id=None, post_id=None): return data -def insert_poll(post_id, multi_choice, allow_writein): +def insert_poll(post_id, quest_id, multi_choice, allow_writein): """Inserts a new poll post.""" _DB.execute( "INSERT INTO `polls` " \ - + "(`post_id`, `multi_choice`, `allow_writein`) " \ - + "VALUES (%s, %s, %s)", - (post_id, multi_choice, allow_writein)) + + "(`post_id`, `quest_id`, `multi_choice`, `allow_writein`) " \ + + "VALUES (%s, %s, %s, %s)", + (post_id, quest_id, multi_choice, allow_writein)) + + +def get_polls(quest_id): + """Gets poll information.""" + data = _DB.execute( + "SELECT * FROM `polls` WHERE `quest_id` = %s", (quest_id,)).fetchall() + return data def get_poll(post_id): """Gets poll information.""" - data = _DB.excute( - "SELECT * FROM `polls` WHERE `post_id` = %s", (post_id,)) + data = _DB.execute( + "SELECT * FROM `polls` WHERE `post_id` = %s", (post_id,)).fetchall() return data -def insert_poll_option(post_id, quest_id, option_text): +def insert_poll_option(post_id, option_text): """Insert a new poll option. ips_voted will be NULL to start.""" _DB.execute( "INSERT INTO `poll_options` " \ - + "(`post_id`, `quest_id`, `option_text`) VALUES (%s, %s, %s)", - (post_id, quest_id, option_text)) + + "(`post_id`, `option_text`) VALUES (%s, %s)", + (post_id, option_text)) def get_poll_options(quest_id=None, post_id=None): @@ -307,5 +314,28 @@ def get_poll_options(quest_id=None, post_id=None): ins = (post_id,) else: return - data = _DB.execute(sql, ins) + data = _DB.execute(sql, ins).fetchall() + return data + + +def insert_poll_vote(option_id, ip): + """Inserts a new vote for a poll option.""" + res = _DB.execute( + "INSERT ") + + +def insert_poll_vote(option_id, ip): + """Removes a vote from a poll.""" + pass + + +def get_poll_votes(quest_id): + pass + + +def get_num_votes(option_id): + """Returns the number of votes for an option.""" + data = _DB.execute( + "SELECT COUNT(`ip_address`) FROM `poll_votes` WHERE `option_id` = %s", + (option_id,)).fetchone()[0] return data diff --git a/events.py b/events.py index 755ea5e..bce7460 100644 --- a/events.py +++ b/events.py @@ -9,7 +9,7 @@ import random import functools import bleach -from flask import session +from flask import session, request from flask_socketio import SocketIO, emit, join_room import tools @@ -101,7 +101,7 @@ def message(data): db.insert_quest_roll(message_id, room, dice_call_id, roll_data) if len(db.get_dice_rolls(post_id=dice_call_id)) == dice_call[4]: - db.set_dice_call_closed(room) + db.set_post_closed(room) emit("close_dice_call", {"post_id": dice_call_id}, room=room) room = data["room"] @@ -277,7 +277,7 @@ def open_dice_call(data): @qm_only() def poll_post(data): """ - Called when the QM posts a new dice call. + Called when the QM posts a new poll. """ room = data.pop("room", None) multi_choice = bool(data.pop("pollAllowMultipleChoices", None)) @@ -288,15 +288,16 @@ def poll_post(data): continue if len(value) >= 200: return + value = bleach.clean(value).replace("\n", "") options.append(value) post = "Poll" date = int(time.time()) post_id = db.insert_quest_post(room, "poll", post, date) - db.insert_poll(post_id, multi_choice, allow_writein) + db.insert_poll(post_id, room, multi_choice, allow_writein) for option in options: - db.insert_poll_option(post_id, room, option) + db.insert_poll_option(post_id, option) db.set_post_open(post_id, room) data = {} @@ -306,3 +307,14 @@ def poll_post(data): data["date"] = int(time.time()) data["options"] = options emit("new_post", data, room=room) + + +@socketio.on("vote") +def vote(data): + """ + Called when a user changes their vote on a poll. + """ + print(data) + room = data.get("room") + option_id = data.get("option_id") + polarity = data.get("polarity") diff --git a/templates/quest.html b/templates/quest.html index 1372b22..72d204c 100644 --- a/templates/quest.html +++ b/templates/quest.html @@ -75,12 +75,20 @@ post.children[0].textContent = post.children[0].textContent.replace('Open', 'Closed'); document.getElementById('close_post_id-' + data.post_id).style.display = 'none'; document.getElementById('open_post_id-' + data.post_id).style.display = 'initial'; + if (post.parentElement.classList.contains('pollPost')) { + table = document.getElementById('poll-' + data.post_id); + table.getElementsByTagName("col")[0].style.visibility = 'collapse'; + } }); socket.on('open_post', function(data) { let post = document.getElementById('questPostData-' + data.post_id); post.firstElementChild.textContent = post.firstElementChild.textContent.replace('Closed', 'Open'); document.getElementById('close_post_id-' + data.post_id).style.display = 'initial'; document.getElementById('open_post_id-' + data.post_id).style.display = 'none'; + if (post.parentElement.classList.contains('pollPost')) { + table = document.getElementById('poll-' + data.post_id); + table.getElementsByTagName("col")[0].style.visibility = ''; + } }); let mtarea = document.getElementById('messageTextArea'); mtarea.addEventListener('keypress', function(event) { @@ -104,7 +112,8 @@ date_str += padToTwo(date.getHours()) + ':' + padToTwo(date.getMinutes()) + ':' + padToTwo(date.getSeconds()); return date_str; } - function pollVote() { + function pollVote(option_id) { + socket.emit('vote', {option_id: option_id, polarity: document.getElementById('pollInput-' + option_id).checked, room: {{ room_id }}}); } {% if session.get("user_id") == owner_id %} @@ -231,7 +240,7 @@ {% endautoescape %} {% elif quest_post[2] == "dice" %}

{{ quest_post[3] }} - {% if quest_post[0] == open_post_id %}Open{% else %}Closed{% endif %}

- {% for dice_roll in dice_rolls %} + {% for dice_roll in quest_post[0]|get_rolls %} {% if dice_roll[2] == quest_post[0] %}
Rolled {{ dice_roll[4] }} = {{ dice_roll[5] }} ({{ dice_roll[3] }}){% if quest_post[0]|dice_chal != 0 %} - {% if dice_roll[5] >= quest_post[0]|dice_chal %}Pass{% else %} Fail{% endif %}{% endif %} @@ -241,17 +250,18 @@ {% elif quest_post[2] == "poll" %}

{{ quest_post[3] }} - {% if quest_post[0] == open_post_id %}Open{% else %}Closed{% endif %}

- {% for option in poll_options %} - {% if option[1] == quest_post[0] %} + + + + {% for option in quest_post[0]|get_options %} - - + + - {% endif %} {% endfor %}
- + {{ option[3] }}{{ option[4]|num_ips }}{{ option[2] }}{{ option[0]|num_votes }}
{% endif %} diff --git a/views.py b/views.py index 34feff1..77083cc 100644 --- a/views.py +++ b/views.py @@ -47,28 +47,27 @@ def quest(quest_title): """ An arbituary quest page. """ + then = time.time() ident_title, _, extra = quest_title.partition("/") data = db.get_quest_meta(ident_title=ident_title) if not data: abort(404) - quest_id = data[0] + + quest_id = room_id = data[0] quest_title = data[1] owner_id = data[3] open_post_id = data[4] + quest_posts = db.get_quest_data(quest_id) - dice_rolls = db.get_dice_rolls(quest_id) - poll_options = db.get_poll_options(quest_id) + #dice_rolls = db.get_dice_rolls(quest_id) + #polls = db.get_polls(quest_id) + #polls = {poll[0]: poll[1:] for poll in polls} + messages = db.get_chat_messages(quest_id) - return render_template('quest.html', - quest_title=quest_title, - ident_title=ident_title, - quest_posts=quest_posts, - dice_rolls=dice_rolls, - poll_options=poll_options, - owner_id=owner_id, - open_post_id=open_post_id, - room_id=quest_id, - messages=messages) + + temp = render_template('quest.html', **locals()) + print(time.time() - then) + return temp @views.route("/quest//edit_quest", methods=["GET", "POST"]) @@ -200,4 +199,5 @@ def index(): """ The index page. """ + print(request.remote_addr) return render_template("index.html")