280 lines
13 KiB
Python
280 lines
13 KiB
Python
from celery import current_app
|
|
from django.contrib import messages
|
|
from django.shortcuts import redirect, render
|
|
from django.utils import timezone
|
|
|
|
from .branding import get_default_notification_templates
|
|
from .models import NotificationTemplate, ScheduledWelcomeEmail, WorkflowConfig
|
|
from .tasks import send_scheduled_welcome_email
|
|
|
|
|
|
def welcome_emails_page_impl(request):
|
|
rows = ScheduledWelcomeEmail.objects.select_related('onboarding_request').order_by('-send_at', '-id')[:200]
|
|
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
|
welcome_template = NotificationTemplate.objects.filter(key='onboarding_welcome').first()
|
|
default_welcome = get_default_notification_templates().get('onboarding_welcome', {})
|
|
default_subject = (default_welcome.get('subject') or '').strip()
|
|
default_body = (default_welcome.get('body') or '').strip()
|
|
default_subject_en = (default_welcome.get('subject_en') or '').strip()
|
|
default_body_en = (default_welcome.get('body_en') or '').strip()
|
|
subject_value = (welcome_template.subject_template if welcome_template else '').strip() or default_subject
|
|
body_value = (welcome_template.body_template if welcome_template else '').strip() or default_body
|
|
subject_value_en = (welcome_template.subject_template_en if welcome_template else '').strip() or default_subject_en
|
|
body_value_en = (welcome_template.body_template_en if welcome_template else '').strip() or default_body_en
|
|
return render(
|
|
request,
|
|
'workflows/welcome_emails.html',
|
|
{
|
|
'rows': rows,
|
|
'workflow_config': config,
|
|
'welcome_template': welcome_template,
|
|
'welcome_subject_value': subject_value,
|
|
'welcome_body_value': body_value,
|
|
'welcome_subject_value_en': subject_value_en,
|
|
'welcome_body_value_en': body_value_en,
|
|
'welcome_keywords': ['{{ FULL_NAME }}', '{{ VORNAME }}', '{{ NACHNAME }}', '{{ DEPARTMENT }}', '{{ CONTRACT_START }}', '{{ EMAIL }}', '{{ REQUESTED_BY }}'],
|
|
},
|
|
)
|
|
|
|
|
|
def trigger_welcome_email_now_impl(request, schedule_id: int, *, audit_fn, send_task_fn=send_scheduled_welcome_email):
|
|
scheduled = ScheduledWelcomeEmail.objects.filter(id=schedule_id).first()
|
|
if not scheduled:
|
|
messages.error(request, f'Geplanter Welcome-Eintrag #{schedule_id} nicht gefunden.')
|
|
return redirect('welcome_emails_page')
|
|
if scheduled.status == 'cancelled':
|
|
messages.error(request, f'Welcome E-Mail #{schedule_id} ist abgebrochen und kann nicht gesendet werden.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
async_result = send_task_fn.delay(scheduled.id, True)
|
|
scheduled.celery_task_id = async_result.id or scheduled.celery_task_id
|
|
scheduled.status = 'scheduled'
|
|
scheduled.last_error = ''
|
|
scheduled.save(update_fields=['celery_task_id', 'status', 'last_error', 'updated_at'])
|
|
audit_fn(request, 'welcome_email_triggered_now', target_type='welcome_email', target_id=scheduled.id, target_label=scheduled.recipient_email)
|
|
messages.success(request, f'Welcome E-Mail #{schedule_id} wurde sofort angestoßen.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
|
|
def save_welcome_email_settings_impl(request, *, audit_fn):
|
|
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
|
try:
|
|
delay_days = int(request.POST.get('welcome_email_delay_days', config.welcome_email_delay_days or 5))
|
|
except ValueError:
|
|
messages.error(request, 'Ungültige Zahl bei der Welcome-Verzögerung.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
config.welcome_email_delay_days = max(0, delay_days)
|
|
config.welcome_sender_email = request.POST.get('welcome_sender_email', '').strip()
|
|
config.welcome_include_pdf = request.POST.get('welcome_include_pdf') == 'on'
|
|
config.save(update_fields=['welcome_email_delay_days', 'welcome_sender_email', 'welcome_include_pdf'])
|
|
|
|
subject = request.POST.get('welcome_subject')
|
|
body = request.POST.get('welcome_body')
|
|
subject_en = request.POST.get('welcome_subject_en')
|
|
body_en = request.POST.get('welcome_body_en')
|
|
if subject is not None or body is not None or subject_en is not None or body_en is not None:
|
|
default_welcome = get_default_notification_templates().get('onboarding_welcome', {})
|
|
default_subject = (default_welcome.get('subject') or '').strip()
|
|
default_body = (default_welcome.get('body') or '').strip()
|
|
default_subject_en = (default_welcome.get('subject_en') or '').strip()
|
|
default_body_en = (default_welcome.get('body_en') or '').strip()
|
|
subject_clean = (subject or '').strip() or default_subject
|
|
body_clean = (body or '').strip() or default_body
|
|
subject_clean_en = (subject_en or '').strip() or default_subject_en
|
|
body_clean_en = (body_en or '').strip() or default_body_en
|
|
template, _ = NotificationTemplate.objects.get_or_create(
|
|
key='onboarding_welcome',
|
|
defaults={
|
|
'subject_template': subject_clean,
|
|
'body_template': body_clean,
|
|
'subject_template_en': subject_clean_en,
|
|
'body_template_en': body_clean_en,
|
|
'is_active': True,
|
|
},
|
|
)
|
|
changes = []
|
|
if template.subject_template != subject_clean:
|
|
template.subject_template = subject_clean
|
|
changes.append('subject_template')
|
|
if template.body_template != body_clean:
|
|
template.body_template = body_clean
|
|
changes.append('body_template')
|
|
if template.subject_template_en != subject_clean_en:
|
|
template.subject_template_en = subject_clean_en
|
|
changes.append('subject_template_en')
|
|
if template.body_template_en != body_clean_en:
|
|
template.body_template_en = body_clean_en
|
|
changes.append('body_template_en')
|
|
if not template.is_active:
|
|
template.is_active = True
|
|
changes.append('is_active')
|
|
if changes:
|
|
template.save(update_fields=changes)
|
|
|
|
audit_fn(
|
|
request,
|
|
'welcome_email_settings_saved',
|
|
target_type='welcome_email_settings',
|
|
target_label='onboarding_welcome',
|
|
details={
|
|
'delay_days': config.welcome_email_delay_days,
|
|
'sender_email': config.welcome_sender_email,
|
|
'include_pdf': config.welcome_include_pdf,
|
|
},
|
|
)
|
|
messages.success(request, 'Welcome-E-Mail Einstellungen wurden gespeichert.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
|
|
def _revoke_celery_task(task_id: str) -> None:
|
|
if not task_id:
|
|
return
|
|
try:
|
|
current_app.control.revoke(task_id, terminate=False)
|
|
except Exception:
|
|
return
|
|
|
|
|
|
def _parse_selected_schedule_ids(raw: str) -> list[int]:
|
|
if not raw:
|
|
return []
|
|
parsed: list[int] = []
|
|
seen: set[int] = set()
|
|
for token in raw.split(','):
|
|
token = token.strip()
|
|
if not token:
|
|
continue
|
|
try:
|
|
schedule_id = int(token)
|
|
except ValueError:
|
|
continue
|
|
if schedule_id in seen:
|
|
continue
|
|
seen.add(schedule_id)
|
|
parsed.append(schedule_id)
|
|
return parsed
|
|
|
|
|
|
def bulk_welcome_email_action_impl(request, *, audit_fn, send_task_fn=send_scheduled_welcome_email):
|
|
action = (request.POST.get('bulk_action') or '').strip().lower()
|
|
selected_ids = _parse_selected_schedule_ids(request.POST.get('selected_ids', ''))
|
|
|
|
if action not in {'pause', 'send_now', 'delete'}:
|
|
messages.error(request, 'Ungültige Bulk-Aktion.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
if not selected_ids:
|
|
messages.warning(request, 'Keine Welcome-Einträge ausgewählt.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
rows = list(ScheduledWelcomeEmail.objects.filter(id__in=selected_ids).order_by('id'))
|
|
if not rows:
|
|
messages.warning(request, 'Keine passenden Welcome-Einträge gefunden.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
success_count = 0
|
|
skipped_count = 0
|
|
|
|
for scheduled in rows:
|
|
if action == 'pause':
|
|
if scheduled.status in {'sent', 'cancelled'}:
|
|
skipped_count += 1
|
|
continue
|
|
_revoke_celery_task(scheduled.celery_task_id)
|
|
scheduled.status = 'paused'
|
|
scheduled.save(update_fields=['status', 'updated_at'])
|
|
success_count += 1
|
|
continue
|
|
|
|
if action == 'send_now':
|
|
if scheduled.status == 'cancelled':
|
|
skipped_count += 1
|
|
continue
|
|
async_result = send_task_fn.delay(scheduled.id, True)
|
|
scheduled.celery_task_id = async_result.id or scheduled.celery_task_id
|
|
scheduled.status = 'scheduled'
|
|
scheduled.last_error = ''
|
|
scheduled.save(update_fields=['celery_task_id', 'status', 'last_error', 'updated_at'])
|
|
success_count += 1
|
|
continue
|
|
|
|
if action == 'delete':
|
|
if scheduled.status == 'scheduled':
|
|
_revoke_celery_task(scheduled.celery_task_id)
|
|
scheduled.delete()
|
|
success_count += 1
|
|
|
|
action_label = {
|
|
'pause': 'pausiert',
|
|
'send_now': 'sofort angestoßen',
|
|
'delete': 'gelöscht',
|
|
}[action]
|
|
if success_count:
|
|
audit_fn(
|
|
request,
|
|
'welcome_email_bulk_action',
|
|
target_type='welcome_email',
|
|
target_label=action,
|
|
details={'selected_ids': selected_ids, 'success_count': success_count, 'skipped_count': skipped_count},
|
|
)
|
|
messages.success(request, f'{success_count} Welcome-Eintrag/Einträge {action_label}.')
|
|
if skipped_count:
|
|
messages.warning(request, f'{skipped_count} Eintrag/Einträge wurden übersprungen (Status nicht geeignet).')
|
|
return redirect('welcome_emails_page')
|
|
|
|
|
|
def pause_welcome_email_impl(request, schedule_id: int, *, audit_fn):
|
|
scheduled = ScheduledWelcomeEmail.objects.filter(id=schedule_id).first()
|
|
if not scheduled:
|
|
messages.error(request, f'Geplanter Welcome-Eintrag #{schedule_id} nicht gefunden.')
|
|
return redirect('welcome_emails_page')
|
|
if scheduled.status in {'sent', 'cancelled'}:
|
|
messages.error(request, f'Welcome E-Mail #{schedule_id} kann nicht pausiert werden.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
_revoke_celery_task(scheduled.celery_task_id)
|
|
scheduled.status = 'paused'
|
|
scheduled.save(update_fields=['status', 'updated_at'])
|
|
audit_fn(request, 'welcome_email_paused', target_type='welcome_email', target_id=scheduled.id, target_label=scheduled.recipient_email)
|
|
messages.success(request, f'Welcome E-Mail #{schedule_id} wurde pausiert.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
|
|
def resume_welcome_email_impl(request, schedule_id: int, *, audit_fn, send_task_fn=send_scheduled_welcome_email):
|
|
scheduled = ScheduledWelcomeEmail.objects.filter(id=schedule_id).first()
|
|
if not scheduled:
|
|
messages.error(request, f'Geplanter Welcome-Eintrag #{schedule_id} nicht gefunden.')
|
|
return redirect('welcome_emails_page')
|
|
if scheduled.status != 'paused':
|
|
messages.error(request, f'Welcome E-Mail #{schedule_id} ist nicht pausiert.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
eta = scheduled.send_at if timezone.now() < scheduled.send_at else None
|
|
async_result = send_task_fn.apply_async(args=[scheduled.id], eta=eta)
|
|
scheduled.celery_task_id = async_result.id or scheduled.celery_task_id
|
|
scheduled.status = 'scheduled'
|
|
scheduled.last_error = ''
|
|
scheduled.save(update_fields=['celery_task_id', 'status', 'last_error', 'updated_at'])
|
|
audit_fn(request, 'welcome_email_resumed', target_type='welcome_email', target_id=scheduled.id, target_label=scheduled.recipient_email)
|
|
messages.success(request, f'Welcome E-Mail #{schedule_id} wurde fortgesetzt.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
|
|
def cancel_welcome_email_impl(request, schedule_id: int, *, audit_fn):
|
|
scheduled = ScheduledWelcomeEmail.objects.filter(id=schedule_id).first()
|
|
if not scheduled:
|
|
messages.error(request, f'Geplanter Welcome-Eintrag #{schedule_id} nicht gefunden.')
|
|
return redirect('welcome_emails_page')
|
|
if scheduled.status == 'sent':
|
|
messages.error(request, f'Welcome E-Mail #{schedule_id} wurde bereits gesendet.')
|
|
return redirect('welcome_emails_page')
|
|
|
|
_revoke_celery_task(scheduled.celery_task_id)
|
|
scheduled.status = 'cancelled'
|
|
scheduled.last_error = ''
|
|
scheduled.save(update_fields=['status', 'last_error', 'updated_at'])
|
|
audit_fn(request, 'welcome_email_cancelled', target_type='welcome_email', target_id=scheduled.id, target_label=scheduled.recipient_email)
|
|
messages.success(request, f'Welcome E-Mail #{schedule_id} wurde abgebrochen.')
|
|
return redirect('welcome_emails_page')
|