예제 #1
0
def test_enabling_peer_feedback(test_client, session, describe, admin_user,
                                logged_in):
    with describe('setup'), logged_in(admin_user):
        course = helpers.create_course(test_client)
        assignment = helpers.create_assignment(test_client,
                                               course,
                                               state='open')
        user_with_perm = helpers.create_user_with_perms(
            session, [CPerm.can_edit_peer_feedback_settings], course)
        user_without_perm = helpers.create_user_with_perms(session, [], course)

    with describe('User without perm cannot enable'), logged_in(
            user_without_perm):
        helpers.enable_peer_feedback(test_client, assignment, err=403)

    with describe('User with perm can enable'), logged_in(user_with_perm):
        helpers.enable_peer_feedback(test_client, assignment)

    with describe('Amount should be >= 1'), logged_in(user_with_perm):
        helpers.enable_peer_feedback(test_client,
                                     assignment,
                                     amount=-1,
                                     err=400)
        helpers.enable_peer_feedback(test_client,
                                     assignment,
                                     amount=0,
                                     err=400)
        helpers.enable_peer_feedback(test_client, assignment, amount=110)

    with describe('Time should be > 0'), logged_in(user_with_perm):
        helpers.enable_peer_feedback(test_client, assignment, days=-1, err=400)
        helpers.enable_peer_feedback(test_client, assignment, days=0, err=400)
        helpers.enable_peer_feedback(test_client, assignment, days=0.005)
예제 #2
0
def test_create_lti_provider(
    test_client, describe, lms, iss, session, logged_in
):
    with describe('setup'):
        admin_user = helpers.create_user_with_perms(
            session, [], [], [GPerm.can_manage_lti_providers]
        )
        normal_user = helpers.create_user_with_perms(session, [], [], [])
        data = {'lms': lms, 'iss': iss, 'intended_use': 'AA'}

    with describe('admin can create a provider'), logged_in(admin_user):
        prov = test_client.req(
            'post', '/api/v1/lti1.3/providers/', 200, data=data
        )
        test_client.req('get', '/api/v1/lti1.3/providers/', 200, result=[prov])

    with describe('cannot create provider without iss'), logged_in(admin_user):
        test_client.req(
            'post', '/api/v1/lti1.3/providers/', 400, data={**data, 'iss': ''}
        )
        test_client.req('get', '/api/v1/lti1.3/providers/', 200, result=[prov])

    with describe('normal user cannot create a provider'):
        with logged_in(normal_user):
            test_client.req(
                'post', '/api/v1/lti1.3/providers/', 403, data=data
            )

        with logged_in(admin_user):
            # Should not be a new one created
            test_client.req(
                'get', '/api/v1/lti1.3/providers/', 200, result=[prov]
            )
예제 #3
0
def test_submit_with_small_group(
    test_client, session, logged_in, teacher_user, course, error_template,
    assignment
):
    user_no_group = create_user_with_perms(
        session, [CPerm.can_submit_own_work, CPerm.can_see_assignments], course
    )
    user_with_group = create_user_with_perms(
        session, [CPerm.can_submit_own_work, CPerm.can_see_assignments], course
    )

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, course.id, 1, 1)
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'group_set_id': g_set['id']}
        )
        g1 = create_group(
            test_client,
            g_set['id'],
            [user_with_group.id],
        )

    with logged_in(user_no_group):
        # Can submit without group, you are simply the author (not a group)
        sub = create_submission(test_client, assignment.id)
        assert sub['user']['id'] == user_no_group.id

    with logged_in(user_with_group):
        # But when submitting as a user in a group the group should still be
        # the author
        sub = create_submission(test_client, assignment.id)
        assert sub['user']['group']['id'] == g1['id']
예제 #4
0
def test_change_name_of_group(test_client, logged_in, error_template,
                              prog_course, session, teacher_user):
    new_name = f'NEW_NAME-{uuid.uuid4()}'

    def check_name(name):
        res = g1 if name is None else {**g1, 'name': name}
        with logged_in(teacher_user):
            return test_client.req('get',
                                   f'/api/v1/groups/{g1["id"]}',
                                   200,
                                   result=res)

    u1 = create_user_with_perms(session, [CPerm.can_edit_own_groups],
                                prog_course)
    u2 = create_user_with_perms(session, [CPerm.can_edit_own_groups],
                                prog_course)
    u3 = create_user_with_perms(session, [CPerm.can_edit_own_groups],
                                prog_course)

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, prog_course.id, 2, 4)
        g1 = create_group(
            test_client,
            g_set['id'],
            [u1.id, u2.id],
        )

    with logged_in(u3):
        test_client.req('post',
                        f'/api/v1/groups/{g1["id"]}/name',
                        403,
                        data={'name': new_name})
        check_name(None)

    with logged_in(u1):
        # u1 is member so it can change the name
        old_name = g1['name']
        test_client.req('post',
                        f'/api/v1/groups/{g1["id"]}/name',
                        200,
                        data={'name': new_name})
        check_name(new_name)

        # Reset back to old name
        test_client.req('post',
                        f'/api/v1/groups/{g1["id"]}/name',
                        200,
                        data={'name': old_name})
        check_name(old_name)

        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/name',
            400,
            data={'name': 'sh'},  # This name is too short
            result=error_template)
        check_name(None)
예제 #5
0
def test_get_all_extended_courses(ta_user, test_client, logged_in, session):
    with logged_in(ta_user):
        res = test_client.req(
            'get',
            f'/api/v1/courses/',
            200,
            query={'extended': 'true'},
            result=list,
        )
        assert len(res) == 3
        for item in res:
            assert 'assignments' in item
            assert isinstance(item['assignments'], list)
            assert 'group_sets' in item
            assert isinstance(item['group_sets'], list)

    u = create_user_with_perms(session, [], res)
    with logged_in(u):
        test_client.req('get',
                        '/api/v1/courses/',
                        200,
                        query={'extended': 'true'},
                        result=[{
                            **c,
                            'assignments': [],
                            'role': str,
                        } for c in res])
예제 #6
0
 def make_user():
     return create_user_with_perms(
         session, [
             CPerm.can_edit_own_groups, CPerm.can_submit_own_work,
             CPerm.can_see_assignments
         ], prog_course
     )
