Beispiel #1
0
def test_send_email_as_user(describe, session, stubmailer):
    with describe('setup'):
        user = helpers.create_user_with_perms(session, [], [])
        task_result = m.TaskResult(user)
        session.add(task_result)
        session.commit()

        task_result2 = m.TaskResult(user)
        session.add(task_result2)
        session.commit()

    with describe('can send the first time'):
        psef.tasks._send_email_as_user_1([user.id], 'd', 'b',
                                         task_result.id.hex, user.id)
        assert stubmailer.was_called
        assert m.TaskResult.query.get(
            task_result.id).state == m.TaskResultState.finished

    with describe('Second call should not send'):
        psef.tasks._send_email_as_user_1([user.id], 'd', 'b',
                                         task_result.id.hex, user.id)
        assert not stubmailer.was_called
        assert m.TaskResult.query.get(
            task_result.id).state == m.TaskResultState.finished

    with describe('Should not crash for non existing task id'):
        psef.tasks._send_email_as_user_1([user.id], 'd', 'b',
                                         uuid.uuid4().hex, user.id)
        assert not stubmailer.was_called
        assert m.TaskResult.query.get(
            task_result.id).state == m.TaskResultState.finished

    with describe('task result should indicate failure when function crashes'):
        psef.tasks._send_email_as_user_1([user.id], 'd', 'b',
                                         task_result2.id.hex, -user.id)
        assert not stubmailer.was_called
        assert m.TaskResult.query.get(
            task_result2.id).state == m.TaskResultState.crashed
Beispiel #2
0
def send_students_an_email(course_id: int) -> JSONResponse[models.TaskResult]:
    """Sent the authors in this course an email.

    .. :quickref: Course; Send users in this course an email.

    :>json subject: The subject of the email to send, should not be empty.
    :>json body: The body of the email to send, should not be empty.
    :>json email_all_users: If true all users are emailed, except for those in
        ``usernames``. If ``false`` no users are emailed except for those in
        ``usernames``.
    :>jsonarr usernames: The usernames of the users to which you want to send
        an email (or not if ``email_all_users`` is ``true``).
    :returns: A task result that will send these emails.
    """
    course = helpers.filter_single_or_404(
        models.Course,
        models.Course.id == course_id,
        also_error=lambda c: c.virtual,
    )
    auth.ensure_permission(CPerm.can_email_students, course.id)

    with helpers.get_from_request_transaction() as [get, _]:
        subject = get('subject', str)
        body = get('body', str)
        email_all_users = get('email_all_users', bool)
        usernames: t.List[str] = get('usernames', list)

    if helpers.contains_duplicate(usernames):
        raise APIException('The given exceptions list contains duplicates',
                           'Each exception can only be mentioned once',
                           APICodes.INVALID_PARAM, 400)

    exceptions = helpers.get_in_or_error(
        models.User,
        models.User.username,
        usernames,
        same_order_as_given=True,
    )

    if any(course_id not in u.courses for u in exceptions):
        raise APIException(
            'Not all given users are enrolled in this course',
            f'Some given users are not enrolled in course {course_id}',
            APICodes.INVALID_PARAM, 400)

    if not (subject and body):
        raise APIException(
            'Both a subject and body should be given',
            (f'One or both of the given subject ({subject}) or body'
             f' ({body}) is empty'), APICodes.INVALID_PARAM, 400)

    if email_all_users:
        recipients = course.get_all_users_in_course(
            include_test_students=False).filter(
                models.User.id.notin_([e.id for e in exceptions
                                       ])).with_entities(models.User).all()
    else:
        recipients = exceptions
        # The test student cannot be a member of a group, so we do not need to
        # run this on the expanded group members, and we also do not want to
        # run it when `email_all_users` is true because in that case we let the
        # DB handle it for us.
        if any(r.is_test_student for r in recipients):
            raise APIException('Cannot send an email to the test student',
                               'Test student was selected',
                               APICodes.INVALID_PARAM, 400)

    recipients = helpers.flatten(r.get_contained_users() for r in recipients)

    if not recipients:
        raise APIException(
            'At least one recipient should be given as recipient',
            'No recipients were selected', APICodes.INVALID_PARAM, 400)

    task_result = models.TaskResult(current_user)
    db.session.add(task_result)
    db.session.commit()

    psef.tasks.send_email_as_user(
        receiver_ids=[u.id for u in recipients],
        subject=subject,
        body=body,
        task_result_hex_id=task_result.id.hex,
        sender_id=current_user.id,
    )

    return JSONResponse.make(task_result)
Beispiel #3
0
def test_send_login_links(describe, session, test_client, logged_in,
                          admin_user, tomorrow, stub_function, yesterday):
    with describe('setup'), logged_in(admin_user):
        stub_apply = stub_function(psef.tasks._send_login_links_to_users_1,
                                   'apply_async')
        stub_mail = stub_function(psef.mail, 'send_login_link_mail')

        assig = helpers.create_assignment(test_client)
        assig_id = helpers.get_id(assig)
        login_links_token = uuid.uuid4()
        m.Assignment.query.filter_by(id=assig_id).update({
            '_available_at':
            tomorrow.isoformat(),
            '_deadline': (tomorrow + timedelta(minutes=1)).isoformat(),
            '_send_login_links_token':
            login_links_token,
            'kind':
            'exam',
        })

        task_result = m.TaskResult(user=None)
        session.add(task_result)
        session.commit()

        student = helpers.create_user_with_role(session, 'Student',
                                                assig['course'])

    with describe('does not crash if task does not exist'):
        psef.tasks._send_login_links_to_users_1(assig_id,
                                                uuid.uuid4().hex,
                                                tomorrow.isoformat(),
                                                login_links_token, 1)
        assert task_result.state.is_not_started

    with describe('reschedules when called too early'):
        psef.tasks._send_login_links_to_users_1(assig_id, task_result.id.hex,
                                                tomorrow.isoformat(),
                                                login_links_token.hex, 1)

        assert stub_apply.called_amount == 1
        assert task_result.state.is_not_started

    with describe('Does nothing when token is different'):
        psef.tasks._send_login_links_to_users_1(assig_id, task_result.id.hex,
                                                yesterday.isoformat(),
                                                uuid.uuid4().hex, 1)
        assert not stub_mail.called
        assert task_result.state.is_skipped
        task_result.state = m.TaskResultState.not_started
        session.commit()

    with describe('Does nothing when deadline expired'):
        del flask.g.request_start_time
        with freeze_time(tomorrow + timedelta(days=1)):
            psef.tasks._send_login_links_to_users_1(assig_id,
                                                    task_result.id.hex,
                                                    yesterday.isoformat(),
                                                    login_links_token.hex, 1)

        assert not stub_mail.called
        assert task_result.state.is_skipped
        task_result.state = m.TaskResultState.not_started
        session.commit()

    with describe('Does nothing when task was already finished'):
        task_result.state = m.TaskResultState.finished
        session.commit()

        psef.tasks._send_login_links_to_users_1(assig_id, task_result.id.hex,
                                                yesterday.isoformat(),
                                                login_links_token.hex, 1)
        assert not stub_mail.called
        assert task_result.state.is_finished