enforce QM only events and added try/except blocks on all DB lookups in events.py

This commit is contained in:
iou1name 2018-10-09 14:05:03 -04:00
parent 36d0c0c874
commit 3db28b38a6
3 changed files with 174 additions and 94 deletions

View File

@ -8,6 +8,7 @@ from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from .events import events from .events import events
from .models import Quest
class QuestConsumer(WebsocketConsumer): class QuestConsumer(WebsocketConsumer):
""" """
@ -25,6 +26,11 @@ class QuestConsumer(WebsocketConsumer):
self.quest_id = self.scope['url_route']['kwargs']['quest_id'] self.quest_id = self.scope['url_route']['kwargs']['quest_id']
self.group_name = 'quest_' + str(self.quest_id) self.group_name = 'quest_' + str(self.quest_id)
try:
Quest.objects.get(id=self.quest_id)
except Quest.DoesNotExist:
return
async_to_sync(self.channel_layer.group_add)( async_to_sync(self.channel_layer.group_add)(
self.group_name, self.group_name,
self.channel_name self.channel_name

View File

@ -3,8 +3,6 @@
Individual functions for handling WebSocket events. Gets called by the Individual functions for handling WebSocket events. Gets called by the
QuestConsumer object in consumers.py. QuestConsumer object in consumers.py.
""" """
# TODO: quest owner only events
# TODO: try/except on database calls
import re import re
import time import time
import types import types
@ -25,7 +23,6 @@ def message(socket, data):
""" """
Gets called when the server receives a 'message' event. Gets called when the server receives a 'message' event.
""" """
# TODO: validation
message = data.get('message') message = data.get('message')
# cleaning # cleaning
@ -64,6 +61,7 @@ def message(socket, data):
if not reg: if not reg:
return return
try: try:
# TODO: form validation?
groups = [0 if d is None else int(d) for d in reg.groups()] groups = [0 if d is None else int(d) for d in reg.groups()]
dice_num, dice_sides, dice_mod = groups dice_num, dice_sides, dice_mod = groups
assert 1 <= dice_num <= 256 assert 1 <= dice_num <= 256
@ -150,20 +148,28 @@ def text_post(socket, data):
""" """
Called when the QM creates a new text post. Called when the QM creates a new text post.
""" """
# TODO: security quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
post_text = data.get('text') post_text = data.get('text')
page_num = data.get('page_num') page_num = data.get('page_num')
try:
page = Page.objects.get(quest=quest, page_num=page_num)
except Page.DoesNotExist:
return
# cleaning # cleaning
post_text = bleach.clean(post_text.strip()) post_text = bleach.clean(post_text.strip())
post_text = post_text.replace("\n", "<br>") post_text = post_text.replace("\n", "<br>")
# handle image # handle image
quest = Quest.objects.get(id=socket.quest_id)
p = Post( p = Post(
quest=quest, quest=quest,
page=Page.objects.get(quest=quest, page_num=page_num), page=page,
post_type='text', post_type='text',
post_text=post_text) post_text=post_text)
p.save() p.save()
@ -195,18 +201,31 @@ def dice_post(socket, data):
""" """
Called when the QM makes a new dice post. Called when the QM makes a new dice post.
""" """
quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
page_num = data.get('page_num') page_num = data.get('page_num')
try:
page = Page.objects.get(quest=quest, page_num=page_num)
except Page.DoesNotExist:
return
form = DiceCallForm(data) form = DiceCallForm(data)
if not form.is_valid(): if not form.is_valid():
return # error message? return # error message?
form = form.cleaned_data form = form.cleaned_data
posts = Post.objects.filter( posts = Post.objects.filter(
quest__id=socket.quest_id, post_type='dice', dicecall__open=True) quest=quest,
post_type='dice',
dicecall__open=True
)
for post in posts: for post in posts:
post.dicecall.open = False post.dicecall.open = False
post.dicecall.save() post.dicecall.save()
socket.send('close_all_posts') socket.send('close_all_posts', {'post_type': 'dice'})
dice_roll = str(form['diceNum']) + "d" dice_roll = str(form['diceNum']) + "d"
dice_roll += str(form['diceSides']) dice_roll += str(form['diceSides'])
@ -219,10 +238,9 @@ def dice_post(socket, data):
if form['diceChal']: if form['diceChal']:
post_text += " vs DC" + str(form['diceChal']) post_text += " vs DC" + str(form['diceChal'])
quest = Quest.objects.get(id=socket.quest_id)
p = Post( p = Post(
quest=quest, quest=quest,
page=Page.objects.get(quest=quest, page_num=page_num), page=page,
post_type='dice', post_type='dice',
post_text=post_text post_text=post_text
) )
@ -264,16 +282,25 @@ def poll_post(socket, data):
""" """
Called when the QM makes a new dice post. Called when the QM makes a new dice post.
""" """
quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
try:
page = Page.objects.get(quest=quest, page_num=page_num)
except Page.DoesNotExist:
return
page_num = data.get('page_num') page_num = data.get('page_num')
form = PollForm(data) form = PollForm(data)
if not form.is_valid(): if not form.is_valid():
return # error message? return # error message?
form = form.cleaned_data form = form.cleaned_data
quest=Quest.objects.get(id=socket.quest_id)
p = Post( p = Post(
quest=quest, quest=quest,
page=Page.objects.get(quest=quest, page_num=page_num), page=page,
post_type='poll', post_type='poll',
post_text="Poll" post_text="Poll"
) )
@ -322,16 +349,25 @@ def edit_post(socket, data):
""" """
Called when the QM saves an edited post. Called when the QM saves an edited post.
""" """
quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
post_id = data.get('post_id') post_id = data.get('post_id')
post_text = data.get('post_text') post_text = data.get('post_text')
try:
p = Post.objects.get(id=post_id)
except Post.DoesNotExist:
return
# cleaning # cleaning
post_text = bleach.clean(post_text.strip()) post_text = bleach.clean(post_text.strip())
post_text = post_text.replace("\n", "<br>") post_text = post_text.replace("\n", "<br>")
# handle image # handle image
p = Post.objects.get(id=post_id)
p.post_text = post_text p.post_text = post_text
p.save() p.save()
@ -346,8 +382,17 @@ def close_post(socket, data):
""" """
Called when the QM closes an open post. Called when the QM closes an open post.
""" """
quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
post_id = data.get('post_id') post_id = data.get('post_id')
p = Post.objects.get(id=post_id) try:
p = Post.objects.get(id=post_id)
except Post.DoesNotExist:
return
if data.get('post_type') == 'dice': if data.get('post_type') == 'dice':
p.dicecall.open = False p.dicecall.open = False
p.dicecall.save() p.dicecall.save()
@ -364,12 +409,23 @@ def open_post(socket, data):
""" """
Called when the QM opens a closed post. Called when the QM opens a closed post.
""" """
# TODO: only posts on last page can be opened quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
post_id = data.get('post_id') post_id = data.get('post_id')
p = Post.objects.get(id=post_id) try:
p = Post.objects.get(id=post_id)
except Post.DoesNotExist:
return
if data.get('post_type') == 'dice': if data.get('post_type') == 'dice':
posts = Post.objects.filter( posts = Post.objects.filter(
quest__id=socket.quest_id, post_type='dice', dicecall__open=True) quest=quest,
post_type='dice',
dicecall__open=True
)
for post in posts: for post in posts:
post.dicecall.open = False post.dicecall.open = False
post.dicecall.save() post.dicecall.save()
@ -386,89 +442,18 @@ def open_post(socket, data):
socket.send('open_post', data) socket.send('open_post', data)
def vote(socket, data):
"""
Called when a player votes in a poll.
"""
post_id = data.get('post_id')
option_id = data.get('option_id')
polarity = data.get('polarity')
ip_address = socket.scope['client'][0]
user = socket.scope['user']
if polarity == False:
v = PollVote.objects.get(ip_address=ip_address, option__id=option_id)
v.delete()
else:
p = Poll.objects.get(post_id=post_id)
if p.multi_choice == False:
votes = PollVote.objects.filter(
ip_address=ip_address,
option__poll=p
)
for vote in votes:
vote.delete()
data = {}
data['option_id'] = vote.option.id
data['polarity'] = False
socket.send('vote', data)
socket.self_send('set_option_box', data)
v = PollVote(
option=PollOption.objects.get(id=option_id),
ip_address=ip_address
)
if user.username:
v.user = user
try:
v.save()
except IntegrityError: # shouldn't we check this first?
return
data = {}
data['option_id'] = option_id
data['polarity'] = polarity
socket.send('vote', data)
def write_in(socket, data):
"""
Called when a player creates a new write-in.
"""
post_id = data.get('post_id')
option_text = data.get('option_text', '')
user = socket.scope['user']
option_text = option_text.strip()
if not option_text:
return
option_text = "Write in: " + bleach.clean(option_text)
if len(option_text) > 200:
# error message?
return
p = Poll.objects.get(post_id=post_id)
o = PollOption(
poll=p,
text=option_text
)
o.save()
data = {}
data['post_id'] = post_id
data['post_type'] = 'poll'
data['option_id'] = o.id
data['option_text'] = option_text
socket.send('update_post', data)
def new_page(socket, data): def new_page(socket, data):
""" """
Called when the QM creates a new page. Called when the QM creates a new page.
""" """
quest = Quest.objects.get(id=socket.quest_id)
user = socket.scope['user']
if quest.owner != user:
return # error message?
title = data.get('page_title') title = data.get('page_title')
appendix = bool(data.get('appendix')) appendix = bool(data.get('appendix'))
quest = Quest.objects.get(id=socket.quest_id)
if appendix: if appendix:
page = Page.objects.filter( page = Page.objects.filter(
quest=quest, quest=quest,
@ -518,6 +503,96 @@ def new_page(socket, data):
socket.send('message', data) socket.send('message', data)
def vote(socket, data):
"""
Called when a player votes in a poll.
"""
post_id = data.get('post_id')
option_id = data.get('option_id')
polarity = data.get('polarity')
ip_address = socket.scope['client'][0]
user = socket.scope['user']
if polarity == False:
try:
v = PollVote.objects.get(
ip_address=ip_address,
option__id=option_id
)
except PollVote.DoesNotExist:
return
v.delete()
else:
try:
p = Poll.objects.get(post_id=post_id)
option = PollOption.objects.get(id=option_id)
except (Poll.DoesNotExist, PollOption.DoesNotExist):
return
pvs = PollVote.objects.filter(option=option, ip_address=ip_address)
if pvs.count() != 0:
return
if p.multi_choice == False:
votes = PollVote.objects.filter(
ip_address=ip_address,
option__poll=p
)
for vote in votes:
vote.delete()
data = {}
data['option_id'] = vote.option.id
data['polarity'] = False
socket.send('vote', data)
socket.self_send('set_option_box', data)
pv = PollVote(
option=option,
ip_address=ip_address
)
if user.username:
pv.user = user
pv.save()
data = {}
data['option_id'] = option_id
data['polarity'] = polarity
socket.send('vote', data)
def write_in(socket, data):
"""
Called when a player creates a new write-in.
"""
post_id = data.get('post_id')
option_text = data.get('option_text', '')
user = socket.scope['user']
try:
p = Poll.objects.get(post_id=post_id)
except Poll.DoesNotExist:
return
option_text = option_text.strip()
if not option_text:
return
option_text = "Write in: " + bleach.clean(option_text)
if len(option_text) > 200:
# error message?
return
o = PollOption(
poll=p,
text=option_text
)
o.save()
data = {}
data['post_id'] = post_id
data['post_type'] = 'poll'
data['option_id'] = o.id
data['option_text'] = option_text
socket.send('update_post', data)
events = {} events = {}
for obj in dir(): for obj in dir():
if type(locals()[obj]) == types.FunctionType: if type(locals()[obj]) == types.FunctionType:

1
todo
View File

@ -10,7 +10,6 @@ Quote backlinks
Improvements: Improvements:
More options for text posts (lists and so on) More options for text posts (lists and so on)
More rigorous input checking in events.py
Poll vote highlights entire option Poll vote highlights entire option
Total voters per poll Total voters per poll
Chat archives Chat archives