예제 #7
0
def test_add_test_student_to_group(
    session, test_client, logged_in, assignment, teacher_user, error_template,
    describe, monkeypatch_celery
):
    c_id = assignment.course.id

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, c_id, 1, 4)

        res = create_submission(
            test_client,
            assignment.id,
            is_test_submission=True,
        )
        test_student = res['user']

        with describe('new group with a test student cannot be created'):
            res = test_client.req(
                'post',
                f'/api/v1/group_sets/{g_set["id"]}/group',
                400,
                result=error_template,
                data={
                    'member_ids': [test_student['id']],
                },
            )

        with describe(
            'new group with a test student and other students cannot be created'
        ):
            u1 = create_user_with_perms(
                session, [CPerm.can_edit_own_groups], assignment.course
            )
            res = test_client.req(
                'post',
                f'/api/v1/group_sets/{g_set["id"]}/group',
                400,
                result=error_template,
                data={
                    'member_ids': [test_student['id'], u1.id],
                },
            )

        with describe('test student can not be added to existing group'):
            g1 = create_group(
                test_client,
                g_set['id'],
                [],
            )
            res = test_client.req(
                'post',
                f'/api/v1/groups/{g1["id"]}/member',
                400,
                result=error_template,
                data={
                    'username': test_student['username'],
                },
            )
예제 #8
0
def test_list_groups(
    test_client, logged_in, bs_course, error_template, teacher_user,
    assignment, session
):
    def make_empty_user():
        return create_user_with_perms(session, [], bs_course)

    user_others_too = create_user_with_perms(
        session,
        [CPerm.can_view_others_groups],
        bs_course,
    )
    user_no_perm = make_empty_user()

    with logged_in(teacher_user):
        group_set = create_group_set(test_client, bs_course.id, 2, 4)
        empty_groups = [
            create_group(test_client, group_set['id'], []) for _ in range(4)
        ]
        other_user_groups = [
            create_group(
                test_client, group_set['id'],
                [make_empty_user().id,
                 make_empty_user().id]
            )
        ]
        user_no_perm_group = [
            create_group(
                test_client, group_set['id'], [
                    make_empty_user().id,
                    make_empty_user().id,
                    user_no_perm.id,
                    make_empty_user().id,
                    make_empty_user().id,
                ]
            )
        ]

    with logged_in(user_no_perm):
        test_client.req(
            'get',
            f'/api/v1/group_sets/{group_set["id"]}/groups/',
            200,
            result=empty_groups + user_no_perm_group
        )

    with logged_in(user_others_too):
        test_client.req(
            'get',
            f'/api/v1/group_sets/{group_set["id"]}/groups/',
            200,
            result=empty_groups + other_user_groups + user_no_perm_group
        )
예제 #9
0
def test_reset_password_without_perm(test_client, session, error_template,
                                     describe):
    with describe('setup'):
        user = create_user_with_perms(session, [], [], gperms=[])

    with describe('Cannot get reset password link'):
        test_client.req(
            'patch',
            '/api/v1/login?type=reset_email',
            403,
            data={'username': user.username},
            result={
                **error_template,
                'message':
                re.compile('^This user.*necessary.*reset.*own password'),
            })
예제 #10
0
def test_creating_webhooks(basic, test_client, logged_in, describe, session):
    with describe('setup'):
        course, assig, teacher, student = basic
        url = f'/api/v1/assignments/{assig.id}/webhook_settings'
        other_user = helpers.create_user_with_perms(session, [], [])

    with describe('Posting twice results in the same hook twice'), logged_in(
            student):
        student_webhook = test_client.req('post',
                                          f'{url}?webhook_type=git',
                                          200,
                                          result={
                                              'id': str,
                                              'public_key': str,
                                              'assignment_id': assig.id,
                                              'user_id': student.id,
                                              'secret': str,
                                              'default_branch': '',
                                          })
        assert test_client.req('post', f'{url}?webhook_type=git',
                               200) == student_webhook

    with describe('A different users gets different data'), logged_in(teacher):
        teacher_webhook = test_client.req('post', f'{url}?webhook_type=git',
                                          200)
        assert all(v != teacher_webhook[k] for k, v in student_webhook.items()
                   if k not in ['assignment_id', 'default_branch'])
        assert student_webhook['assignment_id'] == teacher_webhook[
            'assignment_id']

    with describe('Webhook type should exist'), logged_in(teacher):
        test_client.req('post', url, 404)
        test_client.req('post', f'{url}?webhook_type=nope', 404)

    with describe('Can submit for other users'), logged_in(teacher):
        test_client.req('post',
                        f'{url}?webhook_type=git&author={student.username}',
                        200) == student_webhook

    with describe('Users not in the course cannot hand in using it'):
        with logged_in(teacher):
            test_client.req(
                'post', f'{url}?webhook_type=git&author={other_user.username}',
                403)
        with logged_in(other_user):
            test_client.req('post', f'{url}?webhook_type=git', 403)
예제 #11
0
def test_timeout_jwt_token(test_client, session, describe, logged_in, app):
    with describe('setup'):
        user = create_user_with_perms(session, [], [])

    with describe('cannot use the same token far in the future'):
        with logged_in(user):
            # Can within timeout
            test_client.req('get', '/api/v1/login', 200)

            future = datetime.datetime.utcnow() + datetime.timedelta(weeks=8)

            with freezegun.freeze_time(future):
                test_client.req('get', '/api/v1/login', 401)

    with describe('cannot use a garbage jwt token'), app.app_context():
        test_client.req(
            'get',
            '/api/v1/login',
            401,
            headers={'Authorization': f'Bearer jdalksfjakldfjlkadjsdlkf'})
