Repository: apluslms/a-plus

Issue:
Feature request: send email when teacher adds news
Hi

It would be very nice to be able to notify students via email when teacher adds news. This should be an option so the teacher could decide on case-by-case basis whether to send the email or not.

What do you think?

Thanks!
Feature request: send email when teacher adds news
Hi

It would be very nice to be able to notify students via email when teacher adds news. This should be an option so the teacher could decide on case-by-case basis whether to send the email or not.

What do you think?

Thanks!


Discussion:
About notifications from my memory from previous thinking.

levels:
 * priority
 * important
 * not so imporant

notification settings per student:
 * student can state do they receive email from different notification levels or should they get dggest oer day for example

notification sources:
 * grader can define notification level for the feedback notification
 * different other notification sources have opinion to be higher than normal (e.g. one level up)
 * priority is recerved for really high importance stuff, so students would most of the time keep email notifications for it, or that level could be always forced (only if there is less than few emails per year).
About notifications from my memory from previous thinking.

levels:
 * priority
 * important
 * not so imporant

notification settings per student:
 * student can state do they receive email from different notification levels or should they get dggest oer day for example

notification sources:
 * grader can define notification level for the feedback notification
 * different other notification sources have opinion to be higher than normal (e.g. one level up)
 * priority is recerved for really high importance stuff, so students would most of the time keep email notifications for it, or that level could be always forced (only if there is less than few emails per year).

Resolving patch:
diff --git a/lib/email_messages.py b/lib/email_messages.py
--- a/lib/email_messages.py
+++ b/lib/email_messages.py
@@ -1,9 +1,10 @@
 import logging
 import traceback
 from django.conf import settings
-from django.core.mail import send_mail
-from django.urls import reverse
-from .helpers import build_aplus_url
+from django.core.mail import send_mail, send_mass_mail
+
+from .helpers import Enum, build_aplus_url
+from course.models import CourseInstance
 
 
 logger = logging.getLogger('aplus.lib.email_messages')
@@ -61,3 +62,30 @@ def email_course_error(request, exercise, message, exception=True):
         email_course_instance(instance, subject, body)
     except:
         pass
+
+
+def email_course_students(
+        instance: CourseInstance,
+        subject: str,
+        message: str,
+        audience: Enum = CourseInstance.ENROLLMENT_AUDIENCE.ALL_USERS,
+        ) -> int:
+    """
+    Sends an email to students on the course. Audience parameter controls whether the mail goes
+    to all (default), just internal, or just external students.
+    Returns number of emails sent, or -1 in case of error.
+    """
+    students = instance.students
+    if audience == CourseInstance.ENROLLMENT_AUDIENCE.INTERNAL_USERS:
+        students = students.filter(organization=settings.LOCAL_ORGANIZATION)
+    elif audience == CourseInstance.ENROLLMENT_AUDIENCE.EXTERNAL_USERS:
+        students = students.exclude(organization=settings.LOCAL_ORGANIZATION)
+
+    recipients = students.exclude(user__email='').values_list("user__email", flat=True)
+    emails = tuple(map(lambda x: (subject, message, settings.SERVER_EMAIL, [x]), recipients))
+
+    try:
+        return send_mass_mail(emails)
+    except:
+        logger.exception('Failed to send course instance emails.')
+        return -1
diff --git a/news/forms.py b/news/forms.py
--- a/news/forms.py
+++ b/news/forms.py
@@ -1,16 +1,25 @@
+from typing import Any
+
 from django import forms
+from django.utils.translation import gettext_lazy as _
 
 from .models import News
 
 
 class NewsForm(forms.ModelForm):
 
+    email = forms.BooleanField(
+        required=False,
+        label=_("SEND_EMAIL_TO_STUDENTS"),
+    )
+
     class Meta:
         model = News
         fields = [
             'audience',
             'publish',
             'pin',
+            'email',
             'title',
             'body',
         ]
diff --git a/news/views.py b/news/views.py
--- a/news/views.py
+++ b/news/views.py
@@ -1,10 +1,14 @@
+from django.conf import settings
+from django.contrib import messages
 from django.core.exceptions import PermissionDenied
 from django.http import Http404
 from django.shortcuts import get_object_or_404
+from django.utils.translation import gettext_lazy as _
 
 from authorization.permissions import ACCESS
 from course.viewbase import CourseInstanceBaseView, CourseInstanceMixin
 from lib.viewbase import BaseFormView, BaseRedirectView
+from lib.email_messages import email_course_students
 from .forms import NewsForm
 from .models import News
 
@@ -47,6 +51,15 @@ def get_success_url(self):
 
     def form_valid(self, form):
         form.save()
+        if form.cleaned_data['email']:
+            subject = f"[{settings.BRAND_NAME} course news] {self.instance.course.code}: {self.news_item.title}"
+            if email_course_students(
+                self.instance,
+                subject,
+                self.news_item.body,
+                self.news_item.audience,
+            ) < 0:
+                messages.error(self.request, _('FAILED_TO_SEND_EMAIL'))
         return super().form_valid(form)
 
 


Test patch: