Exemplo n.º 1
0
def index(request):
    """Main entry page into EvaP providing all the login options available. The username/password
       login is thought to be used for internal users, e.g. by connecting to a LDAP directory.
       The login key mechanism is meant to be used to include external participants, e.g. visiting
       students or visiting contributors.
    """

    # parse the form data into the respective form
    submit_type = request.POST.get("submit_type", "no_submit")
    new_key_form = NewKeyForm(request.POST if submit_type == "new_key" else None)
    login_username_form = LoginUsernameForm(request, request.POST if submit_type == "login_username" else None)

    # process form data
    if request.method == 'POST':
        if new_key_form.is_valid():
            # user wants a new login key
            profile = new_key_form.get_user()
            profile.ensure_valid_login_key()
            profile.save()

            EmailTemplate.send_login_url_to_user(new_key_form.get_user())

            messages.success(request, _("We sent you an email with a one-time login URL. Please check your inbox."))
            return redirect('evaluation:index')
        elif login_username_form.is_valid():
            # user would like to login with username and password and passed password test
            auth.login(request, login_username_form.get_user())

            # clean up our test cookie
            if request.session.test_cookie_worked():
                request.session.delete_test_cookie()

    # if not logged in by now, render form
    if not request.user.is_authenticated:
        # set test cookie to verify whether they work in the next step
        request.session.set_test_cookie()

        template_data = dict(new_key_form=new_key_form, login_username_form=login_username_form)
        return render(request, "index.html", template_data)
    else:
        user, __ = UserProfile.objects.get_or_create(username=request.user.username)

        # check for redirect variable
        redirect_to = request.GET.get("next", None)
        if redirect_to is not None:
            return redirect(redirect_to)

        # redirect user to appropriate start page
        if request.user.is_reviewer:
            return redirect('staff:semester_view', Semester.active_semester().id)
        if request.user.is_staff:
            return redirect('staff:index')
        elif request.user.is_grade_publisher:
            return redirect('grades:semester_view', Semester.active_semester().id)
        elif user.is_student:
            return redirect('student:index')
        elif user.is_contributor_or_delegate:
            return redirect('contributor:index')
        else:
            return redirect('results:index')
Exemplo n.º 2
0
 def send(self, request, courses):
     recipient = self.cleaned_data.get('to')
     self.template.subject = self.cleaned_data.get('subject')
     self.template.body = self.cleaned_data.get('body')
     subject_params = {}
     body_params = {'user': recipient, 'courses': courses}
     EmailTemplate.send_to_user(recipient, self.template, subject_params, body_params, use_cc=True, request=request)
Exemplo n.º 3
0
def send_publish_notifications(courses, template=None):
    from evap.evaluation.models import EmailTemplate
    publish_notifications = defaultdict(set)

    if not template:
        template = EmailTemplate.objects.get(
            name=EmailTemplate.PUBLISHING_NOTICE)

    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():
                publish_notifications[participant].add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_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:
                    publish_notifications[
                        textanswer.contribution.contributor].add(course)

            for contributor in course.responsible_contributors:
                publish_notifications[contributor].add(course)

    for user, course_set in publish_notifications.items():
        body_params = {'user': user, 'courses': list(course_set)}
        EmailTemplate.send_to_user(user,
                                   template, {},
                                   body_params,
                                   use_cc=True)
Exemplo n.º 4
0
    def test_recipient_list_filtering(self):
        course = mommy.make(Course)

        contributor1 = mommy.make(UserProfile)
        contributor2 = mommy.make(UserProfile, delegates=[contributor1])

        mommy.make(Contribution, course=course, contributor=contributor1)
        mommy.make(Contribution, course=course, contributor=contributor2)

        # no-one should get filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [contributor1, contributor2])

        # contributor1 is in cc of contributor2 and gets filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=True)
        self.assertCountEqual(recipient_list, [contributor2])

        contributor3 = mommy.make(UserProfile, delegates=[contributor2])
        mommy.make(Contribution, course=course, contributor=contributor3)

        # again, no-one should get filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [contributor1, contributor2, contributor3])

        # contributor1 is in cc of contributor2 and gets filtered.
        # contributor2 is in cc of contributor3 but is not filtered since contributor1 wouldn't get an email at all then.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=True)
        self.assertCountEqual(recipient_list, [contributor2, contributor3])
Exemplo n.º 5
0
def semester_publish(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)
    courses = semester.course_set.filter(state="reviewed").all()

    forms = helper_create_grouped_course_selection_forms(courses, None, request)

    valid = helper_are_course_selection_forms_valid(forms)

    for form in forms:
        for course_id, field in form.fields.items():
            course = Course.objects.get(pk=course_id)
            field.label += " (graded)" if course.is_graded else " (not graded)" 

    if valid:
        selected_courses = []
        for form in forms:
            for course in form.selected_courses:
                course.publish()
                course.save()
                selected_courses.append(course)
        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))
Exemplo n.º 6
0
    def handle(self, *args, **options):
        logger.info("send_reminders called.")
        check_dates = []

        # Collect end-dates of courses whose participants need to be reminded today.
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() +
                               datetime.timedelta(days=number_of_days))

        recipients = set()
        for course in Course.objects.filter(state='in_evaluation',
                                            vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = get_due_courses_for_user(recipient)
            first_due_in_days = due_courses[0][
                1]  # entry 0 is first due course, entry 1 in tuple is number of days

            EmailTemplate.send_reminder_to_user(
                recipient,
                first_due_in_days=first_due_in_days,
                due_courses=due_courses)
        logger.info("send_reminders finished.")
        logger.info("sent reminders to {} people.".format(len(recipients)))
Exemplo n.º 7
0
    def handle(self, *args, **options):
        logger.info("send_reminders called.")
        check_dates = []

        # Collect end-dates of courses whose participants need to be reminded today.
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() +
                               datetime.timedelta(days=number_of_days))

        recipients = set()
        for course in Course.objects.filter(state='in_evaluation',
                                            vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = dict()
            for course in Course.objects.filter(
                    participants=recipient,
                    state='in_evaluation').exclude(voters=recipient):
                due_courses[course] = (course.vote_end_date -
                                       datetime.date.today()).days
            first_due_in_days = min(due_courses.values())

            # Sort courses by number of days left for evaluation and bring them to following format:
            # [(course, due_in_days), ...]
            due_courses = sorted(due_courses.items(),
                                 key=operator.itemgetter(1))

            EmailTemplate.send_reminder_to_user(
                recipient,
                first_due_in_days=first_due_in_days,
                due_courses=due_courses)
        logger.info("send_reminders finished.")
        logger.info("sent reminders to {} people.".format(len(recipients)))
Exemplo n.º 8
0
def evaluation_direct_delegation(request, evaluation_id):
    delegate_user_id = request.POST.get("delegate_to")

    evaluation = get_object_or_404(Evaluation, id=evaluation_id)
    delegate_user = get_object_or_404(UserProfile, id=delegate_user_id)

    Contribution.objects.update_or_create(evaluation=evaluation,
                                          contributor=delegate_user,
                                          defaults={'can_edit': True})

    template = EmailTemplate.objects.get(name=EmailTemplate.DIRECT_DELEGATION)
    subject_params = {
        "evaluation": evaluation,
        "user": request.user,
        "delegate_user": delegate_user
    }
    body_params = subject_params

    # we don't provide the request here since send_to_user only uses it to display a warning message in case the user does not have
    # an email address. In this special case, we don't want that warning. Instead, we want a mail to the admins.
    EmailTemplate.send_to_user(delegate_user,
                               template,
                               subject_params,
                               body_params,
                               use_cc=True,
                               additional_cc_user=request.user)

    messages.add_message(
        request, messages.SUCCESS,
        _('{} was added as a contributor for evaluation "{}" and was sent an email with further information.'
          ).format(str(delegate_user), str(evaluation)))

    return redirect('contributor:index')
Exemplo n.º 9
0
    def test_recipient_list_filtering(self):
        course = mommy.make(Course)

        contributor1 = mommy.make(UserProfile)
        contributor2 = mommy.make(UserProfile, delegates=[contributor1])

        mommy.make(Contribution, course=course, contributor=contributor1)
        mommy.make(Contribution, course=course, contributor=contributor2)

        # no-one should get filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [contributor1, contributor2])

        # contributor1 is in cc of contributor2 and gets filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=True)
        self.assertCountEqual(recipient_list, [contributor2])

        contributor3 = mommy.make(UserProfile, delegates=[contributor2])
        mommy.make(Contribution, course=course, contributor=contributor3)

        # again, no-one should get filtered.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [contributor1, contributor2, contributor3])

        # contributor1 is in cc of contributor2 and gets filtered.
        # contributor2 is in cc of contributor3 but is not filtered since contributor1 wouldn't get an email at all then.
        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=True)
        self.assertCountEqual(recipient_list, [contributor2, contributor3])