예제 #12
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
예제 #13
0
def test_course_snippets(error_template, logged_in, test_client, session,
                         prog_course, prolog_course):
    url_base = f'/api/v1/courses/{prog_course.id}'
    teacher_user = create_user_with_perms(session, [
        CPerm.can_manage_course_snippets,
        CPerm.can_view_course_snippets,
    ], [prog_course, prolog_course])
    ta_user = create_user_with_perms(session, [
        CPerm.can_view_course_snippets,
    ], [prog_course, prolog_course])
    student_user = create_user_with_perms(session, [],
                                          [prog_course, prolog_course])

    snips = []
    with logged_in(teacher_user):
        # Create snippets
        for i in range(2):
            snips.append({
                'key': f'snippet_key{i}',
                'value': f'snippet_value{i}',
            })
            test_client.req(
                'put',
                f'{url_base}/snippet',
                201,
                data=snips[-1],
                result={
                    'id': int,
                    **snips[-1]
                },
            )
        snips = test_client.req(
            'get',
            f'{url_base}/snippets/',
            200,
            result=[{
                'id': int,
                **snip
            } for snip in snips],
        )

        # Change value by putting snippet with existing key
        snips[0]['value'] = 'newvalue'
        test_client.req(
            'put',
            f'{url_base}/snippet',
            201,
            data={
                'key': snips[0]['key'],
                'value': snips[0]['value']
            },
            result=snips[0],
        )
        test_client.req(
            'get',
            f'{url_base}/snippets/',
            200,
            result=snips,
        )

        # Change key, patch by id
        snips[0]['key'] = 'newkey'
        test_client.req(
            'patch',
            f'{url_base}/snippets/{snips[0]["id"]}',
            204,
            data={
                'key': snips[0]['key'],
                'value': snips[0]['value']
            },
        )
        test_client.req(
            'get',
            f'{url_base}/snippets/',
            200,
            result=snips,
        )

        # Check that duplicate keys raise an error
        test_client.req(
            'patch',
            f'{url_base}/snippets/{snips[0]["id"]}',
            400,
            data={
                'key': snips[1]['key'],
                'value': snips[0]['value']
            },
            result=error_template,
        )

        # Delete existing snippet
        test_client.req(
            'delete',
            f'{url_base}/snippets/{snips[0]["id"]}',
            204,
        )
        snips = test_client.req(
            'get',
            f'{url_base}/snippets/',
            200,
            result=snips[1:],
        )

        # Shouldn't be able to change other course's snippets
        # This should return a 404 to minimize leaking information
        res = test_client.req(
            'patch',
            f'/api/v1/courses/{prolog_course.id}/snippets/{snips[0]["id"]}',
            404,
            data=snips[0],
            result=error_template,
        )

        res = test_client.req(
            'delete',
            f'/api/v1/courses/{prolog_course.id}/snippets/{snips[0]["id"]}',
            404,
            result=error_template,
        )

    with logged_in(ta_user):
        # TA user should only be able to view snippets
        test_client.req(
            'get',
            f'{url_base}/snippets/',
            200,
            result=snips,
        )

        # But they may not edit them.
        test_client.req(
            'put',
            f'{url_base}/snippet',
            403,
            result=error_template,
        )
        test_client.req(
            'patch',
            f'{url_base}/snippets/{snips[0]["id"]}',
            403,
            data={
                'key': snips[0]['key'],
                'value': 'new value'
            },
            result=error_template,
        )
        test_client.req(
            'delete',
            f'{url_base}/snippets/{snips[0]["id"]}',
            403,
            result=error_template,
        )

    with logged_in(student_user):
        # Student users may not use course snippets
        test_client.req(
            'get',
            f'{url_base}/snippets/',
            403,
            result=error_template,
        )

        # They can also not edit them
        test_client.req(
            'put',
            f'{url_base}/snippet',
            403,
            result=error_template,
        )
        test_client.req(
            'patch',
            f'{url_base}/snippets/{snips[0]["id"]}',
            403,
            data={
                'key': snips[0]['key'],
                'value': 'new value'
            },
            result=error_template,
        )
        test_client.req(
            'delete',
            f'{url_base}/snippets/{snips[0]["id"]}',
            403,
            result=error_template,
        )
예제 #14
0
def test_submit_with_group(
    test_client, session, logged_in, teacher_user, course, error_template,
    assignment, monkeypatch_celery
):
    user_full_group = create_user_with_perms(
        session, [CPerm.can_submit_own_work, CPerm.can_see_assignments], course
    )
    user_empty_group = create_user_with_perms(
        session, [CPerm.can_submit_own_work, CPerm.can_see_assignments], course
    )
    user_no_group = create_user_with_perms(
        session, [CPerm.can_submit_own_work, CPerm.can_see_assignments], course
    )
    user_no_perms = create_user_with_perms(
        session, [CPerm.can_see_assignments], course
    )

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, course.id, 2, 4)
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'group_set_id': g_set['id']}
        )
        g1 = create_group(
            test_client,
            g_set['id'],
            [user_full_group.id, user_no_perms.id],
        )
        create_group(test_client, g_set['id'], [user_empty_group.id])

    with logged_in(user_empty_group):
        err = create_submission(test_client, assignment.id, err=400)
        assert 'enough members' in err['message']

    with logged_in(user_no_perms):
        # Can't submit even if some users in the group can
        err = create_submission(test_client, assignment.id, err=403)

    with logged_in(user_no_group):
        # Can't submit as a user without group as the minimum size is 2
        err = create_submission(test_client, assignment.id, err=404)
        assert 'group was found' in err['message']

    with logged_in(user_full_group):
        # User can submit submission
        sub = create_submission(test_client, assignment.id)
        # Make sure submission is done as the group, not as the user
        assert sub['user']['group']['id'] == g1['id']

        # Make sure the user can see the just submitted submission
        test_client.req(
            'get',
            f'/api/v1/assignments/{assignment.id}/submissions/?extended',
            200,
            result=[sub]
        )
        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}?extended',
            200,
            result=sub
        )
        files = test_client.req(
            'get', f'/api/v1/submissions/{sub["id"]}/files/', 200
        )
        while 'entries' in files:
            files = files['entries'][0]
        code_id = files['id']
        response = test_client.get(f'/api/v1/code/{code_id}')
        assert response.status_code == 200
    with logged_in(teacher_user):
        test_client.req(
            'put',
            f'/api/v1/code/{code_id}/comments/3',
            204,
            data={'comment': 'Lekker gewerkt pik!'}
        )
        # Set state to done so the student can see its feedback
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'state': 'done'}
        )
    with logged_in(user_full_group):
        # Make sure we can see comments on the files
        test_client.req(
            'get',
            f'/api/v1/code/{code_id}?type=feedback',
            200,
            result={'3': {'line': 3, 'msg': 'Lekker gewerkt pik!'}}
        )
    with logged_in(teacher_user):
        # Reset state back
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'state': 'open'}
        )
