Repository: e-valuation/EvaP

Issue:
Send publish notification only if user can see results
Currently an email is sent to all participants and contributors of a course when the course is getting published. This email should only be sent to users who can actually see any results (grades or comments).

Send publish notification only if user can see results
Currently an email is sent to all participants and contributors of a course when the course is getting published. This email should only be sent to users who can actually see any results (grades or comments).



Discussion:
@Nef10: How is the current state? Do you want to continue working on this issue? It would be nice, but if not - could you give me your current state so that I can take over?

No new things after our discussion at the hackday. I´m also unable to push the branch because my mac is still in repair

@Nef10: How is the current state? Do you want to continue working on this issue? It would be nice, but if not - could you give me your current state so that I can take over?

No new things after our discussion at the hackday. I´m also unable to push the branch because my mac is still in repair


Resolving patch:
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -755,45 +755,36 @@ def send_to_users_in_courses(self, courses, recipient_groups):
                     user_course_map.setdefault(user, []).append(course)
 
         for user, courses in user_course_map.items():
-            cc_users = []
-            if ("responsible" in recipient_groups or "editors" in recipient_groups) and any(course.is_user_editor(user) for course in courses):
-                cc_users += user.delegates.all()
-            cc_users += user.cc_users.all()
-            cc_addresses = [p.email for p in cc_users if p.email]
-
-            mail = EmailMessage(
-                subject = self.render_string(self.subject, {'user': user, 'courses': courses}),
-                body = self.render_string(self.body, {'user': user, 'courses': courses}),
-                to = [user.email],
-                cc = cc_addresses,
-                bcc = [a[1] for a in settings.MANAGERS],
-                headers = {'Reply-To': settings.REPLY_TO_EMAIL})
-            mail.send(False)
+            self.send_to_user(user, courses)
 
-    @classmethod
-    def send_reminder_to_user(cls, user, due_in_number_of_days, due_courses):
+    def send_to_user(self, user, courses=None):
         if not user.email:
             return
 
-        template = cls.get_reminder_template()        
-        subject = template.render_string(template.subject, {'user': user, 'due_in_number_of_days': due_in_number_of_days})
-        body = template.render_string(template.body, {'user': user, 'due_in_number_of_days': due_in_number_of_days, 'due_courses': due_courses})
+        cc_users = set(user.delegates.all() | user.cc_users.all())
+        cc_addresses = [p.email for p in cc_users if p.email]
 
         mail = EmailMessage(
-            subject = subject,
-            body = body,
+            subject = self.render_string(self.subject, {'user': user, 'courses': courses}),
+            body = self.render_string(self.body, {'user': user, 'courses': courses}),
             to = [user.email],
+            cc = cc_addresses,
             bcc = [a[1] for a in settings.MANAGERS],
             headers = {'Reply-To': settings.REPLY_TO_EMAIL})
         mail.send(False)
 
-    def send_to_user(self, user):
+    @classmethod
+    def send_reminder_to_user(cls, user, due_in_number_of_days, due_courses):
         if not user.email:
             return
 
+        template = cls.get_reminder_template()        
+        subject = template.render_string(template.subject, {'user': user, 'due_in_number_of_days': due_in_number_of_days})
+        body = template.render_string(template.body, {'user': user, 'due_in_number_of_days': due_in_number_of_days, 'due_courses': due_courses})
+
         mail = EmailMessage(
-            subject = self.render_string(self.subject, {'user': user}),
-            body = self.render_string(self.body, {'user': user}),
+            subject = subject,
+            body = body,
             to = [user.email],
             bcc = [a[1] for a in settings.MANAGERS],
             headers = {'Reply-To': settings.REPLY_TO_EMAIL})
diff --git a/evap/evaluation/tools.py b/evap/evaluation/tools.py
--- a/evap/evaluation/tools.py
+++ b/evap/evaluation/tools.py
@@ -4,7 +4,7 @@
 from django.utils.translation import ugettext_lazy as _
 from evap.evaluation.models import LikertAnswer, TextAnswer, GradeAnswer
 
-from collections import OrderedDict
+from collections import OrderedDict, defaultdict
 from collections import namedtuple
 
 LIKERT_NAMES = {
@@ -327,3 +327,23 @@ def create_contributor_questionnaires(form_groups_items):
                 errors.append(contributor.id)
 
     return contributor_questionnaires, errors
+
+
+def user_publish_notifications(courses):
+    user_notifications = defaultdict(set)
+    for course in courses:
+        # for published courses all contributors and participants get a notification
+        if course.can_publish_grades():
+            for participant in course.participants.all():
+                user_notifications[participant].add(course)
+            for contribution in course.contributions.all():
+                if contribution.contributor:
+                    user_notifications[contribution.contributor].add(course)
+        # if a course was not published notifications are only sent for contributors who can see comments
+        elif len(course.textanswer_set) > 0:
+            for textanswer in course.textanswer_set:
+                if textanswer.contribution.contributor:
+                    user_notifications[textanswer.contribution.contributor].add(course)
+            user_notifications[course.responsible_contributor].add(course)
+
+    return user_notifications
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -11,7 +11,7 @@
 from evap.evaluation.auth import staff_required
 from evap.evaluation.models import Contribution, Course, Question, Questionnaire, Semester, \
                                    TextAnswer, UserProfile, FaqSection, FaqQuestion, EmailTemplate
-from evap.evaluation.tools import questionnaires_and_contributions, STATES_ORDERED
+from evap.evaluation.tools import questionnaires_and_contributions, STATES_ORDERED, user_publish_notifications
 from evap.staff.forms import ContributionForm, AtLeastOneFormSet, ReviewTextAnswerForm, CourseForm, \
                            CourseEmailForm, EmailTemplateForm, IdLessQuestionFormSet, ImportForm, \
                            LotteryForm, QuestionForm, QuestionnaireForm, QuestionnairesAssignForm, \
@@ -127,12 +127,14 @@ def semester_publish(request, semester_id):
                 course.publish()
                 course.save()
                 selected_courses.append(course)
-
-        try:
-            EmailTemplate.get_publish_template().send_to_users_in_courses(selected_courses, ['contributors', 'all_participants'])
-        except Exception:
-            messages.error(request, _("Could not send emails to participants and contributors"))
         messages.success(request, _("Successfully published %d courses.") % (len(selected_courses)))
+
+        for user, courses in user_publish_notifications(selected_courses).iteritems():
+            try:
+                EmailTemplate.get_publish_template().send_to_user(user, courses=list(courses))
+            except Exception:
+                messages.error(request, _("Could not send notification email to ") + user.username)
+        
         return redirect('evap.staff.views.semester_view', semester_id)
     else:
         return render(request, "staff_semester_publish.html", dict(semester=semester, forms=forms))


Test patch: