From: Magnus Hagander Date: Mon, 9 Jul 2018 14:09:25 +0000 (+0200) Subject: Attempt to simplify talk voting pages X-Git-Url: http://git.postgresql.org/gitweb/static/%7B%7Bpgdulink%28?a=commitdiff_plain;h=b26e096ea54ac7e5b6abc2f1deb1e6530855217f;p=pgeu-website.git Attempt to simplify talk voting pages This merges a couple of changes: 1. Each individual vote is cast by selection in dropdown and is immediately ajax-posted to the backend, so there is no huge save button for everything that risks overwriting other fields. Changing the vote will automatically update the average value based on the changes (and other changes made by others). 2. No dedicated text-edit box for own comments. Instead, own comments are listed alongside other comments, and there is an edit button that brings up a popup and lets the comment be edited. 3. No popup windows for talk descriptions. Instead, accordions are used, so clicking the title will expand the description in-line. This also makes it a lot easier to handle things like copy/paste from the descriptions. --- diff --git a/postgresqleu/confreg/views.py b/postgresqleu/confreg/views.py index 05560ad..8c02f24 100644 --- a/postgresqleu/confreg/views.py +++ b/postgresqleu/confreg/views.py @@ -8,13 +8,13 @@ from django.contrib.auth.models import User from django.contrib import messages from django.conf import settings from django.db import transaction, connection -from django.db.models import Q, Count +from django.db.models import Q, Count, Avg from django.db.models.expressions import F from django.forms import formsets from django.forms import ValidationError from models import Conference, ConferenceRegistration, ConferenceSession -from models import ConferenceSessionSlides, GlobalOptOut +from models import ConferenceSessionSlides, ConferenceSessionVote, GlobalOptOut from models import ConferenceSessionFeedback, Speaker, Speaker_Photo from models import ConferenceFeedbackQuestion, ConferenceFeedbackAnswer from models import RegistrationType, PrepaidVoucher, PrepaidBatch @@ -2088,28 +2088,6 @@ def talkvote(request, confname): curs = connection.cursor() - if request.method=='POST': - # Record votes - # We could probably do this with some fancy writable CTEs, but - # this code won't run often, so we don't really care about being - # fast, and this is easier... - # Thus, remove existing entries and replace them with current ones. - curs.execute("DELETE FROM confreg_conferencesessionvote WHERE voter_id=%(userid)s AND session_id IN (SELECT id FROM confreg_conferencesession WHERE conference_id=%(confid)s)", { - 'confid': conference.id, - 'userid': request.user.id, - }) - curs.executemany("INSERT INTO confreg_conferencesessionvote (session_id, voter_id, vote, comment) VALUES (%(sid)s, %(vid)s, %(vote)s, %(comment)s)", [ - { - 'sid': k[3:], - 'vid': request.user.id, - 'vote': int(v) > 0 and int(v) or None, - 'comment': request.POST['tc_%s' % k[3:]], - } - for k,v in request.POST.items() if k.startswith("sv_") and (int(v)>0 or request.POST['tc_%s' % k[3:]]) - ]) - - return HttpResponseRedirect(".") - order = "" if request.GET.has_key("sort"): if request.GET["sort"] == "avg": @@ -2202,6 +2180,46 @@ def talkvote_status(request, confname): session.status!=session.lastnotifiedstatus and 1 or 0, ), content_type='text/plain') +@login_required +@transaction.atomic +def talkvote_vote(request, confname): + conference = get_object_or_404(Conference, urlname=confname) + if not conference.talkvoters.filter(pk=request.user.id): + return HttpResponse('You are not a talk voter for this conference!') + if request.method!='POST': + return HttpResponse('Can only use POST') + + session = get_object_or_404(ConferenceSession, conference=conference, id=request.POST['sessionid']) + v = int(request.POST['vote']) + if v > 0: + vote,created = ConferenceSessionVote.objects.get_or_create(session=session, voter=request.user) + vote.vote = v + vote.save() + else: + ConferenceSessionVote.objects.filter(session=session, voter=request.user).delete() + + # Re-calculate the average + avg = session.conferencesessionvote_set.all().aggregate(Avg('vote'))['vote__avg'] + if avg is None: + avg = 0 + return HttpResponse("{0:.2f}".format(avg), content_type='text/plain') + +@login_required +@transaction.atomic +def talkvote_comment(request, confname): + conference = get_object_or_404(Conference, urlname=confname) + if not conference.talkvoters.filter(pk=request.user.id): + return HttpResponse('You are not a talk voter for this conference!') + if request.method!='POST': + return HttpResponse('Can only use POST') + + session = get_object_or_404(ConferenceSession, conference=conference, id=request.POST['sessionid']) + vote,created = ConferenceSessionVote.objects.get_or_create(session=session, voter=request.user) + vote.comment = request.POST['comment'] + vote.save() + + return HttpResponse(vote.comment, content_type='text/plain') + @login_required @csrf_exempt @transaction.atomic diff --git a/postgresqleu/urls.py b/postgresqleu/urls.py index 555ec09..e03b1c5 100644 --- a/postgresqleu/urls.py +++ b/postgresqleu/urls.py @@ -77,6 +77,8 @@ urlpatterns = [ url(r'^events/(?P[^/]+)/volunteer/', include(postgresqleu.confreg.volsched)), url(r'^events/([^/]+)/talkvote/$', postgresqleu.confreg.views.talkvote), url(r'^events/([^/]+)/talkvote/changestatus/$', postgresqleu.confreg.views.talkvote_status), + url(r'^events/([^/]+)/talkvote/vote/$', postgresqleu.confreg.views.talkvote_vote), + url(r'^events/([^/]+)/talkvote/comment/$', postgresqleu.confreg.views.talkvote_comment), url(r'^events/([^/]+)/sessions/$', postgresqleu.confreg.views.sessionlist), url(r'^events/speaker/(\d+)/photo/$', postgresqleu.confreg.views.speakerphoto), url(r'^events/([^/]+)/speakerprofile/$', postgresqleu.confreg.views.speakerprofile), diff --git a/template/confreg/sessionvotes.html b/template/confreg/sessionvotes.html index aa32f85..f698a9d 100644 --- a/template/confreg/sessionvotes.html +++ b/template/confreg/sessionvotes.html @@ -7,13 +7,13 @@