예제 #15
0
def test_add_user_to_group(
    test_client, session, logged_in, teacher_user, prog_course, error_template
):
    user_only_own = create_user_with_perms(
        session, [CPerm.can_edit_own_groups], prog_course
    )
    user_other_too = create_user_with_perms(
        session, [CPerm.can_edit_others_groups], prog_course
    )
    nobody = create_user_with_perms(session, [], prog_course)

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, prog_course.id, 2, 4)
        g1 = create_group(
            test_client,
            g_set['id'],
            [create_user_with_perms(session, [], prog_course).id],
        )
        g2 = create_group(test_client, g_set['id'], [])

    with logged_in(user_only_own) as u:
        # Can add to group with members not including the user.
        g1 = test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/member',
            200,
            data={'username': u.username},
        )

        # Cannot add other user to group
        test_client.req(
            'post',
            f'/api/v1/groups/{g2["id"]}/member',
            403,
            data={'username': nobody.username}
        )

    with logged_in(user_other_too) as u:
        # Can add to empty group
        g2 = test_client.req(
            'post',
            f'/api/v1/groups/{g2["id"]}/member',
            200,
            data={'username': u.username},
        )

        # Can other user to a group
        test_client.req(
            'post',
            f'/api/v1/groups/{g2["id"]}/member',
            200,
            data={'username': nobody.username}
        )

        # Cannot add virtual user to a group
        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/member',
            400,
            data={
                'username': m.Group.query.get(g2['id']).virtual_user.username
            }
        )

        # user_only_own is already in g1 so we can't add this user to any group
        # too.
        for g in [g1, g2]:
            err = test_client.req(
                'post',
                f'/api/v1/groups/{g["id"]}/member',
                400,
                data={
                    'username': user_only_own.username,
                },
                result=error_template,
            )
            assert 'already in a group' in err['message']

        # Fill group g1
        for _ in range(2):
            test_client.req(
                'post',
                f'/api/v1/groups/{g1["id"]}/member',
                200,
                data={
                    'username':
                        create_user_with_perms(session, [],
                                               prog_course).username
                }
            )
        # Group is full so we can't add another user
        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/member',
            400,
            data={
                'username':
                    create_user_with_perms(session, [], prog_course).username
            },
            result=error_template
        )
예제 #16
0
def test_delete_group(
    test_client, logged_in, prog_course, session, teacher_user, error_template,
    app, monkeypatch_celery
):
    user_only_own = create_user_with_perms(
        session, [
            CPerm.can_edit_own_groups, CPerm.can_submit_own_work,
            CPerm.can_see_assignments
        ], prog_course
    )
    user_other_too = create_user_with_perms(
        session, [CPerm.can_edit_others_groups, CPerm.can_see_assignments],
        prog_course
    )

    with logged_in(teacher_user):
        assig_id = [
            a for a in test_client.
            req('get', f'/api/v1/courses/{prog_course.id}/assignments/', 200)
            if a['state'] == 'submitting'
        ][0]['id']

    with logged_in(teacher_user):
        group_set = create_group_set(test_client, prog_course.id, 2, 4)
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assig_id}',
            200,
            data={'group_set_id': group_set['id']}
        )

        group_own_id = create_group(
            test_client, group_set["id"], [
                create_user_with_perms(session, [], prog_course).id,
                user_only_own.id,
            ]
        )['id']
        group_others_id = create_group(
            test_client, group_set["id"], [
                create_user_with_perms(session, [], prog_course).id,
                create_user_with_perms(session, [], prog_course).id,
            ]
        )['id']
        group_empty_id = create_group(test_client, group_set["id"], [])['id']

    with logged_in(user_only_own):
        sub = create_submission(test_client, assig_id)
        assert sub['user']['group']

    with logged_in(user_only_own):
        # Cannot delete with submission
        test_client.req(
            'delete',
            f'/api/v1/groups/{group_own_id}',
            400,
            result=error_template
        )
        # Cannot delete non empty group of other members
        test_client.req(
            'delete',
            f'/api/v1/groups/{group_others_id}',
            403,
            result=error_template
        )
        # Can delete empty group
        test_client.req('delete', f'/api/v1/groups/{group_empty_id}', 204)

    with logged_in(user_other_too):
        # Cannot delete with submission
        test_client.req(
            'delete',
            f'/api/v1/groups/{group_own_id}',
            400,
            result=error_template
        )
        # Can delete non empty group of other members
        test_client.req('delete', f'/api/v1/groups/{group_others_id}', 204)

    with logged_in(teacher_user):
        test_client.req('delete', f'/api/v1/submissions/{sub["id"]}', 204)

    with logged_in(user_only_own):
        # Can delete now submission has been deleted
        test_client.req('delete', f'/api/v1/groups/{group_own_id}', 204)
예제 #17
0
def test_delete_group_set(
    test_client, logged_in, teacher_user, user_with_perms, prog_course,
    session, request, error_template
):
    assigs = list(prog_course.assignments)[:2]
    assert len(assigs) == 2
    with logged_in(teacher_user):
        group_set = create_group_set(test_client, prog_course.id, 2, 4)
        for assig in assigs:
            test_client.req(
                'patch',
                f'/api/v1/assignments/{assig.id}',
                200,
                data={'group_set_id': group_set['id']}
            )

        groups = [
            create_group(
                test_client, group_set["id"],
                [create_user_with_perms(session, [], prog_course).id]
            ) for _ in range(2)
        ]

    perm_err = request.node.get_closest_marker('perm_error')
    has_err = bool(perm_err)

    if perm_err:
        status = 403
    else:
        status = 400

    with logged_in(user_with_perms):
        test_client.req(
            'delete',
            f'/api/v1/group_sets/{group_set["id"]}',
            status,
            result=error_template
        )

    with logged_in(teacher_user):
        test_client.req(
            'get',
            f'/api/v1/group_sets/{group_set["id"]}',
            200,
        )

        for assig in assigs:
            test_client.req(
                'patch',
                f'/api/v1/assignments/{assig.id}',
                200,
                data={'group_set_id': None}
            )

    with logged_in(user_with_perms):
        # Still fails because there are groups
        test_client.req(
            'delete',
            f'/api/v1/group_sets/{group_set["id"]}',
            status,
            result=error_template
        )

    with logged_in(teacher_user):
        for group in groups:
            test_client.req(
                'delete',
                f'/api/v1/groups/{group["id"]}',
                204,
            )

    # Should now work as there are no groups anymore
    if perm_err:
        status = 403
    else:
        status = 204

    with logged_in(user_with_perms):
        test_client.req(
            'delete',
            f'/api/v1/group_sets/{group_set["id"]}',
            status,
            result=error_template if has_err else None
        )

    with logged_in(teacher_user):
        if not has_err:
            test_client.req(
                'get',
                f'/api/v1/group_sets/{group_set["id"]}',
                404,
            )
