From f6a01b3ad1fde998ea0f0ce38ce26715068a9281 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Fri, 25 Aug 2023 18:21:48 +0200 Subject: [PATCH] Add result and statistics data to reminder job --- .../send_attendance_course_reminders.py | 47 ++++++++-- server/vbv_lernwelt/notify/services.py | 92 ++++++++++++------- 2 files changed, 95 insertions(+), 44 deletions(-) diff --git a/server/vbv_lernwelt/notify/management/commands/send_attendance_course_reminders.py b/server/vbv_lernwelt/notify/management/commands/send_attendance_course_reminders.py index 19c81b8a..7e6dd80c 100644 --- a/server/vbv_lernwelt/notify/management/commands/send_attendance_course_reminders.py +++ b/server/vbv_lernwelt/notify/management/commands/send_attendance_course_reminders.py @@ -1,3 +1,4 @@ +from collections import Counter from datetime import timedelta import structlog @@ -21,8 +22,8 @@ PRESENCE_COURSE_REMINDER_LEAD_TIME = timedelta(weeks=2) def send_attendance_course_reminder_notification( recipient: User, attendance_course: CourseSessionAttendanceCourse -): - NotificationService.send_information_notification( +) -> str: + return NotificationService.send_information_notification( recipient=recipient, verb=_("Erinnerung: Bald findet ein Präsenzkurs statt"), 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""" start = timezone.now() end = timezone.now() + PRESENCE_COURSE_REMINDER_LEAD_TIME - logger.info( - "Querying for attendance courses in specified time range", - start_time=start, - end_time=end, - ) + results_counter = Counter() attendance_courses = CourseSessionAttendanceCourse.objects.filter( due_date__start__lte=end, 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: cs_id = attendance_course.course_session.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: - 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: - 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): help = "Sends attendance course reminder notifications to participants" 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, + ) diff --git a/server/vbv_lernwelt/notify/services.py b/server/vbv_lernwelt/notify/services.py index af329da7..c4b5c8bb 100644 --- a/server/vbv_lernwelt/notify/services.py +++ b/server/vbv_lernwelt/notify/services.py @@ -21,8 +21,8 @@ class NotificationService: target_url: str, email_template: EmailTemplate, template_data: dict = None, - ) -> None: - cls._send_notification( + ) -> str: + return cls._send_notification( recipient=recipient, verb=verb, sender=sender, @@ -42,8 +42,8 @@ class NotificationService: target_url: str, email_template: EmailTemplate, template_data: dict = None, - ) -> None: - cls._send_notification( + ) -> str: + return cls._send_notification( recipient=recipient, verb=verb, course=course, @@ -61,8 +61,8 @@ class NotificationService: target_url: str, email_template: EmailTemplate, template_data: dict = None, - ) -> None: - cls._send_notification( + ) -> str: + return cls._send_notification( recipient=recipient, verb=verb, target_url=target_url, @@ -82,10 +82,13 @@ class NotificationService: sender: User | None = None, course: str | None = None, target_url: str | None = None, - ) -> None: + fail_silently: bool = True, + ) -> str: if template_data is None: template_data = {} + notification_identifier = f"{notification_type.name}_{email_template.name}" + actor_avatar_url: Optional[str] = None if not sender: sender = User.objects.get(email="admin") @@ -100,32 +103,42 @@ class NotificationService: target_url=target_url, 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 - 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: + 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( sender=sender, recipient=recipient, @@ -141,10 +154,19 @@ class NotificationService: sent_notification.course = course sent_notification.actor_avatar_url = actor_avatar_url sent_notification.save() - except Exception as e: - log.error("Failed to send notification", exception=str(e)) - else: 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 def _should_send_email( @@ -159,12 +181,14 @@ class NotificationService: recipient: User, template: EmailTemplate, template_data: dict, + fail_silently: bool = True, ) -> bool: return send_email( recipient_email=recipient.email, template=template, template_data=template_data, template_language=recipient.language, + fail_silently=fail_silently, ) @staticmethod