119 lines
5.0 KiB
Python
119 lines
5.0 KiB
Python
import os
|
|
import sys
|
|
import django
|
|
|
|
# Set up Django
|
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
|
django.setup()
|
|
|
|
from core.models import Voter, ScheduledCall
|
|
from django.db.models.signals import pre_save, post_save, post_delete
|
|
from django.dispatch import receiver
|
|
|
|
# New pre_save signal
|
|
def handle_voter_status_on_voted_pre_save(sender, instance, **kwargs):
|
|
if instance.voted:
|
|
instance.target_door_visit = False
|
|
instance.call_queue_status = 'no_call_required'
|
|
|
|
# I will append this to the file instead of monkey patching if possible,
|
|
# but for now I'll just write the whole signal part.
|
|
|
|
# Let's read models.py and replace the signals with better ones.
|
|
with open('core/models.py', 'r') as f:
|
|
content = f.read()
|
|
|
|
# 1. Add pre_save signal before the other signals
|
|
new_pre_save = """
|
|
@receiver(pre_save, sender=Voter)
|
|
def handle_voter_status_on_voted_pre_save(sender, instance, **kwargs):
|
|
\"\"\"
|
|
If a voter has voted, ensure they are not targets for door visits or calls.
|
|
\"\"\"
|
|
if instance.voted:
|
|
instance.target_door_visit = False
|
|
instance.call_queue_status = 'no_call_required'
|
|
"""
|
|
|
|
if '@receiver(pre_save, sender=Voter)' not in content:
|
|
# Insert before the first post_save
|
|
content = content.replace('@receiver(post_save, sender=Voter)', new_pre_save + '\n@receiver(post_save, sender=Voter)', 1)
|
|
|
|
# 2. Update update_voter_call_queue_status_on_voter_save
|
|
import re
|
|
|
|
old_call_signal = re.search(r'def update_voter_call_queue_status_on_voter_save\(sender, instance, \*\*kwargs\):.*?return', content, re.DOTALL)
|
|
# Actually, it's better to just replace the whole function content.
|
|
|
|
new_call_signal_body = """def update_voter_call_queue_status_on_voter_save(sender, instance, **kwargs):
|
|
\"\"\"
|
|
Sync call_queue_status when is_targeted, candidate_support or voted changes.
|
|
\"\"\"
|
|
if getattr(instance, '_skip_signals', False):
|
|
return
|
|
|
|
orig = getattr(instance, '_orig_obj', None)
|
|
if orig and instance.call_queue_status != orig.call_queue_status:
|
|
# If call_queue_status was manually changed, don't auto-override in this save
|
|
return
|
|
|
|
update_fields = kwargs.get('update_fields')
|
|
if update_fields:
|
|
relevant = {'is_targeted', 'candidate_support', 'voted'}
|
|
if not relevant.intersection(update_fields):
|
|
return
|
|
|
|
# PRIORITY 1: If they voted, no call required and cancel pending calls
|
|
if instance.voted:
|
|
# Cancel any pending calls
|
|
ScheduledCall.objects.filter(voter=instance, status='pending').update(status='cancelled')
|
|
|
|
if instance.call_queue_status != 'no_call_required':
|
|
Voter.objects.filter(pk=instance.pk).update(call_queue_status='no_call_required')
|
|
return
|
|
|
|
# PRIORITY 2: Check if in queue (pending scheduled call)
|
|
if ScheduledCall.objects.filter(voter=instance, status='pending').exists():
|
|
if instance.call_queue_status != 'in_call_queue':
|
|
Voter.objects.filter(pk=instance.pk).update(call_queue_status='in_call_queue')
|
|
return
|
|
|
|
# PRIORITY 3: If support is 'supporting', then 'no_call_required'
|
|
if instance.candidate_support == 'supporting':
|
|
if instance.call_queue_status != 'no_call_required':
|
|
Voter.objects.filter(pk=instance.pk).update(call_queue_status='no_call_required')
|
|
return
|
|
|
|
# PRIORITY 4: If un-targeted, set to no_call_required
|
|
if not instance.is_targeted:
|
|
if instance.call_queue_status != 'no_call_required':
|
|
Voter.objects.filter(pk=instance.pk).update(call_queue_status='no_call_required')
|
|
else:
|
|
# If targeted, and currently no_call_required, set to to_be_called
|
|
if instance.call_queue_status == 'no_call_required':
|
|
Voter.objects.filter(pk=instance.pk).update(call_queue_status='to_be_called')"""
|
|
|
|
# Use regex to replace the function
|
|
content = re.sub(r'def update_voter_call_queue_status_on_voter_save\(sender, instance, \*\*kwargs\):.*?# PRIORITY 3: If targeted, and currently no_call_required, set to to_be_called.*?Voter.objects.filter\(pk=instance.pk\).update\(call_queue_status=\'to_be_called\'\)', new_call_signal_body, content, flags=re.DOTALL)
|
|
|
|
# 3. Update update_voter_call_queue_status_on_call_save to check voted
|
|
new_call_save_body = """def update_voter_call_queue_status_on_call_save(sender, instance, **kwargs):
|
|
\"\"\"
|
|
Sync Voter.call_queue_status when a ScheduledCall is saved.
|
|
\"\"\"
|
|
voter = instance.voter
|
|
|
|
# PRIORITY 0: If they voted, always no_call_required
|
|
if voter.voted:
|
|
if voter.call_queue_status != 'no_call_required':
|
|
voter.call_queue_status = 'no_call_required'
|
|
voter.save(update_fields=['call_queue_status'])
|
|
return"""
|
|
|
|
content = content.replace('def update_voter_call_queue_status_on_call_save(sender, instance, **kwargs):\n \"\"\"\n Sync Voter.call_queue_status when a ScheduledCall is saved.\n \"\"\"\n voter = instance.voter', new_call_save_body)
|
|
|
|
with open('core/models.py', 'w') as f:
|
|
f.write(content)
|
|
|
|
print("Updated core/models.py with more robust signals.")
|