예제 #18
0
def test_update_group_set(
    test_client, logged_in, bs_course, prog_course, request, error_template,
    teacher_user, ta_user, assignment, session
):
    with logged_in(teacher_user):
        group_set = test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 1,
                'maximum_size': 3,
            },
            status_code=200,
        )

        # Update should be done in place
        group_set = test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 3,
                'maximum_size': 10,
                'id': group_set['id'],
            },
            status_code=200,
            result={
                'id': group_set['id'],
                'minimum_size': 3,
                'maximum_size': 10,
                'assignment_ids': [],
            },
        )
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'group_set_id': group_set['id']}
        )
        group_set['assignment_ids'].append(assignment.id)

        test_client.req(
            'get',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            200,
            result=[group_set]
        )

        # You should not be able to change the course id
        test_client.req(
            'put',
            f'/api/v1/courses/{prog_course.id}/group_sets/',
            data={
                'minimum_size': 3,
                'maximum_size': 10,
                'id': group_set['id'],
            },
            status_code=400,
            result=error_template,
        )

        # The group set now has a group with 3 members
        user = create_user_with_perms(session, [], bs_course)
        group = test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [teacher_user.id, ta_user.id, user.id]},
            status_code=200
        )
        test_client.req(
            'get',
            f'/api/v1/assignments/{assignment.id}/groups/{group["id"]}/member_states/',
            200,
            result={
                str(teacher_user.id): True,
                str(ta_user.id): True,
                str(user.id): True,
            }
        )
        # You should not be able to set the max size to lower than 3
        test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 1,
                'maximum_size': 2,
                'id': group_set['id'],
            },
            status_code=400,
            result=error_template,
        )

        # You SHOULD be able to set the min size to higher than 3 as there was
        # no submission by any group
        test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 4,
                'maximum_size': 10,
                'id': group_set['id'],
            },
            status_code=200,
            result={
                'minimum_size': 4,
                'maximum_size': 10,
                'id': group_set['id'],
                'assignment_ids': [assignment.id],
            }
        )

        # Reset back to minimum size of 3
        test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 3,
                'maximum_size': 4,
                'id': group_set['id'],
            },
            status_code=200,
        )

        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            200,
            data={'group_set_id': group_set['id']}
        )
        submission = create_submission(test_client, assignment.id)
        assert submission['user']['group']
        assert submission['user']['group']['id'] == group['id']

        # Now you should not be able to set the min size to higher than 3 as
        # there IS a submission by a group.
        test_client.req(
            'put',
            f'/api/v1/courses/{bs_course.id}/group_sets/',
            data={
                'minimum_size': 4,
                'maximum_size': 10,
                'id': group_set['id'],
            },
            status_code=400,
            result=error_template,
        )

        # You should also not be able to disconnect the group set for this
        # assignment
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            400,
            data={'group_set_id': None},
            result=error_template,
        )
        new_group_set = create_group_set(test_client, prog_course.id, 2, 4)
        # You should also not be able to change the group set for this
        # assignment
        test_client.req(
            'patch',
            f'/api/v1/assignments/{assignment.id}',
            400,
            data={'group_set_id': new_group_set['id']},
            result=error_template,
        )
예제 #19
0
 def make_empty_user():
     return create_user_with_perms(session, [], bs_course)
예제 #20
0
def test_update_lti_provider(
    test_client, describe, lms, iss, session, logged_in
):
    with describe('setup'):
        admin_user = helpers.create_user_with_perms(
            session, [], [], [GPerm.can_manage_lti_providers]
        )
        normal_user = helpers.create_user_with_perms(session, [], [], [])
        with logged_in(admin_user):
            prov = test_client.req(
                'post',
                '/api/v1/lti1.3/providers/',
                200,
                data={'lms': lms, 'iss': iss, 'intended_use': 'AA'},
            )
            url = f'/api/v1/lti1.3/providers/{helpers.get_id(prov)}'

    with describe('admin can update a provider'), logged_in(admin_user):
        prov = test_client.req('patch', url, 200, data={'client_id': 'aa'})
        test_client.req('get', '/api/v1/lti1.3/providers/', 200, result=[prov])

    with describe('normal user cannot update a provider'
                  ), logged_in(normal_user):
        test_client.req(
            'patch', url + '?secret=aa', 403, data={'auth_token_url': 'err'}
        )
        with logged_in(admin_user):
            test_client.req(
                'get', '/api/v1/lti1.3/providers/', 200, result=[prov]
            )

    with describe('normal user can update provider with secret'
                  ), logged_in(normal_user):
        test_client.req(
            'patch',
            f'{url}?secret={prov["edit_secret"]}',
            200,
            data={'auth_token_url': 'DEP 1'},
            result={
                **prov,
                'auth_token_url': 'DEP 1',
                'edit_secret': None,
            },
        )
        with logged_in(admin_user):
            prov, = test_client.req(
                'get',
                '/api/v1/lti1.3/providers/',
                200,
                result=[{**prov, 'auth_token_url': 'DEP 1'}]
            )

    with describe('cannot finalize before all info is filled in'
                  ), logged_in(admin_user):
        test_client.req('patch', url, 400, data={'finalize': True})

    with describe('Can also update the iss'), logged_in(admin_user):
        test_client.req(
            'patch',
            url,
            200,
            data={'iss': 'NEW ISS!!'},
            result={'__allow_extra__': True, 'iss': 'NEW ISS!!'},
        )

    with describe('cannot edit after it is finalized'), logged_in(admin_user):
        prov = test_client.req(
            'patch',
            url,
            200,
            data={
                'client_id': 'id',
                'auth_token_url': 'c',
                'auth_login_url': 'd',
                'key_set_url': 'asdf',
                'finalize': True,
            },
            result={'__allow_extra__': True, 'finalized': True}
        )
        test_client.req('patch', url, 403, data={'client_id': 'e'})
        test_client.req('get', url, 200, result=prov)