Exemplo n.º 10
0
 def send(self, request):
     self.template.subject = self.cleaned_data.get('subject')
     self.template.body = self.cleaned_data.get('body')
     EmailTemplate.send_to_users_in_courses(self.template, [self.instance],
                                            self.recipient_groups,
                                            use_cc=True,
                                            request=request)
Exemplo n.º 11
0
    def handle(self, *args, **options):
        logger.info("send_reminders called.")
        check_dates = []

        # Collect end-dates of evaluations whose participants need to be reminded today.
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() +
                               datetime.timedelta(days=number_of_days))

        recipients = set()
        for evaluation in Evaluation.objects.filter(
                state=Evaluation.State.IN_EVALUATION,
                vote_end_date__in=check_dates):
            recipients.update(evaluation.due_participants)

        for recipient in recipients:
            due_evaluations = recipient.get_sorted_due_evaluations()

            # entry 0 is first due evaluation, entry 1 in tuple is number of days
            first_due_in_days = due_evaluations[0][1]

            EmailTemplate.send_reminder_to_user(
                recipient,
                first_due_in_days=first_due_in_days,
                due_evaluations=due_evaluations)
        logger.info("send_reminders finished.")
        logger.info("sent reminders to {} people.".format(len(recipients)))
Exemplo n.º 12
0
class EvaluationEmailForm(forms.Form):
    recipients = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=EmailTemplate.Recipients.choices, label=_("Send email to"))
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Message"))

    def __init__(self, *args, evaluation, export=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.template = EmailTemplate()
        self.evaluation = evaluation
        self.recipient_groups = None
        self.fields['subject'].required = not export
        self.fields['body'].required = not export

    def clean(self):
        self.recipient_groups = self.cleaned_data.get('recipients')

        if not self.recipient_groups:
            raise forms.ValidationError(_("No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    def email_addresses(self):
        recipients = self.template.recipient_list_for_evaluation(self.evaluation, self.recipient_groups, filter_users_in_cc=False)
        return set(user.email for user in recipients if user.email)

    def send(self, request):
        self.template.subject = self.cleaned_data.get('subject')
        self.template.body = self.cleaned_data.get('body')
        self.template.send_to_users_in_evaluations([self.evaluation], self.recipient_groups, use_cc=True, request=request)
Exemplo n.º 13
0
def send_publish_notifications(courses, template=None):
    from evap.evaluation.models import EmailTemplate
    publish_notifications = defaultdict(set)

    if not template:
        template = EmailTemplate.objects.get(name=EmailTemplate.PUBLISHING_NOTICE)

    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():
                publish_notifications[participant].add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_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:
                    publish_notifications[textanswer.contribution.contributor].add(course)

            for contributor in course.responsible_contributors:
                publish_notifications[contributor].add(course)

    for user, course_set in publish_notifications.items():
        body_params = {'user': user, 'courses': list(course_set)}
        EmailTemplate.send_to_user(user, template, {}, body_params, use_cc=True)
Exemplo n.º 14
0
def send_publish_notifications(grade_document_courses=None, evaluation_results_courses=None):
    grade_document_courses = grade_document_courses or []
    evaluation_results_courses = evaluation_results_courses or []

    publish_notifications = defaultdict(lambda: CourseLists(set(), set()))

    for course in evaluation_results_courses:
        # for published courses all contributors and participants get a notification
        if course.can_publish_grades:
            for participant in course.participants.all():
                publish_notifications[participant].evaluation_results_courses.add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_notifications[contribution.contributor].evaluation_results_courses.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:
                    publish_notifications[textanswer.contribution.contributor].evaluation_results_courses.add(course)
            publish_notifications[course.responsible_contributor].evaluation_results_courses.add(course)
    for course in grade_document_courses:
        # all participants who can download grades get a notification
        for participant in course.participants.all():
            if participant.can_download_grades:
                publish_notifications[participant].grade_document_courses.add(course)

    for user, course_lists in publish_notifications.items():
        EmailTemplate.send_publish_notifications_to_user(
            user,
            grade_document_courses=list(course_lists.grade_document_courses),
            evaluation_results_courses=list(course_lists.evaluation_results_courses)
        )
Exemplo n.º 15
0
 def test_copy_plain_content_on_empty_html_content(self):
     template = EmailTemplate(
         subject="Example", plain_content="Example plain content\nWith newline", html_content=""
     )
     template.send_to_user(self.user, {}, {}, False)
     self.assertEqual(mail.outbox[0].body, "Example plain content\nWith newline")
     self.assertIn("Example plain content<br />With newline", mail.outbox[0].alternatives[0][0])
Exemplo n.º 16
0
 def __init__(self, *args, evaluation, export=False, **kwargs):
     super().__init__(*args, **kwargs)
     self.template = EmailTemplate()
     self.evaluation = evaluation
     self.recipient_groups = None
     self.fields['subject'].required = not export
     self.fields['body'].required = not export
Exemplo n.º 17
0
def send_publish_notifications(courses, template=None):
    from evap.evaluation.models import EmailTemplate
    publish_notifications = defaultdict(set)

    if not template:
        template = EmailTemplate.objects.get(name=EmailTemplate.PUBLISHING_NOTICE)

    for course in courses:
        # for courses with published averaged grade, all contributors and participants get a notification
        # we don't send a notification if the significance threshold isn't met
        if course.can_publish_average_grade:
            for participant in course.participants.all():
                publish_notifications[participant].add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_notifications[contribution.contributor].add(course)
        # if the average grade was not published, notifications are only sent for contributors who can see text answers
        elif course.textanswer_set:
            for textanswer in course.textanswer_set:
                if textanswer.contribution.contributor:
                    publish_notifications[textanswer.contribution.contributor].add(course)

            for contributor in course.responsible_contributors:
                publish_notifications[contributor].add(course)

    for user, course_set in publish_notifications.items():
        body_params = {'user': user, 'courses': list(course_set)}
        EmailTemplate.send_to_user(user, template, {}, body_params, use_cc=True)
Exemplo n.º 18
0
class CourseEmailForm(forms.Form, BootstrapMixin):
    recipients = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=EMAIL_RECIPIENTS, label=_("Send email to"))
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Message"))

    def __init__(self, *args, **kwargs):
        self.instance = kwargs.pop('instance')
        self.template = EmailTemplate()
        super(CourseEmailForm, self).__init__(*args, **kwargs)

    def clean(self):
        self.recipient_groups = self.cleaned_data.get('recipients')

        if not self.recipient_groups:
            raise forms.ValidationError(_(u"No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    # returns whether all recepients have an email address
    def all_recepients_reachable(self):
        return self.missing_email_addresses() == 0

    # returns the number of recepients without an email address
    def missing_email_addresses(self):
        recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
        return len([user for user in recipients if not user.email])

    def send(self):
        self.template.subject = self.cleaned_data.get('subject')
        self.template.body = self.cleaned_data.get('body')
        self.template.send_to_users_in_courses([self.instance], self.recipient_groups)
Exemplo n.º 19
0
 def __init__(self, *args, **kwargs):
     self.instance = kwargs.pop('instance')
     self.export = kwargs.pop('export', False)
     self.template = EmailTemplate()
     super().__init__(*args, **kwargs)
     self.fields['subject'].required = not self.export
     self.fields['body'].required = not self.export
Exemplo n.º 20
0
    def handle(self, *args, **options):
        logger.info("send_reminders called.")
        check_dates = []

        # Collect end-dates of courses whose participants need to be reminded today.
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() + datetime.timedelta(days=number_of_days))

        recipients = set()
        for course in Course.objects.filter(state="in_evaluation", vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = dict()
            for course in Course.objects.filter(participants=recipient, state="in_evaluation").exclude(
                voters=recipient
            ):
                due_courses[course] = (course.vote_end_date - datetime.date.today()).days
            first_due_in_days = min(due_courses.values())

            # Sort courses by number of days left for evaluation and bring them to following format:
            # [(course, due_in_days), ...]
            due_courses = sorted(due_courses.items(), key=operator.itemgetter(1))

            EmailTemplate.send_reminder_to_user(recipient, first_due_in_days=first_due_in_days, due_courses=due_courses)
        logger.info("send_reminders finished.")
        logger.info("sent reminders to {} people.".format(len(recipients)))
Exemplo n.º 21
0
def login_key_authentication(request, key):
    user = auth.authenticate(request, key=key)

    if user and not user.is_active:
        messages.error(request, _("Inactive users are not allowed to login."))
        return redirect('evaluation:index')

    # If we already have an authenticated user don't try to login a new user. Show an error message if another user
    # tries to login with a URL in this situation.
    if request.user.is_authenticated:
        if user != request.user:
            messages.error(request, _("Another user is currently logged in. Please logout first and then use the login URL again."))
        return redirect('evaluation:index')

    if user and user.login_key_valid_until >= date.today():
        # User is valid. Set request.user and persist user in the session by logging the user in.
        request.user = user
        auth.login(request, user)
        messages.success(request, _("Logged in as %s.") % user.full_name)
        # Invalidate the login key, but keep it stored so we can later identify the user that is trying to login and send a new link
        user.login_key_valid_until = date.today() - timedelta(1)
        user.save()
    elif user:
        # A user exists, but the login key is not valid anymore. Send the user a new one.
        user.ensure_valid_login_key()
        EmailTemplate.send_login_url_to_user(user)
        messages.warning(request, _("The login URL is not valid anymore. We sent you a new one to your email address."))
    else:
        messages.warning(request, _("Invalid login URL. Please request a new one below."))

    return redirect('evaluation:index')
Exemplo n.º 22
0
def evaluation_direct_delegation(request, evaluation_id):
    delegate_user_id = request.POST.get("delegate_to")

    evaluation = get_object_or_404(Evaluation, id=evaluation_id)
    delegate_user = get_object_or_404(UserProfile, id=delegate_user_id)

    contribution, created = Contribution.objects.update_or_create(evaluation=evaluation, contributor=delegate_user, defaults={'can_edit': True})
    if created:
        contribution.order = evaluation.contributions.all().aggregate(Max('order'))['order__max'] + 1
        contribution.save()

    template = EmailTemplate.objects.get(name=EmailTemplate.DIRECT_DELEGATION)
    subject_params = {"evaluation": evaluation, "user": request.user, "delegate_user": delegate_user}
    body_params = subject_params

    # we don't provide the request here since send_to_user only uses it to display a warning message in case the user does not have
    # an email address. In this special case, we don't want that warning. Instead, we want a mail to the admins.
    EmailTemplate.send_to_user(delegate_user, template, subject_params, body_params, use_cc=True, additional_cc_user=request.user)

    messages.add_message(
        request,
        messages.SUCCESS,
        _('{} was added as a contributor for evaluation "{}" and was sent an email with further information.').format(str(delegate_user), str(evaluation))
    )

    return redirect('contributor:index')
Exemplo n.º 23
0
def index(request):
    """Main entry page into EvaP providing all the login options available. The username/password
       login is thought to be used for internal users, e.g. by connecting to a LDAP directory.
       The login key mechanism is meant to be used to include external participants, e.g. visiting
       students or visiting contributors.
    """

    # parse the form data into the respective form
    submit_type = request.POST.get("submit_type", "no_submit")
    new_key_form = NewKeyForm(request.POST if submit_type == "new_key" else None)
    login_username_form = LoginUsernameForm(request, request.POST if submit_type == "login_username" else None)

    # process form data
    if request.method == 'POST':
        if new_key_form.is_valid():
            # user wants a new login key
            profile = new_key_form.get_user()
            profile.ensure_valid_login_key()
            profile.save()

            EmailTemplate.send_login_url_to_user(new_key_form.get_user())

            messages.success(request, _("We sent you an email with a one-time login URL. Please check your inbox."))
            return redirect('evaluation:index')
        elif login_username_form.is_valid():
            # user would like to login with username and password and passed password test
            auth.login(request, login_username_form.get_user())

            # clean up our test cookie
            if request.session.test_cookie_worked():
                request.session.delete_test_cookie()

    # if not logged in by now, render form
    if not request.user.is_authenticated:
        # set test cookie to verify whether they work in the next step
        request.session.set_test_cookie()

        template_data = dict(new_key_form=new_key_form, login_username_form=login_username_form)
        return render(request, "index.html", template_data)
    else:
        user, __ = UserProfile.objects.get_or_create(username=request.user.username)

        # check for redirect variable
        redirect_to = request.GET.get("next", None)
        if redirect_to is not None:
            return redirect(redirect_to)

        # redirect user to appropriate start page
        if request.user.is_reviewer:
            return redirect('staff:semester_view', Semester.active_semester().id)
        if request.user.is_manager:
            return redirect('staff:index')
        elif request.user.is_grade_publisher:
            return redirect('grades:semester_view', Semester.active_semester().id)
        elif user.is_student:
            return redirect('student:index')
        elif user.is_contributor_or_delegate:
            return redirect('contributor:index')
        else:
            return redirect('results:index')
Exemplo n.º 24
0
 def send(self, request, courses):
     recipient = self.cleaned_data.get('to')
     self.template.subject = self.cleaned_data.get('subject')
     self.template.body = self.cleaned_data.get('body')
     subject_params = {}
     body_params = {'user': recipient, 'courses': courses}
     EmailTemplate.send_to_user(recipient, self.template, subject_params, body_params, use_cc=True, request=request)
Exemplo n.º 25
0
def login_key_authentication(request, key):
    user = auth.authenticate(request, key=key)

    if user and not user.is_active:
        messages.error(request, _("Inactive users are not allowed to login."))
        return redirect('evaluation:index')

    # If we already have an authenticated user don't try to login a new user. Show an error message if another user
    # tries to login with a URL in this situation.
    if request.user.is_authenticated:
        if user != request.user:
            messages.error(request, _("Another user is currently logged in. Please logout first and then use the login URL again."))
        return redirect('evaluation:index')

    if user and user.login_key_valid_until >= date.today():
        # User is valid. Set request.user and persist user in the session by logging the user in.
        request.user = user
        auth.login(request, user)
        messages.success(request, _("Logged in as %s.") % user.full_name)
        # Invalidate the login key, but keep it stored so we can later identify the user that is trying to login and send a new link
        user.login_key_valid_until = date.today() - timedelta(1)
        user.save()
    elif user:
        # A user exists, but the login key is not valid anymore. Send the user a new one.
        user.ensure_valid_login_key()
        EmailTemplate.send_login_url_to_user(user)
        messages.warning(request, _("The login URL is not valid anymore. We sent you a new one to your email address."))
    else:
        messages.warning(request, _("Invalid login URL. Please request a new one below."))

    return redirect('evaluation:index')
Exemplo n.º 26
0
def send_publish_notifications(courses, template=None):
    from evap.evaluation.models import EmailTemplate
    publish_notifications = defaultdict(set)

    if not template:
        template = EmailTemplate.objects.get(
            name=EmailTemplate.PUBLISHING_NOTICE)

    for course in courses:
        # for courses with published averaged grade, all contributors and participants get a notification
        # we don't send a notification if the significance threshold isn't met
        if course.can_publish_average_grade:
            for participant in course.participants.all():
                publish_notifications[participant].add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_notifications[contribution.contributor].add(course)
        # if the average grade was not published, notifications are only sent for contributors who can see text answers
        elif course.textanswer_set:
            for textanswer in course.textanswer_set:
                if textanswer.contribution.contributor:
                    publish_notifications[
                        textanswer.contribution.contributor].add(course)

            for contributor in course.responsible_contributors:
                publish_notifications[contributor].add(course)

    for user, course_set in publish_notifications.items():
        body_params = {'user': user, 'courses': list(course_set)}
        EmailTemplate.send_to_user(user,
                                   template, {},
                                   body_params,
                                   use_cc=True)
Exemplo n.º 27
0
def index(request):
    """Main entry page into EvaP providing all the login options available. The OpenID login is thought to be used for
       internal users. The login key mechanism is meant to be used to include external participants, e.g. visiting
       students or visiting contributors. A login with email and password is available if OpenID is deactivated.
    """

    # parse the form data into the respective form
    submit_type = request.POST.get("submit_type", "no_submit")
    new_key_form = NewKeyForm(request.POST if submit_type ==
                              "new_key" else None)
    login_email_form = LoginEmailForm(
        request, request.POST if submit_type == "login_email" else None)

    # process form data
    if request.method == 'POST':
        if new_key_form.is_valid():
            # user wants a new login key
            profile = new_key_form.get_user()
            profile.ensure_valid_login_key()
            profile.save()

            EmailTemplate.send_login_url_to_user(new_key_form.get_user())

            messages.success(
                request,
                _("We sent you an email with a one-time login URL. Please check your inbox."
                  ))
            return redirect('evaluation:index')

        if login_email_form.is_valid():
            # user would like to login with email and password and passed password test
            auth.login(request, login_email_form.get_user())

            # clean up our test cookie
            if request.session.test_cookie_worked():
                request.session.delete_test_cookie()
            return redirect('evaluation:index')

    # if not logged in by now, render form
    if not request.user.is_authenticated:
        # set test cookie to verify whether they work in the next step
        request.session.set_test_cookie()

        template_data = dict(
            new_key_form=new_key_form,
            login_email_form=login_email_form,
            openid_active=settings.ACTIVATE_OPEN_ID_LOGIN,
        )
        return render(request, "index.html", template_data)

    # the cached navbar might contain CSRF tokens that are invalid after a new login
    delete_navbar_cache_for_users([request.user])

    # check for redirect variable
    redirect_to = request.GET.get("next", None)
    if redirect_to is not None:
        return redirect(redirect_to)

    return redirect_user_to_start_page(request.user)
Exemplo n.º 28
0
 def test_missing_email_address(self):
     """
     Tests that __send_to_user behaves when the user has no email address.
     Regression test to https://github.com/fsr-itse/EvaP/issues/825
     """
     user = mommy.make(UserProfile, email=None)
     template = EmailTemplate.objects.get(name=EmailTemplate.STUDENT_REMINDER)
     EmailTemplate._EmailTemplate__send_to_user(user, template, {}, {}, False, None)
Exemplo n.º 29
0
 def __init__(self, *args, evaluation, export=False, **kwargs):
     super().__init__(*args, **kwargs)
     self.template = EmailTemplate()
     self.evaluation = evaluation
     self.recipient_groups = None
     self.fields["subject"].required = not export
     self.fields["plain_content"].required = not export
     self.fields["html_content"].required = False
Exemplo n.º 30
0
 def test_no_login_url_when_delegates_in_cc(self):
     self.user.delegates.add(self.other_user)
     EmailTemplate.send_to_users_in_evaluations(self.template, [self.evaluation], EmailTemplate.CONTRIBUTORS, use_cc=True, request=None)
     self.assertEqual(len(mail.outbox), 2)
     self.assertEqual(mail.outbox[0].body, "")  # message does not contain the login url
     self.assertEqual(mail.outbox[1].body, self.user.login_url)  # separate email with login url was sent
     self.assertEqual(len(mail.outbox[1].cc), 0)
     self.assertEqual(mail.outbox[1].to, [self.user.email])
Exemplo n.º 31
0
 def test_no_login_url_when_cc_users_in_cc(self):
     self.user.cc_users.add(self.other_user)
     EmailTemplate.send_to_users_in_courses(self.template, [self.course], [EmailTemplate.CONTRIBUTORS], use_cc=True)
     self.assertEqual(len(mail.outbox), 2)
     self.assertFalse("loginkey" in mail.outbox[0].body)  # message does not contain the login url
     self.assertTrue("loginkey" in mail.outbox[1].body)  # separate email with login url was sent
     self.assertEqual(len(mail.outbox[1].cc), 0)
     self.assertEqual(mail.outbox[1].to, [self.user.email])
Exemplo n.º 32
0
 def test_no_login_url_when_cc_users_in_cc(self):
     self.user.cc_users.add(self.other_user)
     EmailTemplate.send_to_users_in_courses(self.template, [self.course], [EmailTemplate.CONTRIBUTORS], use_cc=True, request=None)
     self.assertEqual(len(mail.outbox), 2)
     self.assertFalse("loginkey" in mail.outbox[0].body)  # message does not contain the login url
     self.assertTrue("loginkey" in mail.outbox[1].body)  # separate email with login url was sent
     self.assertEqual(len(mail.outbox[1].cc), 0)
     self.assertEqual(mail.outbox[1].to, [self.user.email])
Exemplo n.º 33
0
def helper_semester_course_operation_prepare(request, courses, send_email):
    for course in courses:
        course.ready_for_editors()
        course.save()
    messages.success(request, ungettext("Successfully enabled %(courses)d course for editor review.",
        "Successfully enabled %(courses)d courses for editor review.", len(courses)) % {'courses': len(courses)})
    if send_email:
        EmailTemplate.send_review_notifications(courses)
Exemplo n.º 34
0
 def test_missing_email_address(self):
     """
     Tests that __send_to_user behaves when the user has no email address.
     Regression test to https://github.com/fsr-itse/EvaP/issues/825
     """
     user = mommy.make(UserProfile, email=None)
     template = EmailTemplate.objects.get(name=EmailTemplate.STUDENT_REMINDER)
     EmailTemplate._EmailTemplate__send_to_user(user, template, {}, {}, False, None)
Exemplo n.º 35
0
 def test_escape_special_characters_in_html_email(self):
     template = EmailTemplate(
         subject="<h1>Special Email</h1>",
         plain_content="Example plain content",
         html_content="Special Content: {{special_content}}",
     )
     template.send_to_user(self.user, {}, {"special_content": "0 < 1"}, False)
     self.assertIn("&lt;h1&gt;Special Email&lt;/h1&gt;", mail.outbox[0].alternatives[0][0])
     self.assertIn("Special Content: 0 &lt; 1", mail.outbox[0].alternatives[0][0])
Exemplo n.º 36
0
def helper_semester_course_operation_start(request, courses, send_email):
    for course in courses:
        course.vote_start_date = datetime.date.today()
        course.evaluation_begin()
        course.save()
    messages.success(request, ungettext("Successfully started evaluation for %(courses)d course.",
        "Successfully started evaluation for %(courses)d courses.", len(courses)) % {'courses': len(courses)})
    if send_email:
        EmailTemplate.send_evaluation_started_notifications(courses)
Exemplo n.º 37
0
    def process_request(self, request):
        # AuthenticationMiddleware is required so that request.user exists.
        if not hasattr(request, 'user'):
            raise ImproperlyConfigured(
                "The Django remote user auth middleware requires the"
                " authentication middleware to be installed.  Edit your"
                " MIDDLEWARE_CLASSES setting to insert"
                " 'django.contrib.auth.middleware.AuthenticationMiddleware'"
                " before the RequestAuthMiddleware class.")

        try:
            key = int(request.GET[self.field_name])
        except (KeyError, ValueError):
            # If specified variable doesn't exist or does not convert to an int
            # then return (leaving request.user set to AnonymousUser by the
            # AuthenticationMiddleware).
            return

        # We are seeing this user for the first time in this session, attempt to authenticate the user.
        user = auth.authenticate(request, key=key)

        if user and not user.is_active:
            messages.error(request,
                           _("Inactive users are not allowed to login."))
            return

        # If we already have an authenticated user don't try to login a new user. Show an error message if another user
        # tries to login with a URL in this situation.
        if request.user.is_authenticated:
            if user != request.user:
                messages.error(
                    request,
                    _("Another user is currently logged in. Please logout first and then use the login URL again."
                      ))
            return

        if user and user.login_key_valid_until >= date.today():
            # User is valid. Set request.user and persist user in the session by logging the user in.
            request.user = user
            auth.login(request, user)
            messages.success(request, _("Logged in as %s.") % user.full_name)
            # Invalidate the login key, but keep it stored so we can later identify the user that is trying to login and send a new link
            user.login_key_valid_until = date.today() - timedelta(1)
            user.save()
        elif user:
            # A user exists, but the login key is not valid anymore. Send the user a new one.
            user.ensure_valid_login_key()
            EmailTemplate.send_login_url_to_user(user)
            messages.warning(
                request,
                _("The login URL is not valid anymore. We sent you a new one to your email address."
                  ))
        else:
            messages.warning(
                request,
                _("Invalid login URL. Please request a new one below."))
Exemplo n.º 38
0
 def test_login_url_when_nobody_in_cc(self):
     # message is not sent to others in cc
     EmailTemplate.send_to_users_in_evaluations(
         self.template, [self.evaluation], [EmailTemplate.CONTRIBUTORS],
         use_cc=True,
         request=None)
     self.assertEqual(len(mail.outbox), 1)
     self.assertEqual(
         mail.outbox[0].body,
         self.user.login_url)  # message does contain the login url
Exemplo n.º 39
0
 def test_login_url_when_nobody_in_cc(self):
     # message is not sent to others in cc
     EmailTemplate.send_to_users_in_courses(self.template, [self.course],
                                            [EmailTemplate.CONTRIBUTORS],
                                            use_cc=True,
                                            request=None)
     self.assertEqual(len(mail.outbox), 1)
     self.assertTrue(
         "loginkey"
         in mail.outbox[0].body)  # message does contain the login url
Exemplo n.º 40
0
 def test_send_multi_alternatives_email(self):
     template = EmailTemplate(
         subject="Example", plain_content="Example plain content", html_content="<p>Example html content</p>"
     )
     template.send_to_user(self.user, {}, {}, False)
     self.assertEqual(len(mail.outbox), 1)
     self.assertTrue(isinstance(mail.outbox[0], mail.message.EmailMultiAlternatives))
     self.assertEqual(mail.outbox[0].body, "Example plain content")
     self.assertEqual(len(mail.outbox[0].alternatives), 1)
     self.assertEqual(mail.outbox[0].alternatives[0][1], "text/html")
     self.assertIn("<p>Example html content</p>", mail.outbox[0].alternatives[0][0])
Exemplo n.º 41
0
 def test_login_url_when_use_cc_is_false(self):
     # message is not sent to others in cc
     self.user.delegates.add(self.other_user)
     EmailTemplate.send_to_users_in_evaluations(
         self.template, [self.evaluation], [EmailTemplate.CONTRIBUTORS],
         use_cc=False,
         request=None)
     self.assertEqual(len(mail.outbox), 1)
     self.assertEqual(
         mail.outbox[0].body,
         self.user.login_url)  # message does contain the login url
Exemplo n.º 42
0
def on_grading_process_finished(course):
    evaluations = course.evaluations.all()
    if all(evaluation.state == 'reviewed' for evaluation in evaluations):
        for evaluation in evaluations:
            assert evaluation.grading_process_is_finished
        for evaluation in evaluations:
            evaluation.publish()
            evaluation.save()

        EmailTemplate.send_participant_publish_notifications(evaluations)
        EmailTemplate.send_contributor_publish_notifications(evaluations)
Exemplo n.º 43
0
def helper_semester_course_operation_prepare(request, courses, send_email):
    for course in courses:
        course.ready_for_editors()
        course.save()
    messages.success(
        request,
        ungettext(
            "Successfully enabled %(courses)d course for editor review.",
            "Successfully enabled %(courses)d courses for editor review.",
            len(courses)) % {'courses': len(courses)})
    if send_email:
        EmailTemplate.send_review_notifications(courses)
Exemplo n.º 44
0
    def test_send_contributor_publish_notifications():
        responsible1 = baker.make(UserProfile)
        responsible2 = baker.make(UserProfile)
        # use is_single_result to get can_publish_average_grade to become true
        evaluation1 = baker.make(Evaluation, course__responsibles=[responsible1], is_single_result=True)
        evaluation2 = baker.make(Evaluation, course__responsibles=[responsible2])

        editor1 = baker.make(UserProfile)
        contributor1 = baker.make(UserProfile)

        contributor2 = baker.make(UserProfile)
        editor2 = baker.make(UserProfile)
        contributor_both = baker.make(UserProfile)

        # Contributions for evaluation1
        make_contributor(responsible1, evaluation1)
        make_contributor(contributor1, evaluation1)
        make_contributor(contributor_both, evaluation1)
        make_editor(editor1, evaluation1)

        # Contributions for evaluation2
        make_editor(editor2, evaluation2)
        contributor_both_contribution = make_contributor(contributor_both, evaluation2)
        contributor2_contribution = make_contributor(contributor2, evaluation2)

        baker.make(TextAnswer, contribution=contributor_both_contribution)
        baker.make(TextAnswer, contribution=contributor2_contribution)

        expected_calls = [
            # these 4 are included since they are contributors for evaluation1 which can publish the average grade
            call(responsible1, {}, {"user": responsible1, "evaluations": {evaluation1}}, use_cc=True),
            call(editor1, {}, {"user": editor1, "evaluations": {evaluation1}}, use_cc=True),
            call(contributor1, {}, {"user": contributor1, "evaluations": {evaluation1}}, use_cc=True),
            call(
                contributor_both, {}, {"user": contributor_both, "evaluations": {evaluation1, evaluation2}}, use_cc=True
            ),
            # contributor2 has textanswers, so they are notified
            call(contributor2, {}, {"user": contributor2, "evaluations": {evaluation2}}, use_cc=True),
        ]

        with patch("evap.evaluation.models.EmailTemplate.send_to_user") as send_to_user_mock:
            EmailTemplate.send_contributor_publish_notifications({evaluation1, evaluation2})
            # Assert that all expected publish notifications are sent to contributors.
            send_to_user_mock.assert_has_calls(expected_calls, any_order=True)

        # if general textanswers for an evaluation exist, all responsibles should also be notified
        baker.make(TextAnswer, contribution=evaluation2.general_contribution)
        expected_calls.append(call(responsible2, {}, {"user": responsible2, "evaluations": {evaluation2}}, use_cc=True))

        with patch("evap.evaluation.models.EmailTemplate.send_to_user") as send_to_user_mock:
            EmailTemplate.send_contributor_publish_notifications({evaluation1, evaluation2})
            send_to_user_mock.assert_has_calls(expected_calls, any_order=True)
Exemplo n.º 45
0
    def test_plain_content_escaped_and_copied_on_empty_html_content(self):
        template = EmailTemplate(subject="Subject <>&", plain_content="A\nB <>& {{ some_var }}", html_content="")
        template.send_to_user(self.user, {}, {"some_var": "0 < 1"}, False)

        self.assertEqual(len(mail.outbox), 1)
        message = mail.outbox[0]
        self.assertEqual(message.alternatives[0][1], "text/html")
        html_content = message.alternatives[0][0]

        self.assertEqual("Subject <>&", message.subject)
        self.assertEqual("A\nB <>& 0 < 1", message.body)
        self.assertIn("A<br>B &lt;&gt;&amp; 0 &lt; 1\n", html_content)
        self.assertNotIn("<>&", html_content)
Exemplo n.º 46
0
    def check_reminders(self):
        check_dates = []
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() + datetime.timedelta(days=number_of_days))
        
        recipients = set()
        for course in Course.objects.filter(state='inEvaluation', vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = list(set(Course.objects.filter(participants=recipient, state='inEvaluation').exclude(voters=recipient)))
            due_in_number_of_days = min((course.vote_end_date - datetime.date.today()).days for course in due_courses)
        
            EmailTemplate.send_reminder_to_user(recipient, due_in_number_of_days=due_in_number_of_days, due_courses=due_courses)
Exemplo n.º 47
0
class CourseEmailForm(forms.Form, BootstrapMixin):
    recipients = forms.MultipleChoiceField(
        widget=forms.CheckboxSelectMultiple(), choices=EmailTemplate.EMAIL_RECIPIENTS, label=_("Send email to")
    )
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Message"))

    def __init__(self, *args, **kwargs):
        self.instance = kwargs.pop("instance")
        self.export = kwargs.pop("export", False)
        self.template = EmailTemplate()
        super().__init__(*args, **kwargs)
        self.fields["subject"].required = not self.export
        self.fields["body"].required = not self.export

    def clean(self):
        self.recipient_groups = self.cleaned_data.get("recipients")

        if not self.recipient_groups:
            raise forms.ValidationError(_("No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    def email_addresses(self):
        recipients = self.template.recipient_list_for_course(
            self.instance, self.recipient_groups, filter_users_in_cc=False
        )
        return set(user.email for user in recipients if user.email)

    def send(self):
        self.template.subject = self.cleaned_data.get("subject")
        self.template.body = self.cleaned_data.get("body")
        EmailTemplate.send_to_users_in_courses(self.template, [self.instance], self.recipient_groups, use_cc=True)
Exemplo n.º 48
0
class CourseEmailForm(forms.Form):
    recipients = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=EmailTemplate.EMAIL_RECIPIENTS, label=_("Send email to"))
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Message"))

    def __init__(self, *args, course, export=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.template = EmailTemplate()
        self.course = course
        self.fields['subject'].required = not export
        self.fields['body'].required = not export

    def clean(self):
        self.recipient_groups = self.cleaned_data.get('recipients')

        if not self.recipient_groups:
            raise forms.ValidationError(_("No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    def email_addresses(self):
        recipients = self.template.recipient_list_for_course(self.course, self.recipient_groups, filter_users_in_cc=False)
        return set(user.email for user in recipients if user.email)

    def send(self, request):
        self.template.subject = self.cleaned_data.get('subject')
        self.template.body = self.cleaned_data.get('body')
        EmailTemplate.send_to_users_in_courses(self.template, [self.course], self.recipient_groups, use_cc=True, request=request)
Exemplo n.º 49
0
 def __init__(self, *args, **kwargs):
     self.instance = kwargs.pop("instance")
     self.export = kwargs.pop("export", False)
     self.template = EmailTemplate()
     super().__init__(*args, **kwargs)
     self.fields["subject"].required = not self.export
     self.fields["body"].required = not self.export
Exemplo n.º 50
0
 def __init__(self, *args, **kwargs):
     self.instance = kwargs.pop('instance')
     self.export = kwargs.pop('export', False)
     self.template = EmailTemplate()
     super().__init__(*args, **kwargs)
     self.fields['subject'].required = not self.export
     self.fields['body'].required = not self.export
Exemplo n.º 51
0
    def process_request(self, request):
        # AuthenticationMiddleware is required so that request.user exists.
        if not hasattr(request, 'user'):
            raise ImproperlyConfigured(
                "The Django remote user auth middleware requires the"
                " authentication middleware to be installed.  Edit your"
                " MIDDLEWARE_CLASSES setting to insert"
                " 'django.contrib.auth.middleware.AuthenticationMiddleware'"
                " before the RequestAuthMiddleware class.")

        try:
            key = int(request.GET[self.field_name])
        except (KeyError, ValueError):
            # If specified variable doesn't exist or does not convert to an int
            # then return (leaving request.user set to AnonymousUser by the
            # AuthenticationMiddleware).
            return

        # We are seeing this user for the first time in this session, attempt to authenticate the user.
        user = auth.authenticate(request, key=key)

        if user and not user.is_active:
            messages.error(request, _("Inactive users are not allowed to login."))
            return

        # If we already have an authenticated user don't try to login a new user. Show an error message if another user
        # tries to login with a URL in this situation.
        if request.user.is_authenticated:
            if user != request.user:
                messages.error(request, _("Another user is currently logged in. Please logout first and then use the login URL again."))
            return

        if user and user.login_key_valid_until >= date.today():
            # User is valid. Set request.user and persist user in the session by logging the user in.
            request.user = user
            auth.login(request, user)
            messages.success(request, _("Logged in as %s.") % user.full_name)
            # Invalidate the login key, but keep it stored so we can later identify the user that is trying to login and send a new link
            user.login_key_valid_until = date.today() - timedelta(1)
            user.save()
        elif user:
            # A user exists, but the login key is not valid anymore. Send the user a new one.
            user.ensure_valid_login_key()
            EmailTemplate.send_login_url_to_user(user)
            messages.warning(request, _("The login URL is not valid anymore. We sent you a new one to your email address."))
        else:
            messages.warning(request, _("Invalid login URL. Please request a new one below."))
Exemplo n.º 52
0
def send_publish_notifications(evaluations, template_contributor=USE_DEFAULT, template_participant=USE_DEFAULT):
    from evap.evaluation.models import EmailTemplate

    if template_contributor == USE_DEFAULT:
        template_contributor = EmailTemplate.objects.get(name=EmailTemplate.PUBLISHING_NOTICE_CONTRIBUTOR)

    if template_participant == USE_DEFAULT:
        template_participant = EmailTemplate.objects.get(name=EmailTemplate.PUBLISHING_NOTICE_PARTICIPANT)

    evaluations_for_contributors = defaultdict(set)
    evaluations_for_participants = defaultdict(set)

    for evaluation in evaluations:
        # for evaluations with published averaged grade, all contributors and participants get a notification
        # we don't send a notification if the significance threshold isn't met
        if evaluation.can_publish_average_grade:
            if template_contributor:
                for contribution in evaluation.contributions.all():
                    if contribution.contributor:
                        evaluations_for_contributors[contribution.contributor].add(evaluation)

            if template_participant:
                for participant in evaluation.participants.all():
                    evaluations_for_participants[participant].add(evaluation)

        # if the average grade was not published, notifications are only sent for contributors who can see text answers
        elif evaluation.textanswer_set and template_contributor:
            for textanswer in evaluation.textanswer_set:
                if textanswer.contribution.contributor:
                    evaluations_for_contributors[textanswer.contribution.contributor].add(evaluation)

            for contributor in evaluation.course.responsibles.all():
                evaluations_for_contributors[contributor].add(evaluation)

    assert(not evaluations_for_contributors or template_contributor)
    assert(not evaluations_for_participants or template_participant)

    for contributor, evaluation_set in evaluations_for_contributors.items():
        body_params = {'user': contributor, 'evaluations': list(evaluation_set)}
        EmailTemplate.send_to_user(contributor, template_contributor, {}, body_params, use_cc=True)

    for participant, evaluation_set in evaluations_for_participants.items():
        body_params = {'user': participant, 'evaluations': list(evaluation_set)}
        EmailTemplate.send_to_user(participant, template_participant, {}, body_params, use_cc=True)
Exemplo n.º 53
0
    def handle(self, *args, **options):
        logger.info("send_reminders called.")
        check_dates = []

        # Collect end-dates of courses whose participants need to be reminded today.
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() + datetime.timedelta(days=number_of_days))

        recipients = set()
        for course in Course.objects.filter(state='in_evaluation', vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = get_due_courses_for_user(recipient)
            first_due_in_days = due_courses[0][1]  # entry 0 is first due course, entry 1 in tuple is number of days

            EmailTemplate.send_reminder_to_user(recipient, first_due_in_days=first_due_in_days, due_courses=due_courses)
        logger.info("send_reminders finished.")
        logger.info("sent reminders to {} people.".format(len(recipients)))
Exemplo n.º 54
0
    def check_reminders(self):
        logger.info("check_reminders called.")
        check_dates = []
        for number_of_days in settings.REMIND_X_DAYS_AHEAD_OF_END_DATE:
            check_dates.append(datetime.date.today() + datetime.timedelta(days=number_of_days))

        recipients = set()
        for course in Course.objects.filter(state='inEvaluation', vote_end_date__in=check_dates):
            recipients.update(course.due_participants)

        for recipient in recipients:
            due_courses = dict()
            for course in Course.objects.filter(participants=recipient, state='inEvaluation').exclude(voters=recipient):
                due_courses[course] = (course.vote_end_date - datetime.date.today()).days
            first_due_in_days = min(due_courses.values())
            # sort courses by number of days left for evaluation and bring them to following format: [(course, due_in_days), ...]
            due_courses = sorted(due_courses.items(), key=operator.itemgetter(1))

            EmailTemplate.send_reminder_to_user(recipient, first_due_in_days=first_due_in_days, due_courses=due_courses)
        logger.info("check_reminders finished.")
Exemplo n.º 55
0
def send_publish_notifications(courses):
    publish_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():
                publish_notifications[participant].add(course)
            for contribution in course.contributions.all():
                if contribution.contributor:
                    publish_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:
                    publish_notifications[textanswer.contribution.contributor].add(course)
            publish_notifications[course.responsible_contributor].add(course)

    for user, course_set in publish_notifications.items():
        EmailTemplate.send_publish_notifications_to_user(user, list(course_set))
Exemplo n.º 56
0
Arquivo: forms.py Projeto: Nef10/EvaP
class CourseEmailForm(forms.Form, BootstrapMixin):
    sendToDueParticipants = forms.BooleanField(label=_("Send to participants who didn't vote yet"), required=False, initial=True)
    sendToAllParticipants = forms.BooleanField(label=_("Send to all participants"), required=False)
    sendToResponsible = forms.BooleanField(label=_("Send to the responsible person"), required=False)
    sendToEditors = forms.BooleanField(label=_("Send to editors"), required=False)
    sendToContributors = forms.BooleanField(label=_("Send to all contributors (includes editors)"), required=False)
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Body"))

    def __init__(self, *args, **kwargs):
        self.instance = kwargs.pop('instance')
        self.template = EmailTemplate()
        super(CourseEmailForm, self).__init__(*args, **kwargs)

    def clean(self):
        self.recipient_groups = []

        if self.cleaned_data.get('sendToAllParticipants'): self.recipient_groups += ['all_participants']
        if self.cleaned_data.get('sendToDueParticipants'): self.recipient_groups += ['due_participants']
        if self.cleaned_data.get('sendToResponsible'): self.recipient_groups += ['responsible']
        if self.cleaned_data.get('sendToEditors'): self.recipient_groups += ['editors']
        if self.cleaned_data.get('sendToContributors'): self.recipient_groups += ['contributors']

        if len(self.recipient_groups) == 0:
            raise forms.ValidationError(_(u"No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    # returns whether all recepients have an email address
    def all_recepients_reachable(self):
        return self.missing_email_addresses() == 0

    # returns the number of recepients without an email address
    def missing_email_addresses(self):
        recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
        return len([user for user in recipients if not user.email])

    def send(self):
        self.template.subject = self.cleaned_data.get('subject')
        self.template.body = self.cleaned_data.get('body')
        self.template.send_to_users_in_courses([self.instance], self.recipient_groups)
Exemplo n.º 57
0
    def test_recipient_list(self):
        course = mommy.make(Course)
        responsible = mommy.make(UserProfile)
        editor = mommy.make(UserProfile)
        contributor = mommy.make(UserProfile)
        mommy.make(Contribution, course=course, contributor=responsible, responsible=True, can_edit=True, comment_visibility=Contribution.ALL_COMMENTS)
        mommy.make(Contribution, course=course, contributor=editor, can_edit=True)
        mommy.make(Contribution, course=course, contributor=contributor)

        participant1 = mommy.make(UserProfile, courses_participating_in=[course])
        participant2 = mommy.make(UserProfile, courses_participating_in=[course])
        course.voters = [participant1]

        recipient_list = EmailTemplate.recipient_list_for_course(course, [], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [])

        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.RESPONSIBLE], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [responsible])

        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.EDITORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [responsible, editor])

        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.CONTRIBUTORS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [responsible, editor, contributor])

        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.ALL_PARTICIPANTS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [participant1, participant2])

        recipient_list = EmailTemplate.recipient_list_for_course(course, [EmailTemplate.DUE_PARTICIPANTS], filter_users_in_cc=False)
        self.assertCountEqual(recipient_list, [participant2])
Exemplo n.º 58
0
    def update_courses(self):
        """ Updates courses state, when evaluation time begins/ends."""
        today = datetime.date.today()

        courses_new_in_evaluation = []

        for course in Course.objects.all():
            try:
                if course.state == "approved" and course.vote_start_date <= today:
                    course.evaluation_begin()
                    course.save()
                    courses_new_in_evaluation.append(course)
                elif course.state == "inEvaluation" and course.vote_end_date < today:
                    course.evaluation_end()
                    if course.is_fully_checked():
                        course.review_finished()
                    course.save()
            except Exception:
                pass

        if courses_new_in_evaluation:
            EmailTemplate.get_evaluation_started_template().send_to_users_in_courses(courses_new_in_evaluation, ['all_participants'])
Exemplo n.º 59
0
Arquivo: views.py Projeto: Nef10/EvaP
def semester_contributor_ready(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)
    courses = semester.course_set.filter(state__in=['new', 'lecturerApproved']).all()

    forms = helper_create_grouped_course_selection_forms(courses, lambda course: not course.warnings(), request)

    valid = helper_are_course_selection_forms_valid(forms)

    if valid:
        selected_courses = []
        for form in forms:
            for course in form.selected_courses:
                course.ready_for_contributors()
                course.save()
                selected_courses.append(course)

        EmailTemplate.get_review_template().send_to_users_in_courses(selected_courses, ['editors'])

        messages.success(request, _("Successfully marked %d courses as ready for lecturer review.") % (len(selected_courses)))
        return redirect('evap.fsr.views.semester_view', semester_id)
    else:
        return render_to_response("fsr_semester_contributor_ready.html", dict(semester=semester, forms=forms), context_instance=RequestContext(request))
Exemplo n.º 60
0
class CourseEmailForm(forms.Form, BootstrapMixin):
    recipients = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=EmailTemplate.EMAIL_RECIPIENTS, label=_("Send email to"))
    subject = forms.CharField(label=_("Subject"))
    body = forms.CharField(widget=forms.Textarea(), label=_("Message"))

    def __init__(self, *args, **kwargs):
        self.instance = kwargs.pop('instance')
        self.export = kwargs.pop('export', False)
        self.template = EmailTemplate()
        super().__init__(*args, **kwargs)
        self.fields['subject'].required = not self.export
        self.fields['body'].required = not self.export

    def clean(self):
        self.recipient_groups = self.cleaned_data.get('recipients')

        if not self.recipient_groups:
            raise forms.ValidationError(_("No recipient selected. Choose at least one group of recipients."))

        return self.cleaned_data

    # returns the number of recipients without an email address
    def missing_email_addresses(self):
        recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
        return len([user for user in recipients if not user.email])

    def email_addresses(self):
        if self.recipient_groups is None:
            return []
        recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
        return set(user.email for user in recipients if user.email)

    def send(self):
        self.template.subject = self.cleaned_data.get('subject')
        self.template.body = self.cleaned_data.get('body')
        EmailTemplate.send_to_users_in_courses(self.template, [self.instance], self.recipient_groups)