members/waitinglist: waiting list confirmation reminders

individual-sender-address
Christian Merten 1 year ago
parent fd29fa6199
commit 57b4d517b1
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -52,7 +52,8 @@ Wenn du weiterhin auf der Warteliste bleiben möchtest, klicke auf den folgenden
{link} {link}
Falls du nicht mehr auf der Warteliste bleiben möchtest, musst du nichts machen. Du wirst automatisch entfernt. Das ist Erinnerung Nummer {reminder} von {max_reminder_count}. Nach Erinnerung Nummer {max_reminder_count} wirst
du automatisch entfernt.
Viele Grüße Viele Grüße
Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION } Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION }

@ -34,6 +34,8 @@ ADMINS = (('admin', 'christian@merten-moser.de'),)
GRACE_PERIOD_WAITING_CONFIRMATION = 30 GRACE_PERIOD_WAITING_CONFIRMATION = 30
WAITING_CONFIRMATION_FREQUENCY = 90 WAITING_CONFIRMATION_FREQUENCY = 90
CONFIRMATION_REMINDER_FREQUENCY = 30
MAX_REMINDER_COUNT = 3
# testing # testing

@ -414,13 +414,14 @@ class WaiterInviteForm(forms.Form):
class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin): class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin):
fields = ['prename', 'lastname', 'email', 'birth_date', 'gender', 'application_text', fields = ['prename', 'lastname', 'email', 'birth_date', 'gender', 'application_text',
'application_date', 'comments', 'invited_for_group'] 'application_date', 'comments', 'invited_for_group',
'sent_reminders']
list_display = ('name', 'birth_date', 'age', 'application_date', 'confirmed_mail', list_display = ('name', 'birth_date', 'age', 'application_date', 'confirmed_mail',
'waiting_confirmed') 'waiting_confirmed', 'sent_reminders')
search_fields = ('prename', 'lastname', 'email') search_fields = ('prename', 'lastname', 'email')
list_filter = ('confirmed_mail',) list_filter = ('confirmed_mail',)
actions = ['ask_for_registration', 'ask_for_wait_confirmation'] actions = ['ask_for_registration', 'ask_for_wait_confirmation']
readonly_fields= ['invited_for_group', 'application_date'] readonly_fields= ['invited_for_group', 'application_date', 'sent_reminders']
def has_add_permission(self, request, obj=None): def has_add_permission(self, request, obj=None):
return False return False

@ -0,0 +1,23 @@
# Generated by Django 4.0.1 on 2024-10-27 19:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('members', '0018_group_add_times'),
]
operations = [
migrations.AddField(
model_name='memberwaitinglist',
name='last_reminder',
field=models.DateTimeField(auto_now=True, verbose_name='Last reminder'),
),
migrations.AddField(
model_name='memberwaitinglist',
name='sent_reminders',
field=models.IntegerField(default=0, verbose_name='Missed reminders'),
),
]

@ -704,6 +704,9 @@ class MemberWaitingList(Person):
wait_confirmation_key = models.CharField(max_length=32, default="") wait_confirmation_key = models.CharField(max_length=32, default="")
wait_confirmation_key_expire = models.DateTimeField(default=timezone.now) wait_confirmation_key_expire = models.DateTimeField(default=timezone.now)
last_reminder = models.DateTimeField(auto_now=True, verbose_name=_('Last reminder'))
sent_reminders = models.IntegerField(default=0, verbose_name=_('Missed reminders'))
registration_key = models.CharField(max_length=32, default="") registration_key = models.CharField(max_length=32, default="")
registration_expire = models.DateTimeField(default=timezone.now) registration_expire = models.DateTimeField(default=timezone.now)
@ -728,7 +731,8 @@ class MemberWaitingList(Person):
def waiting_confirmation_needed(self): def waiting_confirmation_needed(self):
"""Returns if person should be asked to confirm waiting status.""" """Returns if person should be asked to confirm waiting status."""
return wait_confirmation_key is None \ return wait_confirmation_key is None \
and last_wait_confirmation < timezone.now() - timezone.timedelta(days=90) and last_wait_confirmation < timezone.now() -\
timezone.timedelta(days=settings.WAITING_CONFIRMATION_FREQUENCY)
def waiting_confirmed(self): def waiting_confirmed(self):
"""Returns if the persons waiting status is considered to be confirmed.""" """Returns if the persons waiting status is considered to be confirmed."""
@ -742,9 +746,14 @@ class MemberWaitingList(Person):
def ask_for_wait_confirmation(self): def ask_for_wait_confirmation(self):
"""Sends an email to the person asking them to confirm their intention to wait.""" """Sends an email to the person asking them to confirm their intention to wait."""
self.last_reminder = datetime.now()
self.sent_reminders += 1
self.save()
self.send_mail(_('Waiting confirmation needed'), self.send_mail(_('Waiting confirmation needed'),
settings.WAIT_CONFIRMATION_TEXT.format(name=self.prename, settings.WAIT_CONFIRMATION_TEXT.format(name=self.prename,
link=get_wait_confirmation_link(self))) link=get_wait_confirmation_link(self),
reminder=self.sent_reminders,
max_reminder_count=settings.MAX_REMINDER_COUNT))
def confirm_waiting(self, key): def confirm_waiting(self, key):
# if a wrong key is supplied, we return invalid # if a wrong key is supplied, we return invalid
@ -755,6 +764,7 @@ class MemberWaitingList(Person):
if timezone.now() < self.wait_confirmation_key_expire: if timezone.now() < self.wait_confirmation_key_expire:
self.last_wait_confirmation = timezone.now() self.last_wait_confirmation = timezone.now()
self.wait_confirmation_key_expire = timezone.now() self.wait_confirmation_key_expire = timezone.now()
self.sent_reminders = 0
self.save() self.save()
return self.WAITING_CONFIRMATION_SUCCESS return self.WAITING_CONFIRMATION_SUCCESS

@ -5,6 +5,16 @@ from .models import MemberWaitingList
@shared_task @shared_task
def ask_for_waiting_confirmation(): def ask_for_waiting_confirmation():
reminder_cutoff = timezone.now() - timezone.timedelta(days=settings.CONFIRMATION_REMINDER_FREQUENCY)
cutoff = timezone.now() - timezone.timedelta(days=settings.WAITING_CONFIRMATION_FREQUENCY) cutoff = timezone.now() - timezone.timedelta(days=settings.WAITING_CONFIRMATION_FREQUENCY)
for waiter in MemberWaitingList.objects.filter(last_wait_confirmation__lte=cutoff): no = 0
# we ask all waiters for wait confirmation whose last confirmed waiting status is at least
# settings.WAITING_CONFIRMATION_FREQUENCY days ago, who have not received a reminder
# in the last settings.CONFIRMATION_REMINDER_FREQUENCY days and
# who have yet received strictly less reminders then settings.MAX_REMINDER_COUNT.
for waiter in MemberWaitingList.objects.filter(last_wait_confirmation__lte=cutoff,
last_reminder__lte=reminder_cutoff,
sent_reminders__lt=settings.MAX_REMINDER_COUNT):
waiter.ask_for_wait_confirmation() waiter.ask_for_wait_confirmation()
no += 1
return no

Loading…
Cancel
Save