Add result and statistics data to reminder job

This commit is contained in:
Daniel Egger 2023-08-25 18:21:48 +02:00
parent 5790fac78f
commit f6a01b3ad1
2 changed files with 95 additions and 44 deletions

View File

@ -1,3 +1,4 @@
from collections import Counter
from datetime import timedelta from datetime import timedelta
import structlog import structlog
@ -21,8 +22,8 @@ PRESENCE_COURSE_REMINDER_LEAD_TIME = timedelta(weeks=2)
def send_attendance_course_reminder_notification( def send_attendance_course_reminder_notification(
recipient: User, attendance_course: CourseSessionAttendanceCourse recipient: User, attendance_course: CourseSessionAttendanceCourse
): ) -> str:
NotificationService.send_information_notification( return NotificationService.send_information_notification(
recipient=recipient, recipient=recipient,
verb=_("Erinnerung: Bald findet ein Präsenzkurs statt"), verb=_("Erinnerung: Bald findet ein Präsenzkurs statt"),
target_url=attendance_course.learning_content.get_frontend_url(), target_url=attendance_course.learning_content.get_frontend_url(),
@ -37,26 +38,52 @@ def attendance_course_reminder_notification_job():
"""Checks if an attendance course is coming up and sends a reminder to the participants""" """Checks if an attendance course is coming up and sends a reminder to the participants"""
start = timezone.now() start = timezone.now()
end = timezone.now() + PRESENCE_COURSE_REMINDER_LEAD_TIME end = timezone.now() + PRESENCE_COURSE_REMINDER_LEAD_TIME
logger.info( results_counter = Counter()
"Querying for attendance courses in specified time range",
start_time=start,
end_time=end,
)
attendance_courses = CourseSessionAttendanceCourse.objects.filter( attendance_courses = CourseSessionAttendanceCourse.objects.filter(
due_date__start__lte=end, due_date__start__lte=end,
due_date__start__gte=start, due_date__start__gte=start,
) )
logger.info(
"Querying for attendance courses in specified time range",
start_time=start,
end_time=end,
label="attendance_course_reminder_notification_job",
num_attendance_courses=len(attendance_courses),
)
for attendance_course in attendance_courses: for attendance_course in attendance_courses:
cs_id = attendance_course.course_session.id cs_id = attendance_course.course_session.id
csu = CourseSessionUser.objects.filter(course_session_id=cs_id) csu = CourseSessionUser.objects.filter(course_session_id=cs_id)
logger.info(
"Sending attendance course reminder notification",
start_time=start,
end_time=end,
label="attendance_course_reminder_notification_job",
num_users=len(csu),
course_session_id=cs_id,
)
for user in csu: for user in csu:
send_attendance_course_reminder_notification(user.user, attendance_course) result = send_attendance_course_reminder_notification(
user.user, attendance_course
)
results_counter[result] += 1
if not attendance_courses: if not attendance_courses:
logger.info("No attendance courses found") logger.info(
"No attendance courses found",
label="attendance_course_reminder_notification_job",
)
return dict(results_counter)
class Command(LoggedCommand): class Command(LoggedCommand):
help = "Sends attendance course reminder notifications to participants" help = "Sends attendance course reminder notifications to participants"
def handle(self, *args, **options): def handle(self, *args, **options):
attendance_course_reminder_notification_job() results = attendance_course_reminder_notification_job()
self.job_log.json_data = results
self.job_log.save()
logger.info(
"Attendance course reminder notification job finished",
label="attendance_course_reminder_notification_job",
results=results,
)

View File

@ -21,8 +21,8 @@ class NotificationService:
target_url: str, target_url: str,
email_template: EmailTemplate, email_template: EmailTemplate,
template_data: dict = None, template_data: dict = None,
) -> None: ) -> str:
cls._send_notification( return cls._send_notification(
recipient=recipient, recipient=recipient,
verb=verb, verb=verb,
sender=sender, sender=sender,
@ -42,8 +42,8 @@ class NotificationService:
target_url: str, target_url: str,
email_template: EmailTemplate, email_template: EmailTemplate,
template_data: dict = None, template_data: dict = None,
) -> None: ) -> str:
cls._send_notification( return cls._send_notification(
recipient=recipient, recipient=recipient,
verb=verb, verb=verb,
course=course, course=course,
@ -61,8 +61,8 @@ class NotificationService:
target_url: str, target_url: str,
email_template: EmailTemplate, email_template: EmailTemplate,
template_data: dict = None, template_data: dict = None,
) -> None: ) -> str:
cls._send_notification( return cls._send_notification(
recipient=recipient, recipient=recipient,
verb=verb, verb=verb,
target_url=target_url, target_url=target_url,
@ -82,10 +82,13 @@ class NotificationService:
sender: User | None = None, sender: User | None = None,
course: str | None = None, course: str | None = None,
target_url: str | None = None, target_url: str | None = None,
) -> None: fail_silently: bool = True,
) -> str:
if template_data is None: if template_data is None:
template_data = {} template_data = {}
notification_identifier = f"{notification_type.name}_{email_template.name}"
actor_avatar_url: Optional[str] = None actor_avatar_url: Optional[str] = None
if not sender: if not sender:
sender = User.objects.get(email="admin") sender = User.objects.get(email="admin")
@ -100,32 +103,42 @@ class NotificationService:
target_url=target_url, target_url=target_url,
template_data=template_data, template_data=template_data,
) )
if NotificationService._is_duplicate_notification(
recipient=recipient,
verb=verb,
notification_type=notification_type,
target_url=target_url,
template_name=email_template.name,
template_data=template_data,
):
log.info("A duplicate notification was omitted from being sent")
return
emailed = False emailed = False
if cls._should_send_email(notification_type, recipient):
log.debug("Try to send email")
emailed = cls._send_email(
recipient=recipient,
template=email_template,
template_data={
"target_url": f"https://my.vbv-afa.ch{target_url}",
**template_data,
},
)
else:
log.debug("Should not send email")
try: try:
if NotificationService._is_duplicate_notification(
recipient=recipient,
verb=verb,
notification_type=notification_type,
target_url=target_url,
template_name=email_template.name,
template_data=template_data,
):
log.info("A duplicate notification was omitted from being sent")
return f"{notification_identifier}_duplicate"
if cls._should_send_email(notification_type, recipient):
log.debug("Try to send email")
try:
emailed = cls._send_email(
recipient=recipient,
template=email_template,
template_data={
"target_url": f"https://my.vbv-afa.ch{target_url}",
**template_data,
},
fail_silently=False,
)
except Exception as e:
notification_identifier += "_email_error"
if not fail_silently:
raise e
return notification_identifier
if emailed:
notification_identifier += "_emailed"
else:
log.debug("Should not send email")
response = notify.send( response = notify.send(
sender=sender, sender=sender,
recipient=recipient, recipient=recipient,
@ -141,10 +154,19 @@ class NotificationService:
sent_notification.course = course sent_notification.course = course
sent_notification.actor_avatar_url = actor_avatar_url sent_notification.actor_avatar_url = actor_avatar_url
sent_notification.save() sent_notification.save()
except Exception as e:
log.error("Failed to send notification", exception=str(e))
else:
log.info("Notification sent successfully", emailed=emailed) log.info("Notification sent successfully", emailed=emailed)
return f"{notification_identifier}_success"
except Exception as e:
log.error(
"Failed to send notification",
exception=str(e),
exc_info=True,
stack_info=True,
emailed=emailed,
)
if not fail_silently:
raise e
return f"{notification_identifier}_error"
@staticmethod @staticmethod
def _should_send_email( def _should_send_email(
@ -159,12 +181,14 @@ class NotificationService:
recipient: User, recipient: User,
template: EmailTemplate, template: EmailTemplate,
template_data: dict, template_data: dict,
fail_silently: bool = True,
) -> bool: ) -> bool:
return send_email( return send_email(
recipient_email=recipient.email, recipient_email=recipient.email,
template=template, template=template,
template_data=template_data, template_data=template_data,
template_language=recipient.language, template_language=recipient.language,
fail_silently=fail_silently,
) )
@staticmethod @staticmethod