예제 #21
0
def test_create_extended_group(
    test_client, logged_in, user_with_perms, prog_course, request,
    error_template, teacher_user, session, bs_course
):
    with logged_in(teacher_user):
        group_set = create_group_set(test_client, prog_course.id, 2, 4)

    perm_err = request.node.get_closest_marker('perm_error')
    has_err = bool(perm_err)

    if perm_err:
        status = 403
    else:
        status = 200

    with logged_in(user_with_perms) as user:
        user1 = create_user_with_perms(session, [], prog_course)
        user2 = create_user_with_perms(session, [], prog_course)

        group = test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [user1.id]},
            status_code=status,
            result=error_template if has_err else {
                'id': int,
                'name': str,
                'members': list,
                'virtual_user': dict,
                'created_at': str,
                'group_set_id': group_set['id'],
            }
        )

        if not has_err:
            assert len(group['members']) == 1
            assert group['members'][0]['id'] == user1.id

        group = test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [user.id, user2.id]},
            status_code=status,
            result=error_template if has_err else {
                'id': int,
                'name': str,
                'members': list,
                'virtual_user': dict,
                'created_at': str,
                'group_set_id': group_set['id'],
            }
        )
        if not has_err:
            assert len(group['members']) == 2
    if has_err:
        return

    with logged_in(teacher_user) as user:
        user_not_in_course = create_user_with_perms(session, [], bs_course)
        # We should be able to create a normal group
        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [user.id]},
            status_code=200
        )

        # But not with users that are not in this course
        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [user_not_in_course.id]},
            status_code=400,
            result=error_template
        )

        # We can't be in a group twice
        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [user.id]},
            status_code=400
        )

        # We can't add users that don't exist
        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [10000000]},
            status_code=404
        )

        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'member_ids': [None]},
            status_code=400,
            result=error_template
        )
        test_client.req(
            'post',
            f'/api/v1/group_sets/{group_set["id"]}/group',
            data={'name': ['not', 'a', 'string']},
            status_code=400,
            result=error_template
        )
예제 #22
0
def test_seeing_teacher_revision_in_group(
    test_client, session, logged_in, teacher_user, course, error_template,
    assignment, describe
):
    with describe('setup'):
        user_other_group = create_user_with_perms(
            session, [
                CPerm.can_submit_own_work, CPerm.can_view_own_teacher_files,
                CPerm.can_see_assignments
            ], course
        )
        user_with_perm = create_user_with_perms(
            session, [
                CPerm.can_submit_own_work, CPerm.can_view_own_teacher_files,
                CPerm.can_see_assignments
            ], course
        )
        user_without_perm = create_user_with_perms(
            session, [CPerm.can_submit_own_work, CPerm.can_see_assignments],
            course
        )

        with logged_in(teacher_user):
            g_set = create_group_set(test_client, course.id, 1, 2)
            test_client.req(
                'patch',
                f'/api/v1/assignments/{assignment.id}',
                200,
                data={'group_set_id': g_set['id']}
            )
            g1 = create_group(
                test_client,
                g_set['id'],
                [user_with_perm, user_without_perm],
            )

        with logged_in(user_with_perm):
            sub = create_submission(test_client, assignment.id)
            # Submission is by the group
            assert sub['user']['group']['id'] == g1['id']

            student_files = test_client.req(
                'get', f'/api/v1/submissions/{sub["id"]}/files/', 200
            )

    with describe('Cannot view teacher files while assig is open'
                  ), logged_in(user_with_perm):
        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}/files/?owner=teacher',
            403,
            result=error_template,
        )

    with describe('Can see teacher files after assig is done'
                  ), logged_in(user_with_perm):
        assignment.set_state_with_string('done')
        session.commit()

        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}/files/?owner=teacher',
            200,
            result=student_files,
        )

        # This marks all files as from the student revision, i.e. there are no
        # teacher files.
        m.File.query.filter(
            m.File.work_id == sub['id'], m.File.parent_id.isnot(None)
        ).update({'fileowner': m.FileOwner.student})

        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}/files/?owner=teacher',
            200,
            result={
                **student_files,
                'entries': [],
            }
        )

    with describe(
        'User without permission to see own teacher files gets an error'
    ), logged_in(user_without_perm):
        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}/files/?owner=teacher',
            403,
            result=error_template,
        )

    with describe('User from other group cannot see teacher files'
                  ), logged_in(user_other_group):
        test_client.req(
            'get',
            f'/api/v1/submissions/{sub["id"]}/files/?owner=teacher',
            403,
            result=error_template,
        )
예제 #23
0
def test_add_feedback(request, logged_in, test_client, session, data,
                      error_template, admin_user, mail_functions, describe,
                      tomorrow):
    with describe('setup'), logged_in(admin_user):
        assignment = helpers.create_assignment(test_client,
                                               state='open',
                                               deadline=tomorrow)
        course = assignment['course']
        teacher = admin_user
        student = helpers.create_user_with_perms(session,
                                                 [CPerm.can_submit_own_work],
                                                 course)
        work = helpers.create_submission(test_client,
                                         assignment,
                                         for_user=student)

        data_err = request.node.get_closest_marker('data_error') is not None

        code_id = session.query(m.File.id).filter(
            m.File.work_id == work['id'],
            m.File.parent_id.isnot(None),
            m.File.name != '__init__',
        ).first()[0]

        if data_err:
            code = 400
        else:
            code = 204

        def get_result(has_author=True):
            if data_err:
                return {}
            msg = data.get('expected_result', data['comment'])
            res = {
                '0': {
                    'line': 0,
                    'msg': msg,
                    'author': {
                        'id': teacher.id,
                        '__allow_extra__': True
                    },
                }
            }
            if not has_author:
                res['0'].pop('author')
            return res

    with describe('teacher can place comments'), logged_in(teacher):
        test_client.req('put',
                        f'/api/v1/code/{code_id}/comments/0',
                        code,
                        data=data,
                        result=None if code == 204 else error_template)
        if data_err:
            assert not mail_functions.any_mails()
            return
        assert not mail_functions.any_mails(), 'Student should not be mailed'

        res = test_client.req('get',
                              f'/api/v1/code/{code_id}',
                              200,
                              query={'type': 'feedback'},
                              result=get_result())

        data = {
            'comment': 'bye',
            'expected_result': 'bye',
        }
        test_client.req(
            'put',
            f'/api/v1/code/{code_id}/comments/0',
            code,
            data=data,
        )
        assert not mail_functions.any_mails(), 'No mails for updates'

        test_client.req('get',
                        f'/api/v1/code/{code_id}',
                        200,
                        query={'type': 'feedback'},
                        result=get_result())

    with describe(
            'Students cannot place comments if they do not have the permission'
    ), logged_in(student):
        test_client.req('put',
                        f'/api/v1/code/{code_id}/comments/1',
                        403,
                        data=data)

    with describe('Students can get comments when assignment is done'):
        with logged_in(student):
            test_client.req(
                'get',
                f'/api/v1/code/{code_id}',
                200,
                query={'type': 'feedback'},
                result={},
            )

            # We don't have the permission to see the notification
            test_client.req('get',
                            '/api/v1/notifications/',
                            200,
                            result={'notifications': []})
            test_client.req('get',
                            '/api/v1/notifications/?has_unread',
                            200,
                            result={'has_unread': False})

        with logged_in(teacher):
            test_client.req(
                'patch',
                f'/api/v1/assignments/{assignment["id"]}',
                200,
                data={'state': 'done'},
            )
            assert not mail_functions.any_mails(), (
                'Should not send old notifications when state changes')

        with logged_in(student):
            test_client.req(
                'get',
                f'/api/v1/code/{code_id}',
                200,
                query={'type': 'feedback'},
                result=get_result(has_author=False),
            )
            # Now we do have this permission
            test_client.req('get',
                            '/api/v1/notifications/',
                            200,
                            result={
                                'notifications': [{
                                    'id': int,
                                    'reasons': [['author', str]],
                                    '__allow_extra__': True,
                                    'read': False,
                                    'file_id': code_id,
                                }]
                            })
            test_client.req('get',
                            '/api/v1/notifications/?has_unread',
                            200,
                            result={'has_unread': True})

    with describe('Cannot get or update feedback after deleting submission'
                  ), logged_in(teacher):
        test_client.req('delete', f'/api/v1/submissions/{work["id"]}', 204)

        test_client.req(
            'get',
            f'/api/v1/code/{code_id}',
            404,
            query={'type': 'feedback'},
            result=error_template,
        )
        test_client.req(
            'put',
            f'/api/v1/code/{code_id}/comments/0',
            404,
            data={'comment': 'Any value'},
            result=error_template,
        )

    with describe('After delete notification should be gone'), logged_in(
            student):
        test_client.req('get',
                        '/api/v1/notifications/',
                        200,
                        result={'notifications': []})
        test_client.req('get',
                        '/api/v1/notifications/?has_unread',
                        200,
                        result={'has_unread': False})
