each specific option, as well as the total value calculated from
weighted values. Below it there will also be a complete list of every
individual response.
+
+## Editing attendee signups
+
+Normally, the attendees should handle their own signups, and they
+should never be edited.
+
+However, it is sometimes required that the administrator edit them,
+for example if the deadline has passed, and an attendee needs to
+change their response.
+
+All responses that have been recorded can be edited. In a signup that
+only has yes/no as the answer, the no responses are not recorded, so
+changing a record to no will remove it. For both types of signups it
+is always possible to remove an entry.
+
+If the signup is *not public*, it is also possible to add a new
+response (for example if an attendee never signed up, but reported
+their attendance via email or phone or other means). Duplicate
+responses are of course not allowed.
from django import forms
from django.core.exceptions import ValidationError
+from django.db.models import Q
from postgresqleu.confreg.models import RegistrationType, ConferenceRegistration
-from models import Wikipage, Signup
+from models import Wikipage, Signup, AttendeeSignup
class WikipageEditForm(forms.ModelForm):
class Meta:
model = Signup
exclude = ['conference', ]
+class SignupAdminEditSignupForm(forms.ModelForm):
+ choice = forms.ChoiceField(required=True)
+ class Meta:
+ model = AttendeeSignup
+ fields = ['attendee', 'choice', ]
+
+ def __init__(self, signup, *args, **kwargs):
+ self.signup = signup
+ self.isnew = kwargs.pop('isnew')
+ super(SignupAdminEditSignupForm, self).__init__(*args, **kwargs)
+
+ if self.isnew:
+ self.fields['attendee'].queryset = ConferenceRegistration.objects.filter(conference=signup.conference).filter(
+ Q(user_attendees=signup) | Q(regtype__user_regtypes=signup)).exclude(attendeesignup__signup=signup).distinct()
+ else:
+ del self.fields['attendee']
+
+ if signup.options:
+ choices = signup.options.split(',')
+ self.fields['choice'].choices = [(k,k) for k in choices]
+ self.fields['choice'].choices.insert(0, ('', ''))
+ else:
+ # This one is boolean only
+ self.fields['choice'].choices = (('', ''), ('yes','Yes'), ('', 'No'), )
+ self.fields['choice'].required = False
class SignupSendmailForm(forms.Form):
_recipient_choices = [
from models import Signup, AttendeeSignup
from forms import SignupSubmitForm, SignupAdminEditForm, SignupSendmailForm
+from forms import SignupAdminEditSignupForm
@login_required
def wikipage(request, confurl, wikiurl):
})
sumresults = cursor.fetchall()
results['summary'] = [dict(zip(['choice', 'num', 'percentwidth'], r)) for r in sumresults]
- cursor.execute("SELECT firstname || ' ' || lastname,choice,saved FROM confreg_conferenceregistration r INNER JOIN confwiki_attendeesignup s ON r.id=s.attendee_id WHERE s.signup_id=%(signup)s ORDER BY saved", {
+ cursor.execute("SELECT s.id, firstname || ' ' || lastname,choice,saved FROM confreg_conferenceregistration r INNER JOIN confwiki_attendeesignup s ON r.id=s.attendee_id WHERE s.signup_id=%(signup)s ORDER BY saved", {
'signup': signup.id,
})
- results['details'] = [dict(zip(['name', 'choice', 'when'], r)) for r in cursor.fetchall()]
+ results['details'] = [dict(zip(['id', 'name', 'choice', 'when'], r)) for r in cursor.fetchall()]
if signup.optionvalues:
optionstrings = signup.options.split(',')
optionvalues = [int(x) for x in signup.optionvalues.split(',')]
'helplink': 'signups',
})
+@transaction.atomic
+def signup_admin_editsignup(request, urlname, signupid, id):
+ conference = get_authenticated_conference(request, urlname)
+ signup = get_object_or_404(Signup, conference=conference, pk=signupid)
+
+ if id == 'new':
+ attendeesignup = AttendeeSignup(signup=signup)
+ else:
+ attendeesignup = get_object_or_404(AttendeeSignup, signup=signup, pk=id)
+
+ if request.method == 'POST' and request.POST['submit'] == 'Delete':
+ attendeesignup.delete()
+ return HttpResponseRedirect('../../')
+ elif request.method == 'POST':
+ form = SignupAdminEditSignupForm(signup, isnew=(id == 'new'), instance=attendeesignup, data=request.POST)
+ if form.is_valid():
+ if (not signup.options) and (not form.cleaned_data['choice']):
+ # Yes/no signup changed to no means we actually delete the
+ # record completeliy.
+ attendeesignup.delete()
+ else:
+ form.save()
+ return HttpResponseRedirect('../../')
+ else:
+ form = SignupAdminEditSignupForm(signup, isnew=(id == 'new'), instance=attendeesignup)
+
+ return render(request, 'confreg/admin_backend_form.html', {
+ 'conference': conference,
+ 'form': form,
+ 'what': 'attendee signup',
+ 'cancelurl': '../../',
+ 'allow_delete': (id != 'new'),
+ 'breadcrumbs': (
+ ('/events/admin/{0}/signups/'.format(conference.urlname), 'Signups'),
+ ('/events/admin/{0}/signups/{1}/'.format(conference.urlname, signup.id), signup.title),
+ ),
+ 'helplink': 'signups',
+ })
@transaction.atomic
def signup_admin_sendmail(request, urlname, signupid):
url(r'^events/admin/(\w+)/signups/$', postgresqleu.confwiki.views.signup_admin),
url(r'^events/admin/(\w+)/signups/(new|\d+)/$', postgresqleu.confwiki.views.signup_admin_edit),
url(r'^events/admin/(\w+)/signups/(\d+)/sendmail/$', postgresqleu.confwiki.views.signup_admin_sendmail),
+ url(r'^events/admin/(\w+)/signups/(\d+)/edit/(new|\d+)/$', postgresqleu.confwiki.views.signup_admin_editsignup),
url(r'^events/admin/(\w+)/transfer/$', postgresqleu.confreg.views.transfer_reg),
url(r'^events/admin/(?P<urlname>[^/]+)/volunteer/', include(postgresqleu.confreg.volsched), {'adm': True}),
url(r'^events/admin/(\w+)/regdays/(.*/)?$', postgresqleu.confreg.backendviews.edit_regdays),
<td>{{r.name}}</td>
<td>{{r.choice}}</td>
<td>{{r.when}}</td>
+ <td><a class="btn btn-xs btn-default" href="edit/{{r.id}}/">edit</a></td>
</tr>
{%endfor%}
</table>
+{%if not signup.public%}
+<a class="btn btn-xs btn-default" href="edit/new/">Add new</a>
+{%endif%}
{%if results.awaiting%}
<h3>Awaiting response</h3>