2018-06-16 18:52:46 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
SocketIO events.
|
|
|
|
"""
|
2018-07-11 18:25:10 -04:00
|
|
|
# TODO: harden the fuck up
|
2018-07-05 13:27:48 -04:00
|
|
|
import re
|
2018-06-16 18:52:46 -04:00
|
|
|
import time
|
2018-07-02 16:10:50 -04:00
|
|
|
import random
|
2018-07-11 18:25:10 -04:00
|
|
|
import functools
|
2018-06-16 18:52:46 -04:00
|
|
|
|
2018-06-17 17:49:49 -04:00
|
|
|
import bleach
|
2018-07-13 08:17:29 -04:00
|
|
|
from flask import session, request
|
2018-06-16 18:52:46 -04:00
|
|
|
from flask_socketio import SocketIO, emit, join_room
|
|
|
|
|
2018-06-25 15:52:10 -04:00
|
|
|
import tools
|
2018-07-02 16:10:50 -04:00
|
|
|
import database as db
|
2018-06-17 17:49:49 -04:00
|
|
|
|
2018-06-16 18:52:46 -04:00
|
|
|
socketio = SocketIO()
|
|
|
|
|
2018-07-11 18:25:10 -04:00
|
|
|
def qm_only(msg=""):
|
|
|
|
"""
|
|
|
|
A decorator function to protect certain endpoints so that only the
|
|
|
|
QM can access them.
|
|
|
|
"""
|
|
|
|
# TODO: better docstring, test this more thoroughly
|
|
|
|
def actual_decorator(func):
|
|
|
|
@functools.wraps(func)
|
|
|
|
def _nop(*args, **kwargs):
|
|
|
|
data = args[0]
|
|
|
|
room = data.get("room")
|
|
|
|
res = db.get_quest_meta(quest_id=room)
|
|
|
|
if not res:
|
|
|
|
return msg
|
|
|
|
if session.get("user_id") != res[3]:
|
|
|
|
return msg
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
return _nop
|
|
|
|
return actual_decorator
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-06-20 13:07:11 -04:00
|
|
|
@socketio.on('joined')
|
2018-06-16 18:52:46 -04:00
|
|
|
def joined(data):
|
|
|
|
"""
|
|
|
|
Sent by clients when they enter a room.
|
|
|
|
"""
|
|
|
|
room = data["room"]
|
|
|
|
join_room(room)
|
|
|
|
|
|
|
|
|
2018-06-20 13:07:11 -04:00
|
|
|
@socketio.on('message')
|
|
|
|
def message(data):
|
2018-06-16 18:52:46 -04:00
|
|
|
"""
|
|
|
|
Sent by a client when the user entered a new message.
|
|
|
|
"""
|
2018-07-06 02:09:55 -04:00
|
|
|
room = int(data["room"])
|
2018-06-16 18:52:46 -04:00
|
|
|
message = data["message"]
|
2018-07-06 02:09:55 -04:00
|
|
|
name = data["name"]
|
|
|
|
user_id = data.get("user_id")
|
|
|
|
|
|
|
|
data = {}
|
2018-06-16 18:52:46 -04:00
|
|
|
date = int(time.time())
|
|
|
|
data["date"] = date
|
2018-07-06 02:09:55 -04:00
|
|
|
data["name"] = name
|
|
|
|
data["user_id"] = user_id
|
|
|
|
data["room"] = room
|
2018-06-17 17:49:49 -04:00
|
|
|
|
|
|
|
message = message.strip()
|
|
|
|
if not message:
|
|
|
|
return
|
|
|
|
tags = ["b", "code", "i", "s"]
|
|
|
|
message = bleach.clean(message, tags=tags)
|
|
|
|
lines = []
|
|
|
|
for line in message.splitlines():
|
|
|
|
if line.startswith(">"):
|
|
|
|
line = '<span class="greenText">' + line + '</span>'
|
|
|
|
lines.append(line)
|
|
|
|
message = "<br />".join(lines)
|
2018-06-25 15:52:10 -04:00
|
|
|
message = tools.handle_img(message)
|
2018-07-07 13:43:58 -04:00
|
|
|
data["message"] = message
|
2018-07-07 19:18:08 -04:00
|
|
|
|
|
|
|
roll_msg = ""
|
2018-07-05 18:17:36 -04:00
|
|
|
if message.startswith("/dice") or message.startswith("/roll"):
|
2018-07-07 13:43:58 -04:00
|
|
|
roll_msg = handle_dice(data)
|
2018-07-06 02:09:55 -04:00
|
|
|
if roll_msg:
|
2018-07-08 17:50:54 -04:00
|
|
|
data["message"] += '<hr class="msgSrvHr" /><b>' + roll_msg + "</b>"
|
2018-07-05 13:27:48 -04:00
|
|
|
|
2018-07-07 19:18:08 -04:00
|
|
|
message_id = db.log_chat_message(data)
|
2018-06-17 17:49:49 -04:00
|
|
|
emit("message", data, room=room)
|
2018-06-20 13:07:11 -04:00
|
|
|
|
2018-07-07 19:18:08 -04:00
|
|
|
if roll_msg:
|
2018-07-08 17:50:54 -04:00
|
|
|
dice_call_id = db.get_quest_meta(data["room"])[4]
|
|
|
|
if dice_call_id:
|
|
|
|
dice_call = db.get_dice_call(dice_call_id)
|
2018-07-07 19:18:08 -04:00
|
|
|
dice_roll = re.search(r"(\d+d\d+(?:[+-]\d+)?)", message).group(1)
|
2018-07-09 07:45:35 -04:00
|
|
|
if dice_call[2] and dice_roll != dice_call[1]:
|
|
|
|
return
|
2018-07-09 09:18:58 -04:00
|
|
|
roll_results = re.search(r"Rolled (.+) =", roll_msg).group(1)
|
|
|
|
roll_total = int(re.search(r"= (\d+)$", roll_msg).group(1))
|
|
|
|
roll_data = (dice_roll, roll_results, roll_total)
|
|
|
|
db.insert_quest_roll(message_id, room, dice_call_id, roll_data)
|
2018-07-07 19:18:08 -04:00
|
|
|
|
2018-07-11 18:25:10 -04:00
|
|
|
if len(db.get_dice_rolls(post_id=dice_call_id)) == dice_call[4]:
|
2018-07-13 08:17:29 -04:00
|
|
|
db.set_post_closed(room)
|
2018-07-09 07:45:35 -04:00
|
|
|
emit("close_dice_call", {"post_id": dice_call_id}, room=room)
|
|
|
|
|
2018-07-07 19:18:08 -04:00
|
|
|
room = data["room"]
|
|
|
|
data = {}
|
|
|
|
data["post"] = roll_msg + " (" + dice_roll + ")"
|
2018-07-09 09:18:58 -04:00
|
|
|
if dice_call[3]:
|
|
|
|
if roll_total >= dice_call[3]:
|
|
|
|
data["post"] += " - Pass"
|
|
|
|
else:
|
|
|
|
data["post"] += " - Fail"
|
2018-07-07 19:18:08 -04:00
|
|
|
data["post_type"] = "dice"
|
2018-07-08 17:50:54 -04:00
|
|
|
data["post_id"] = dice_call_id
|
2018-07-07 19:18:08 -04:00
|
|
|
emit("update_post", data, room=room)
|
|
|
|
|
2018-07-05 13:27:48 -04:00
|
|
|
|
2018-07-07 13:43:58 -04:00
|
|
|
def handle_dice(data):
|
2018-07-05 13:27:48 -04:00
|
|
|
"""
|
|
|
|
Handle /dice or /roll messages.
|
|
|
|
"""
|
2018-07-07 13:43:58 -04:00
|
|
|
reg = re.search(r"(\d+)d(\d+)([+-]\d+)?", data["message"])
|
2018-07-05 13:27:48 -04:00
|
|
|
if not reg:
|
|
|
|
return
|
|
|
|
try:
|
2018-07-06 02:09:55 -04:00
|
|
|
groups = [0 if d is None else int(d) for d in reg.groups()]
|
|
|
|
diceNum, diceSides, diceMod = groups
|
2018-07-05 13:27:48 -04:00
|
|
|
assert 0 < diceNum < 100
|
|
|
|
assert 0 < diceSides < 100
|
|
|
|
assert -1000 < diceMod < 1000
|
|
|
|
except (ValueError, AssertionError):
|
|
|
|
return
|
|
|
|
dice = [random.randint(1, diceSides) for _ in range(diceNum)]
|
|
|
|
total = sum(dice)
|
|
|
|
if diceMod:
|
|
|
|
total += diceMod
|
2018-07-08 17:50:54 -04:00
|
|
|
msg = f"Rolled {', '.join(map(str, dice))}"
|
2018-07-05 13:27:48 -04:00
|
|
|
if diceMod:
|
|
|
|
if diceMod > 0:
|
2018-07-09 07:45:35 -04:00
|
|
|
msg += " + " + str(diceMod)
|
2018-07-07 19:18:08 -04:00
|
|
|
else:
|
|
|
|
msg += " - " + str(diceMod)[1:]
|
2018-07-08 17:50:54 -04:00
|
|
|
msg += " = " + str(total)
|
2018-07-05 18:17:36 -04:00
|
|
|
return msg
|
2018-07-05 13:27:48 -04:00
|
|
|
|
2018-06-20 13:07:11 -04:00
|
|
|
|
|
|
|
@socketio.on("new_post")
|
2018-07-11 18:25:10 -04:00
|
|
|
@qm_only()
|
2018-07-06 02:09:55 -04:00
|
|
|
def new_post(data, internal=False):
|
2018-06-20 13:07:11 -04:00
|
|
|
"""
|
|
|
|
Called when the QM makes a new post.
|
|
|
|
"""
|
2018-07-11 18:25:10 -04:00
|
|
|
room = data.get("room")
|
|
|
|
post = data.get("post")
|
2018-07-07 13:43:58 -04:00
|
|
|
post = bleach.clean(post.strip())
|
2018-06-20 13:07:11 -04:00
|
|
|
post = post.replace("\n", "<br />")
|
2018-06-27 08:43:00 -04:00
|
|
|
post = tools.handle_img(post)
|
2018-07-11 18:25:10 -04:00
|
|
|
date = int(time.time())
|
|
|
|
|
|
|
|
post_id = db.insert_quest_post(room, "text", post, date)
|
|
|
|
db.set_post_closed(room)
|
2018-07-06 02:09:55 -04:00
|
|
|
|
|
|
|
data = {}
|
2018-06-20 13:07:11 -04:00
|
|
|
data["post"] = [post]
|
2018-07-07 13:43:58 -04:00
|
|
|
data["post_type"] = "text"
|
2018-07-11 18:25:10 -04:00
|
|
|
data["date"] = date
|
2018-07-04 17:20:47 -04:00
|
|
|
data["post_id"] = post_id
|
2018-06-20 13:07:11 -04:00
|
|
|
|
|
|
|
emit("new_post", data, room=room)
|
2018-06-21 20:44:43 -04:00
|
|
|
|
|
|
|
|
|
|
|
@socketio.on("update_post")
|
2018-07-11 18:25:10 -04:00
|
|
|
@qm_only()
|
2018-06-21 20:44:43 -04:00
|
|
|
def update_post(data):
|
|
|
|
"""
|
|
|
|
Called when the QM edits and saves a post.
|
|
|
|
"""
|
2018-07-07 19:18:08 -04:00
|
|
|
# TODO: enforce only update text posts
|
2018-07-11 18:25:10 -04:00
|
|
|
room = data["room"]
|
2018-06-21 20:44:43 -04:00
|
|
|
post = data["post"]
|
2018-06-21 22:49:25 -04:00
|
|
|
post = post.strip().replace("<br>", "<br />")
|
2018-06-27 08:43:00 -04:00
|
|
|
post = tools.handle_img(post)
|
2018-06-21 22:49:25 -04:00
|
|
|
|
2018-06-21 20:44:43 -04:00
|
|
|
post_id = data["post_id"]
|
|
|
|
db.update_quest_post(post_id, post)
|
2018-07-06 02:09:55 -04:00
|
|
|
|
|
|
|
data = {}
|
|
|
|
data["post"] = post
|
|
|
|
data["post_id"] = post_id
|
2018-07-07 19:18:08 -04:00
|
|
|
data["post_type"] = "text"
|
2018-06-21 20:44:43 -04:00
|
|
|
emit("update_post", data, room=room)
|
2018-07-02 16:10:50 -04:00
|
|
|
|
|
|
|
|
2018-07-04 17:20:47 -04:00
|
|
|
@socketio.on("dice_post")
|
2018-07-11 18:25:10 -04:00
|
|
|
@qm_only()
|
2018-07-06 02:09:55 -04:00
|
|
|
def dice_post(data):
|
2018-07-02 16:10:50 -04:00
|
|
|
"""
|
|
|
|
Called when the QM posts a new dice call.
|
|
|
|
"""
|
|
|
|
room = data["room"]
|
2018-07-06 02:09:55 -04:00
|
|
|
data = {k: v for k, v in data.items() if v}
|
|
|
|
try:
|
|
|
|
diceNum = int(data.get("diceNum", 0))
|
|
|
|
diceSides = int(data.get("diceSides", 0))
|
|
|
|
diceMod = int(data.get("diceMod", 0))
|
|
|
|
diceChal = int(data.get("diceChal", 0))
|
2018-07-11 18:25:10 -04:00
|
|
|
diceRollsTaken = int(data.get("diceRollsTaken", 0))
|
2018-07-06 02:09:55 -04:00
|
|
|
|
|
|
|
assert 0 < diceNum < 100
|
|
|
|
assert 0 < diceSides < 100
|
|
|
|
assert -1000 < diceMod < 1000
|
|
|
|
assert 0 <= diceChal < 100
|
2018-07-11 18:25:10 -04:00
|
|
|
assert 0 <= diceRollsTaken < 100
|
2018-07-06 02:09:55 -04:00
|
|
|
except (ValueError, AssertionError):
|
|
|
|
return
|
2018-07-07 19:18:08 -04:00
|
|
|
diceStrict = bool(data.get("diceStrict"))
|
2018-07-06 02:09:55 -04:00
|
|
|
|
2018-07-07 19:18:08 -04:00
|
|
|
dice_roll = f"{data['diceNum']}d{data['diceSides']}"
|
2018-07-06 02:09:55 -04:00
|
|
|
if diceMod:
|
|
|
|
if diceMod > 0:
|
2018-07-07 19:18:08 -04:00
|
|
|
dice_roll += "+"
|
|
|
|
dice_roll += str(diceMod)
|
|
|
|
|
2018-07-08 17:50:54 -04:00
|
|
|
post = "Roll " + dice_roll
|
2018-07-06 02:09:55 -04:00
|
|
|
if diceChal:
|
|
|
|
post += " vs DC" + str(diceChal)
|
2018-07-11 18:25:10 -04:00
|
|
|
date = int(time.time())
|
|
|
|
|
|
|
|
post_id = db.insert_quest_post(room, "dice", post, date)
|
|
|
|
new_call = (dice_roll, diceStrict, diceChal, diceRollsTaken)
|
|
|
|
db.insert_dice_call(post_id, room, new_call)
|
|
|
|
db.set_post_open(post_id, room)
|
2018-07-04 17:20:47 -04:00
|
|
|
|
2018-07-07 13:43:58 -04:00
|
|
|
data = {}
|
|
|
|
data["post"] = post
|
|
|
|
data["post_type"] = "dice"
|
2018-07-11 18:25:10 -04:00
|
|
|
data["date"] = date
|
2018-07-07 13:43:58 -04:00
|
|
|
data["post_id"] = post_id
|
|
|
|
emit("new_post", data, room=room)
|
2018-07-08 17:50:54 -04:00
|
|
|
|
|
|
|
|
2018-07-11 18:25:10 -04:00
|
|
|
@socketio.on('close_post')
|
|
|
|
@qm_only()
|
2018-07-08 17:50:54 -04:00
|
|
|
def close_dice_call(data):
|
|
|
|
"""
|
2018-07-11 18:25:10 -04:00
|
|
|
Closes an active post.
|
2018-07-08 17:50:54 -04:00
|
|
|
"""
|
|
|
|
room = data["room"]
|
|
|
|
post_id = data.get("post_id")
|
2018-07-11 18:25:10 -04:00
|
|
|
db.set_post_closed(room)
|
2018-07-08 17:50:54 -04:00
|
|
|
|
|
|
|
data = {}
|
|
|
|
data["post_id"] = post_id
|
2018-07-11 18:25:10 -04:00
|
|
|
emit("close_post", data, room=room)
|
2018-07-08 17:50:54 -04:00
|
|
|
|
|
|
|
|
2018-07-11 18:25:10 -04:00
|
|
|
@socketio.on("open_post")
|
|
|
|
@qm_only()
|
2018-07-08 17:50:54 -04:00
|
|
|
def open_dice_call(data):
|
|
|
|
"""
|
2018-07-11 18:25:10 -04:00
|
|
|
Opens an active post. This is only permitted if the active post is
|
2018-07-08 17:50:54 -04:00
|
|
|
the last post in the quest.
|
|
|
|
"""
|
2018-07-08 20:19:19 -04:00
|
|
|
# TODO: enforce only open if last post
|
2018-07-11 18:25:10 -04:00
|
|
|
room = data["room"]
|
2018-07-08 17:50:54 -04:00
|
|
|
post_id = data.get("post_id")
|
2018-07-11 18:25:10 -04:00
|
|
|
db.set_post_open(post_id, room)
|
2018-07-08 17:50:54 -04:00
|
|
|
|
|
|
|
data = {}
|
|
|
|
data["post_id"] = post_id
|
2018-07-11 18:25:10 -04:00
|
|
|
emit("open_post", data, room=room)
|
|
|
|
|
|
|
|
|
|
|
|
@socketio.on("poll_post")
|
|
|
|
@qm_only()
|
|
|
|
def poll_post(data):
|
|
|
|
"""
|
2018-07-13 08:17:29 -04:00
|
|
|
Called when the QM posts a new poll.
|
2018-07-11 18:25:10 -04:00
|
|
|
"""
|
|
|
|
room = data.pop("room", None)
|
|
|
|
multi_choice = bool(data.pop("pollAllowMultipleChoices", None))
|
|
|
|
allow_writein = bool(data.pop("pollAllowUserOptions", None))
|
|
|
|
options = []
|
|
|
|
for key, value in data.items():
|
|
|
|
if not value or not key.startswith("pollOption-"):
|
|
|
|
continue
|
|
|
|
if len(value) >= 200:
|
|
|
|
return
|
2018-07-13 08:17:29 -04:00
|
|
|
value = bleach.clean(value).replace("\n", "")
|
2018-07-11 18:25:10 -04:00
|
|
|
options.append(value)
|
|
|
|
|
|
|
|
post = "Poll"
|
|
|
|
date = int(time.time())
|
|
|
|
|
|
|
|
post_id = db.insert_quest_post(room, "poll", post, date)
|
2018-07-13 08:17:29 -04:00
|
|
|
db.insert_poll(post_id, room, multi_choice, allow_writein)
|
2018-07-11 18:25:10 -04:00
|
|
|
for option in options:
|
2018-07-13 08:17:29 -04:00
|
|
|
db.insert_poll_option(post_id, option)
|
2018-07-11 18:25:10 -04:00
|
|
|
db.set_post_open(post_id, room)
|
|
|
|
|
|
|
|
data = {}
|
|
|
|
data["post"] = post
|
|
|
|
data["post_id"] = post_id
|
|
|
|
data["post_type"] = "poll"
|
|
|
|
data["date"] = int(time.time())
|
|
|
|
data["options"] = options
|
|
|
|
emit("new_post", data, room=room)
|
2018-07-13 08:17:29 -04:00
|
|
|
|
|
|
|
|
|
|
|
@socketio.on("vote")
|
|
|
|
def vote(data):
|
|
|
|
"""
|
|
|
|
Called when a user changes their vote on a poll.
|
|
|
|
"""
|
|
|
|
room = data.get("room")
|
|
|
|
option_id = data.get("option_id")
|
|
|
|
polarity = data.get("polarity")
|
2018-07-18 19:09:54 -04:00
|
|
|
#ip_address = request.remote_addr
|
|
|
|
ip_address = request.headers.get("X-Real-Ip")
|
|
|
|
|
|
|
|
if polarity:
|
|
|
|
db.insert_poll_vote(option_id, ip_address)
|
|
|
|
else:
|
|
|
|
db.remove_poll_vote(option_id, ip_address)
|
|
|
|
|
|
|
|
data = {}
|
|
|
|
data["option_id"] = option_id
|
|
|
|
data["polarity"] = polarity
|
|
|
|
emit("vote", data, room=room)
|