예제 #24
0
def test_get_assignment_all_feedback(named_user, request, logged_in,
                                     test_client, assignment_real_works,
                                     session, error_template, ta_user,
                                     monkeypatch_celery, teacher_user):
    assignment, work = assignment_real_works
    assig_id = assignment.id
    perm_err = request.node.get_closest_marker('perm_error')
    only_own_subs = request.node.get_closest_marker('only_own')

    code_id = session.query(m.File.id).filter(
        m.File.work_id == work['id'],
        m.File.parent != None,  # NOQA
        m.File.name != '__init__',
    ).first()[0]

    with logged_in(ta_user):
        res = test_client.req('patch',
                              f'/api/v1/submissions/{work["id"]}',
                              200,
                              data={
                                  'grade': 5,
                                  'feedback': 'Niet zo goed\0'
                              },
                              result=dict)
        test_client.req(
            'put',
            f'/api/v1/code/{code_id}/comments/0',
            204,
            data={'comment': 'for line 0'},
        )
        test_client.req(
            'put',
            f'/api/v1/code/{code_id}/comments/1',
            204,
            data={'comment': 'for line - 1'},
        )

    with logged_in(teacher_user):
        test_client.req('post',
                        f'/api/v1/assignments/{assignment.id}/linter',
                        200,
                        data={
                            'name': 'Flake8',
                            'cfg': ''
                        })

    def match_res(res, only_own_subs=only_own_subs):
        general = 'Niet zo goed'
        user = ['test.py:1:1: for line 0', 'test.py:2:1: for line - 1']
        assert len(res) == 1 if only_own_subs else 3
        linter = None

        for key, val in res.items():
            if key == str(work['id']):
                assert val['user'] == user
                assert val['general'] == general
                assert len(val['linter']) >= 1
            else:
                assert not val['user']
                assert val['general'] == ''
                assert len(val['linter']) >= 1

            if linter is None:
                linter = val['linter']
            else:
                assert linter == val['linter']

    with logged_in(named_user):
        if perm_err:
            code = perm_err.kwargs['error']
        else:
            code = 200

        if only_own_subs:
            ex_res = {
                str(work["id"]): {
                    'user': [],
                    'linter': [],
                    'general': ''
                }
            }
        elif code == 200:
            ex_res = dict
        else:
            ex_res = error_template
        res = test_client.req(
            'get',
            f'/api/v1/assignments/{assig_id}/feedbacks/',
            code,
            result=ex_res,
        )

        if not (perm_err or only_own_subs):
            match_res(res)

    assig = session.query(m.Assignment).get(assig_id)
    assig.state = m.AssignmentStateEnum.done
    session.commit()

    with logged_in(named_user):
        res = test_client.req(
            'get',
            f'/api/v1/assignments/{assig_id}/feedbacks/',
            code,
            result=dict if code == 200 else error_template,
        )

        if not perm_err:
            match_res(res)

    with logged_in(
            helpers.create_user_with_perms(session,
                                           [CPerm.can_see_others_work],
                                           assig.course)):
        res = test_client.req(
            'get',
            f'/api/v1/assignments/{assig_id}/feedbacks/',
            200,
            result=dict,
        )

        if not perm_err:

            match_res(res, only_own_subs=False)
예제 #25
0
def user_with_perms(session, request, course_name):
    course = session.query(m.Course).filter_by(name=course_name).one()
    yield create_user_with_perms(session, request.param, course)
예제 #26
0
def test_impersonate(logged_in, describe, test_client, session):
    with describe('setup'):
        admin_password = '******'
        user_password = '******'

        with_perm = create_user_with_perms(
            session, [], [], [GlobalPermission.can_impersonate_users])
        no_perm = create_user_with_perms(session, [], [], [])
        with_perm.password = admin_password
        no_perm.password = admin_password

        active = create_user_with_perms(session, [], [])
        not_active = create_user_with_perms(session, [], [])
        not_active.active = False
        active.password = user_password
        not_active.password = user_password

        session.commit()

    with describe('no perm cannot impersonate'), logged_in(no_perm):
        test_client.req('post',
                        '/api/v1/login?impersonate',
                        403,
                        data={
                            'username': active.username,
                            'own_password': admin_password,
                        })

        test_client.req('post',
                        '/api/v1/login?impersonate',
                        403,
                        data={
                            'username': active.username,
                            'own_password': user_password,
                        })

    with describe('with perm can impersonate'), logged_in(with_perm):
        # Does not work with users password
        test_client.req('post',
                        '/api/v1/login?impersonate',
                        403,
                        data={
                            'username': active.username,
                            'own_password': user_password
                        })

        # Does work with own password
        test_client.req('post',
                        '/api/v1/login?impersonate',
                        200,
                        data={
                            'username': active.username,
                            'own_password': admin_password
                        },
                        result={
                            'user': {
                                '__allow_extra__': True,
                                'username': active.username,
                                'email': active.email,
                            },
                            'access_token': str,
                        })

    with describe('cannot impersonate non active user'), logged_in(with_perm):
        test_client.req('post',
                        '/api/v1/login?impersonate',
                        404,
                        data={
                            'username': not_active.username,
                            'own_password': admin_password
                        })

    with describe('cannot impersonate while not logged in'):
        test_client.req('post',
                        '/api/v1/login?impersonate',
                        401,
                        data={
                            'username': active.username,
                            'own_password': admin_password
                        })
