From 1a21c882a2c54c5b2fcdb1c85cf4c7bca8b34b3a Mon Sep 17 00:00:00 2001 From: iou1name Date: Wed, 29 Aug 2018 14:01:31 -0400 Subject: [PATCH] added poll posting --- quest/events.py | 53 +++++++++++++++++++-- quest/forms.py | 19 ++++++++ quest/jinja2/quest/quest.html | 14 +++--- quest/migrations/0010_auto_20180829_1308.py | 47 ++++++++++++++++++ quest/models.py | 37 +++++++++++++- quest/static/questQM.js | 12 +++++ quest/views.py | 4 +- 7 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 quest/migrations/0010_auto_20180829_1308.py diff --git a/quest/events.py b/quest/events.py index 5352162..c6212f6 100644 --- a/quest/events.py +++ b/quest/events.py @@ -12,8 +12,8 @@ import random import bleach from django.utils.timezone import localtime -from quest.models import Message, Quest, Post, DiceCall, DiceRoll -from quest.forms import DiceCallForm +from quest.models import * +from quest.forms import DiceCallForm, PollForm def message(socket, data): """ @@ -209,10 +209,53 @@ def dice_post(socket, data): dc.save() data = {} - data['post_text'] = post_text - data['post_type'] = 'dice' - data['date'] = localtime(p.timestamp).strftime('%Y-%m-%d %H:%M') data['post_id'] = p.id + data['post_type'] = 'dice' + data['post_text'] = post_text + data['date'] = localtime(p.timestamp).strftime('%Y-%m-%d %H:%M') + socket.send('new_post', data) + + +def poll_post(socket, data): + """ + Called when the QM makes a new dice post. + """ + quest_id = data.get('quest_id') + page_num = data.get('page_num') + form = PollForm(data) + if not form.is_valid(): + return # error message? + form = form.cleaned_data + + p = Post( + quest=Quest.objects.get(id=quest_id), + page_num=page_num, + post_type='poll', + post_text="Poll" + ) + p.save() + pl = Poll( + post=p, + multi_choice=form.pop('multi_choice'), + allow_writein=form.pop('allow_writein'), + open=True + ) + pl.save() + options = [] + for key, option in form.items(): + o = PollOption( + poll=pl, + text=option + ) + o.save() + options.append(o) + + data = {} + data['post_type'] = 'poll' + data['post_id'] = p.id + data['post_text'] = "Poll" + data['date'] = localtime(p.timestamp).strftime('%Y-%m-%d %H:%M') + data['options'] = [o.text for o in options] socket.send('new_post', data) diff --git a/quest/forms.py b/quest/forms.py index 463fef6..335f402 100644 --- a/quest/forms.py +++ b/quest/forms.py @@ -17,3 +17,22 @@ class DiceCallForm(forms.Form): diceRollsTaken = forms.IntegerField( min_value=1, max_value=99, required=False) diceStrict = forms.BooleanField(required=False) + + +class PollForm(forms.Form): + """ + The form for the QM making new polls. + """ + multi_choice = forms.BooleanField(required=False) + allow_writein = forms.BooleanField(required=False) + + def __init__(self, *args, **kwargs): + super(PollForm, self).__init__(*args, **kwargs) + data = args[0] # it's not nice to assume + options = {k: v for k, v in data.items() if k.startswith('pollOption')} + if len(options) > 20: + return + for key, value in options.items(): + if not value: + continue + self.fields[key] = forms.CharField(max_length=200) diff --git a/quest/jinja2/quest/quest.html b/quest/jinja2/quest/quest.html index 4983e3a..90d2df8 100644 --- a/quest/jinja2/quest/quest.html +++ b/quest/jinja2/quest/quest.html @@ -68,16 +68,16 @@ {% elif post.post_type == "poll" %}

{{ post.post_text }} - {% if post.poll.open %}Open{% else %}Closed{% endif %}

- {# for option in options.get(post.id, []) %} - + {% for option in poll_options.filter(poll=post.poll) %} + - - + + - {% endfor #} + {% endfor %}
- - + + {{ option[2] }}{{ poll_votes.get(option[0], [])|length }}{{ option.text }}{# poll_votes.get(option[0], [])|length #}
{# if post.id == quest.open_post_id and post.id|is_write_in %}
diff --git a/quest/migrations/0010_auto_20180829_1308.py b/quest/migrations/0010_auto_20180829_1308.py new file mode 100644 index 0000000..f9d0020 --- /dev/null +++ b/quest/migrations/0010_auto_20180829_1308.py @@ -0,0 +1,47 @@ +# Generated by Django 2.1 on 2018-08-29 17:08 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('quest', '0009_diceroll'), + ] + + operations = [ + migrations.CreateModel( + name='Poll', + fields=[ + ('post', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='quest.Post')), + ('multi_choice', models.BooleanField()), + ('allow_writein', models.BooleanField()), + ('open', models.BooleanField()), + ], + ), + migrations.CreateModel( + name='PollOption', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=200)), + ('poll', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quest.Poll')), + ], + ), + migrations.CreateModel( + name='PollVote', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip_address', models.GenericIPAddressField()), + ('option', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quest.PollOption')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AlterField( + model_name='dicecall', + name='open', + field=models.BooleanField(), + ), + ] diff --git a/quest/models.py b/quest/models.py index 610cd16..bc0e15b 100644 --- a/quest/models.py +++ b/quest/models.py @@ -73,7 +73,7 @@ class DiceCall(models.Model): MinValueValidator(1) ] ) - open = models.BooleanField(default=False) + open = models.BooleanField() class DiceRoll(models.Model): @@ -91,6 +91,41 @@ class DiceRoll(models.Model): total = models.IntegerField() +class Poll(models.Model): + """ + An object representing polls made by the QM. + """ + post = models.OneToOneField( + Post, + on_delete=models.CASCADE, + primary_key=True, + ) + multi_choice = models.BooleanField() + allow_writein = models.BooleanField() + open = models.BooleanField() + + +class PollOption(models.Model): + """ + Represents options (choices) attached to a given poll. These can be + added by the QM upon creation, or by users through write-ins. + """ + poll = models.ForeignKey(Poll, on_delete=models.CASCADE) + text = models.CharField(max_length=200) + + +class PollVote(models.Model): + """ + Represents a user voting for an option. + """ + option = models.ForeignKey(PollOption, on_delete=models.CASCADE) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE + ) + ip_address = models.GenericIPAddressField() + + class PageTitle(models.Model): """ Represents the title of a quest page. diff --git a/quest/static/questQM.js b/quest/static/questQM.js index 3f0d7fc..b2a4698 100644 --- a/quest/static/questQM.js +++ b/quest/static/questQM.js @@ -139,3 +139,15 @@ function open_post(post_id) { } } } +function insertPollOption() { + let opts = document.getElementById('pollOptions'); + let num = opts.children.length+1; + let temp = document.createElement('template'); + temp.innerHTML = '
'; + opts.appendChild(temp.content); +} +function removePollOption() { + let opts = document.getElementById('pollOptions'); + if (opts.children.length == 0) { return; } + opts.children[opts.children.length-1].outerHTML = ''; +} diff --git a/quest/views.py b/quest/views.py index 2e825c6..fb58656 100644 --- a/quest/views.py +++ b/quest/views.py @@ -5,7 +5,7 @@ Quest and quest accessory views. from django.shortcuts import render from django.http import HttpResponse -from .models import Quest, DiceRoll +from .models import Quest, DiceRoll, PollOption, PollVote def index(request): """ @@ -23,5 +23,7 @@ def quest(request, quest_id, page_num=1): messages = quest.message_set.all() posts = quest.post_set.all() dice_rolls = DiceRoll.objects.filter(dicecall__post__quest__id=quest_id) + poll_options = PollOption.objects.filter(poll__post__quest__id=quest_id) + poll_votes = PollVote.objects.filter(option__poll__post__quest__id=quest_id) context = locals() return render(request, 'quest/quest.html', context)