## Waitlist workflow

+
+## Waitlist emails <a name="emails"></a>
+
+It is also possible to send email to all attendees on the
+waitlist. This can be filtered to be all on waitlist, or just the ones
+with or without offers.
+
+Unlike [attendee emails](emails) these are sent directly but are not
+archived on the registration pages or similar, as these are to
+accounts that have not yet got a registration.
+
+If wanted, the position on the waitlist and/or the size of the
+waitlist can be included. If this is selected, a sentence about it
+will be added as a footer of the email.
raise ValidationError("At least one registration must be selected to make an offer")
return self.cleaned_data
+class WaitlistSendmailForm(forms.Form):
+ TARGET_ALL=0
+ TARGET_OFFERS=1
+ TARGET_NOOFFERS=2
+
+ TARGET_CHOICES = (
+ (TARGET_ALL, 'All attendees on waitlist'),
+ (TARGET_OFFERS, 'Only attendees with active offers'),
+ (TARGET_NOOFFERS, 'Only attendees without active offers'),
+ )
+
+ POSITION_NONE=0
+ POSITION_FULL=1
+ POSITION_ONLY=2
+ POSITION_SIZE=3
+ POSITION_CHOICES = (
+ (POSITION_NONE, 'No position information'),
+ (POSITION_FULL, 'Both position and size of waitlist'),
+ (POSITION_ONLY, 'Only position on waitlist'),
+ (POSITION_SIZE, 'Only size of waitlist'),
+ )
+
+ waitlist_target = forms.ChoiceField(required=True, choices=TARGET_CHOICES)
+ subject = forms.CharField(max_length=100, required=True)
+ message = forms.CharField(required=True, widget=forms.Textarea)
+ include_position = forms.ChoiceField(required=True, choices=POSITION_CHOICES,
+ help_text="Include a footer with information about waitpost position and/or size")
+ confirm = forms.BooleanField(help_text="Confirm that you are ready to send this email!", required=False)
+
+ def __init__(self, conference, *args, **kwargs):
+ self.conference = conference
+ super(WaitlistSendmailForm, self).__init__(*args, **kwargs)
+ if not (self.data.get('subject') and self.data.get('message')):
+ del self.fields['confirm']
+ self.fields['subject'].help_text = u"Will be prefixed by [{0}]".format(conference.conferencename)
+
+ def clean_confirm(self):
+ if not self.cleaned_data['confirm']:
+ raise ValidationError("Please check this box to confirm that you are really sending this email! There is no going back!")
+
class TransferRegForm(forms.Form):
transfer_from = forms.ModelChoiceField(ConferenceRegistration.objects.filter(id=-1))
transfer_to = forms.ModelChoiceField(ConferenceRegistration.objects.filter(id=-1))
from forms import CallForPapersForm, CallForPapersSpeakerForm
from forms import CallForPapersCopyForm, PrepaidCreateForm, BulkRegistrationForm
from forms import EmailSendForm, EmailSessionForm, CrossConferenceMailForm
-from forms import AttendeeMailForm, WaitlistOfferForm, TransferRegForm
+from forms import AttendeeMailForm, WaitlistOfferForm, WaitlistSendmailForm, TransferRegForm
from forms import NewMultiRegForm, MultiRegInvoiceForm
from forms import SessionSlidesUrlForm, SessionSlidesFileForm
from util import invoicerows_for_registration, notify_reg_confirmed, InvoicerowsException
return HttpResponseRedirect("../../")
+def admin_waitlist_sendmail(request, urlname):
+ conference = get_authenticated_conference(request, urlname)
+
+ if request.method == 'POST':
+ form = WaitlistSendmailForm(conference, data=request.POST)
+ if form.is_valid():
+ with transaction.atomic():
+ q = RegistrationWaitlistEntry.objects.filter(registration__conference=conference,
+ registration__payconfirmedat__isnull=True)
+ tot = q.all().count()
+ if not tot:
+ messages.warning(request, "Waitlist was empty, no email was sent.")
+ return HttpResponseRedirect('../')
+
+ if int(form.cleaned_data['waitlist_target']) == form.TARGET_OFFERS:
+ q = q.filter(offeredon__isnull=False)
+ elif int(form.cleaned_data['waitlist_target']) == form.TARGET_NOOFFERS:
+ q = q.filter(offeredon__isnull=True)
+
+ n = 0
+ for w in q.order_by('enteredon'):
+ n += 1
+
+ msgbody = form.cleaned_data['message']
+ if int(form.cleaned_data['include_position']) == form.POSITION_FULL:
+ msgbody += "\n\nYour position on the waitlist is {0} of {1}.\n".format(n, tot)
+ elif int(form.cleaned_data['include_position']) == form.POSITION_ONLY:
+ msgbody += "\n\nYour position on the waitlist is {0}.\n".format(n)
+ elif int(form.cleaned_data['include_position']) == form.POSITION_SIZE:
+ msgbody += "\n\nThe current size of the waitlist is {0}.\n".format(tot)
+
+ send_simple_mail(conference.contactaddr,
+ conference.contactaddr,
+ u"[{0}] {1}".format(conference.conferencename, form.cleaned_data['subject']),
+ msgbody,
+ sendername=conference.conferencename,
+ receivername=w.registration.fullname)
+ if n:
+ messages.info(request, "Sent {0} emails.".format(tot))
+ else:
+ messages.warning(request, "No matching waitlist entries, no email was sent.")
+ return HttpResponseRedirect('../')
+ else:
+ form = WaitlistSendmailForm(conference)
+
+ return render(request, 'confreg/admin_waitlist_sendmail.html', {
+ 'conference': conference,
+ 'form': form,
+ 'helplink': 'waitlist#emails',
+ 'breadcrumbs': (('/events/admin/{0}/waitlist/'.format(conference.urlname), 'Waitlist'),),
+ })
+
+
@transaction.atomic
def admin_attendeemail(request, urlname):
conference = get_authenticated_conference(request, urlname)
url(r'^events/admin/([^/]+)/sessionnotifyqueue/$', postgresqleu.confreg.views.session_notify_queue),
url(r'^events/admin/(\w+)/waitlist/$', postgresqleu.confreg.views.admin_waitlist),
url(r'^events/admin/(\w+)/waitlist/cancel/(\d+)/$', postgresqleu.confreg.views.admin_waitlist_cancel),
+ url(r'^events/admin/(\w+)/waitlist/sendmail/$', postgresqleu.confreg.views.admin_waitlist_sendmail),
url(r'^events/admin/(\w+)/wiki/$', postgresqleu.confwiki.views.admin),
url(r'^events/admin/(\w+)/wiki/(new|\d+)/$', postgresqleu.confwiki.views.admin_edit_page),
url(r'^events/admin/(\w+)/signups/$', postgresqleu.confwiki.views.signup_admin),
<p>The waitlist is currently empty</p>
{%endif%}
+{%if waitlist%}
+<h3>Operations</h3>
+<a class="btn btn-default" href="sendmail/">Send waitlist email</a>
+{%endif%}
+
<h3>Processed waitlist</h3>
{%with waitlist=waitlist_cleared%}
{%include "confreg/admin_waitlist_list.inc.html"%}
--- /dev/null
+{%extends "confreg/confadmin_base.html"%}
+{%block title%}Send waitlist email{%endblock%}
+{%block layoutblock%}
+<h1>Send waitlist email</h1>
+<form class="form-horizontal" method="POST" action="." enctype="multipart/form-data">{%csrf_token%}
+{%include "confreg/admin_backend_form_content.html" %}
+</form>
+{%endblock%}