예제 #27
0
def test_enabling_login_links(
    describe, test_client, logged_in, admin_user, yesterday, session,
    stub_function, app, monkeypatch, tomorrow, error_template
):
    with describe('setup'), logged_in(admin_user):
        send_mail_stub = stub_function(psef.mail, 'send_login_link_mail')
        assig = helpers.create_assignment(test_client)
        assig_id = helpers.get_id(assig)
        course = helpers.get_id(assig['course'])
        url = f'/api/v1/assignments/{assig_id}?no_course_in_assignment=t'
        teacher = helpers.create_user_with_perms(
            session, [
                CPerm.can_see_assignments,
                CPerm.can_see_hidden_assignments,
                CPerm.can_view_analytics,
                CPerm.can_edit_assignment_info,
            ], course
        )
        no_perm = helpers.create_user_with_perms(
            session, [
                CPerm.can_see_assignments,
                CPerm.can_see_hidden_assignments,
                CPerm.can_view_analytics,
            ], course
        )
        # Make sure there are users to email
        for _ in range(10):
            helpers.create_user_with_role(session, 'Student', course)

    with describe('cannot enable login links for wrong kind'
                  ), logged_in(teacher):
        test_client.req('patch', url, 409, data={'send_login_links': True})
        _, rv = test_client.req(
            'patch',
            url,
            200,
            data={
                'deadline': yesterday.isoformat(),
                'available_at': (yesterday - timedelta(minutes=1)).isoformat(),
                'kind': 'exam',
                'send_login_links': True,
            },
            result={
                '__allow_extra__': True,
                'send_login_links': True,
            },
            include_response=True,
        )
        warning = rv.headers['warning']
        assert re.match(r'.*deadline.*expired.*not send', warning)
        assert not send_mail_stub.called

    with describe('cannot enable login links for wrong kind'
                  ), logged_in(teacher):
        test_client.req('patch', url, 409, data={'kind': 'normal'})
        assert not send_mail_stub.called

    with describe('cannot change login links with incorrect perms'
                  ), logged_in(no_perm):
        test_client.req('patch', url, 403, data={'send_login_links': False})
        assert not send_mail_stub.called

    with describe('Setting again does nothing'), logged_in(teacher):
        old_token = m.Assignment.query.get(assig_id).send_login_links_token
        test_client.req(
            'patch',
            url,
            200,
            data={
                'send_login_links': True,
                'available_at': (yesterday - timedelta(minutes=1)).isoformat(),
            }
        )
        new_token = m.Assignment.query.get(assig_id).send_login_links_token
        assert new_token == old_token
        assert not send_mail_stub.called

    with describe('Changing available at reschedules links'
                  ), logged_in(teacher):
        old_token = m.Assignment.query.get(assig_id).send_login_links_token
        test_client.req(
            'patch',
            url,
            200,
            data={
                'send_login_links': True,
                'available_at': (yesterday - timedelta(minutes=2)).isoformat(),
            }
        )
        new_token = m.Assignment.query.get(assig_id).send_login_links_token
        assert new_token != old_token
        assert new_token is not None
        assert not send_mail_stub.called

    with describe('Disabling clears token'), logged_in(teacher):
        test_client.req('patch', url, 200, data={'send_login_links': False})
        new_token = m.Assignment.query.get(assig_id).send_login_links_token
        assert new_token is None
        assert not send_mail_stub.called

    with describe('Cannot enable login links with large availability window'
                  ), logged_in(teacher):
        psef.site_settings.Opt.EXAM_LOGIN_MAX_LENGTH.set_and_commit_value(
            'P1D'
        )
        test_client.req(
            'patch',
            url,
            409,
            data={
                'send_login_links': True,
                'deadline': tomorrow.isoformat(),
                'available_at': yesterday.isoformat(),
            },
            result={
                **error_template, 'message':
                    re.compile(
                        'Login links can only be enabled if the deadline is at'
                        ' most 24 hours after.*'
                    )
            }
        )
예제 #28
0
def test_change_name_of_group(
    test_client, logged_in, error_template, prog_course, session, teacher_user
):
    new_name = f'NEW_NAME-{uuid.uuid4()}'

    def check_name(name):
        name_to_check = g1['name'] if name is None else name
        with logged_in(teacher_user):
            assert g_model.get_readable_name() == f'group "{name_to_check}"'
            return test_client.req(
                'get',
                f'/api/v1/groups/{g1["id"]}',
                200,
                result={**g1, 'name': name_to_check}
            )

    u1 = create_user_with_perms(
        session, [CPerm.can_edit_own_groups], prog_course
    )
    u2 = create_user_with_perms(
        session, [CPerm.can_edit_own_groups], prog_course
    )
    u3 = create_user_with_perms(
        session, [CPerm.can_edit_own_groups], prog_course
    )

    with logged_in(teacher_user):
        g_set = create_group_set(test_client, prog_course.id, 2, 4)
        g1 = create_group(
            test_client,
            g_set['id'],
            [u1.id, u2.id],
        )
        g_model = LocalProxy(
            lambda: m.User.query.get(g1['virtual_user']['id'])
        )

    with logged_in(u3):
        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/name',
            403,
            data={'name': new_name}
        )
        check_name(None)

    with logged_in(u1):
        # u1 is member so it can change the name
        old_name = g1['name']
        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/name',
            200,
            data={'name': new_name}
        )
        check_name(new_name)

        # Reset back to old name
        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/name',
            200,
            data={'name': old_name}
        )
        check_name(old_name)

        test_client.req(
            'post',
            f'/api/v1/groups/{g1["id"]}/name',
            400,
            data={'name': 'sh'},  # This name is too short
            result=error_template
        )
        check_name(None)