Пример #1
0
def create_new_assignment(course_id: int) -> JSONResponse[models.Assignment]:
    """Create a new course for the given assignment.

    .. :quickref: Course; Create a new assignment in a course.

    :param int course_id: The course to create an assignment in.

    :<json str name: The name of the new assignment.

    :returns: The newly created assignment.
    """
    with get_from_map_transaction(get_json_dict_from_request()) as [get, _]:
        name = get('name', str)

    course = helpers.get_or_404(
        models.Course,
        course_id,
        also_error=lambda c: c.virtual,
    )

    assig = models.Assignment(
        name=name,
        course=course,
        is_lti=False,
    )
    auth.AssignmentPermissions(assig).ensure_may_add()
    db.session.add(assig)
    db.session.commit()

    return jsonify(assig)
Пример #2
0
def assignment(course_name, state_is_hidden, session, request, with_works):
    course = m.Course.query.filter_by(name=course_name).one()
    state = (
        m.AssignmentStateEnum.hidden
        if state_is_hidden else m.AssignmentStateEnum.open
    )
    assig = m.Assignment(
        name='TEST COURSE',
        state=state,
        course=course,
        deadline=DatetimeWithTimezone.utcnow() +
        datetime.timedelta(days=1 if request.param == 'new' else -1),
        is_lti=False,
    )
    session.add(assig)
    session.commit()

    if with_works:
        names = ['Student1', 'Student2', 'Student3', 'Œlµo']
        if with_works != 'single':
            names += names
        for uname in names:
            user = m.User.query.filter_by(name=uname).one()
            work = m.Work(assignment=assig, user=user)
            session.add(work)
        session.commit()

    yield assig
Пример #3
0
def create_new_assignment(course_id: int) -> JSONResponse[models.Assignment]:
    """Create a new course for the given assignment.

    .. :quickref: Course; Create a new assignment in a course.

    :param int course_id: The course to create an assignment in.

    :<json str name: The name of the new assignment.

    :returns: The newly created assignment.

    :raises PermissionException: If the current user does not have the
        ``can_create_assignment`` permission (INCORRECT_PERMISSION).
    """
    auth.ensure_permission('can_create_assignment', course_id)

    content = ensure_json_dict(request.get_json())
    ensure_keys_in_dict(content, [('name', str)])
    name = t.cast(str, content['name'])

    course = helpers.get_or_404(models.Course, course_id)

    if course.lti_course_id is not None:
        raise APIException('You cannot add assignments to a LTI course',
                           f'The course "{course_id}" is a LTI course',
                           APICodes.INVALID_STATE, 400)

    assig = models.Assignment(name=name,
                              course=course,
                              deadline=datetime.datetime.utcnow())
    db.session.add(assig)
    db.session.commit()

    return jsonify(assig)
Пример #4
0
def create_new_assignment(course_id: int) -> JSONResponse[models.Assignment]:
    """Create a new course for the given assignment.

    .. :quickref: Course; Create a new assignment in a course.

    :param int course_id: The course to create an assignment in.

    :<json str name: The name of the new assignment.

    :returns: The newly created assignment.

    :raises PermissionException: If the current user does not have the
        ``can_create_assignment`` permission (INCORRECT_PERMISSION).
    """
    auth.ensure_permission(CPerm.can_create_assignment, course_id)

    content = get_json_dict_from_request()
    ensure_keys_in_dict(content, [('name', str)])
    name = t.cast(str, content['name'])

    course = helpers.get_or_404(
        models.Course,
        course_id,
        also_error=lambda c: c.virtual,
    )

    if course.lti_provider is not None:
        lms = course.lti_provider.lms_name
        raise APIException(f'You cannot add assignments to a {lms} course',
                           f'The course "{course_id}" is a LTI course',
                           APICodes.INVALID_STATE, 400)

    assig = models.Assignment(
        name=name,
        course=course,
        is_lti=False,
    )
    db.session.add(assig)
    db.session.commit()

    return jsonify(assig)
Пример #5
0
def create_lti_assignment(session,
                          course,
                          state='hidden',
                          deadline='tomorrow'):
    name = f'__NEW_LTI_ASSIGNMENT__-{uuid.uuid4()}'

    if deadline == 'tomorrow':
        deadline = DatetimeWithTimezone.utcnow() + datetime.timedelta(days=1)

    res = m.Assignment(
        name=name,
        course=course,
        deadline=deadline,
        lti_assignment_id=str(uuid.uuid4()),
        is_lti=True,
    )
    res.lti_grade_service_data = str(uuid.uuid4())
    res.set_state_with_string(state)
    session.add(res)
    session.commit()
    return res
Пример #6
0
    def get_assignment(self, user: models.User) -> models.Assignment:
        """Get the current LTI assignment as a psef assignment.
        """
        assignment = models.Assignment.query.filter_by(
            lti_assignment_id=self.assignment_id).first()
        if assignment is None:
            course = self.get_course()
            assignment = models.Assignment(
                name=self.assignment_name,
                state=self.assignment_state,
                course_id=course.id,
                deadline=self.get_assignment_deadline(),
                lti_assignment_id=self.assignment_id,
                description='')
            db.session.add(assignment)
            db.session.flush()

        if self.has_result_sourcedid():
            if assignment.id in user.assignment_results:
                user.assignment_results[
                    assignment.id].sourcedid = self.result_sourcedid
            else:
                assig_res = models.AssignmentResult(
                    sourcedid=self.result_sourcedid,
                    user_id=user.id,
                    assignment_id=assignment.id)
                db.session.add(assig_res)

        assignment.lti_outcome_service_url = self.outcome_service_url

        if not assignment.is_done:
            assignment.state = self.assignment_state

        assignment.deadline = self.get_assignment_deadline(
            default=assignment.deadline)

        db.session.flush()

        return assignment
Пример #7
0
def test_data(db=None):
    db = db or psef.models.db

    if not app.config['DEBUG']:
        print('You can not add test data in production mode', file=sys.stderr)
        return 1

    seed()
    db.session.commit()
    with open(
        f'{os.path.dirname(os.path.abspath(__file__))}/test_data/courses.json',
        'r'
    ) as c:
        cs = json.load(c)
        for c in cs:
            if m.Course.query.filter_by(name=c['name']).first() is None:
                db.session.add(m.Course(name=c['name']))
    db.session.commit()
    with open(
        f'{os.path.dirname(os.path.abspath(__file__))}/test_data/assignments.json',
        'r'
    ) as c:
        cs = json.load(c)
        for c in cs:
            assig = m.Assignment.query.filter_by(name=c['name']).first()
            if assig is None:
                db.session.add(
                    m.Assignment(
                        name=c['name'],
                        deadline=datetime.datetime.utcnow() +
                        datetime.timedelta(days=c['deadline']),
                        state=c['state'],
                        description=c['description'],
                        course=m.Course.query.filter_by(name=c['course']
                                                        ).first()
                    )
                )
            else:
                assig.description = c['description']
                assig.state = c['state']
                assig.course = m.Course.query.filter_by(name=c['course']
                                                        ).first()
    db.session.commit()
    with open(
        f'{os.path.dirname(os.path.abspath(__file__))}/test_data/users.json',
        'r'
    ) as c:
        cs = json.load(c)
        for c in cs:
            u = m.User.query.filter_by(name=c['name']).first()
            courses = {
                m.Course.query.filter_by(name=name).first(): role
                for name, role in c['courses'].items()
            }
            perms = {
                course.id:
                m.CourseRole.query.filter_by(name=name,
                                             course_id=course.id).first()
                for course, name in courses.items()
            }
            username = c['name'].split(' ')[0].lower()
            if u is not None:
                u.name = c['name']
                u.courses = perms
                u.email = c['name'].replace(' ', '_').lower() + '@example.com'
                u.password = c['name']
                u.username = username
                u.role = m.Role.query.filter_by(name=c['role']).first()
            else:
                u = m.User(
                    name=c['name'],
                    courses=perms,
                    email=c['name'].replace(' ', '_').lower() + '@example.com',
                    password=c['name'],
                    username=username,
                    role=m.Role.query.filter_by(name=c['role']).first()
                )
                db.session.add(u)
                for course, role in courses.items():
                    if role == 'Student':
                        for assig in course.assignments:
                            work = m.Work(assignment=assig, user=u)
                            db.session.add(
                                m.File(
                                    work=work,
                                    name='Top stub dir',
                                    is_directory=True
                                )
                            )
                            db.session.add(work)
    db.session.commit()
    with open(
        f'{os.path.dirname(os.path.abspath(__file__))}/test_data/rubrics.json',
        'r'
    ) as c:
        cs = json.load(c)
        for c in cs:
            for row in c['rows']:
                assignment = m.Assignment.query.filter_by(
                    name=c['assignment']
                ).first()
                if assignment is not None:
                    rubric_row = m.RubricRow.query.filter_by(
                        header=row['header'],
                        description=row['description'],
                        assignment_id=assignment.id
                    ).first()
                    if rubric_row is None:
                        rubric_row = m.RubricRow(
                            header=row['header'],
                            description=row['description'],
                            assignment=assignment
                        )
                        db.session.add(rubric_row)
                    for item in row['items']:
                        if not db.session.query(
                            m.RubricItem.query.filter_by(
                                rubricrow_id=rubric_row.id,
                                **item,
                            ).exists()
                        ).scalar():
                            rubric_item = m.RubricItem(
                                description=item['description'] * 5,
                                header=item['header'],
                                points=item['points'],
                                rubricrow=rubric_row
                            )
                            db.session.add(rubric_item)
    db.session.commit()
Пример #8
0
def test_data(db=None):
    db = psef.models.db if db is None else db

    if not app.config['DEBUG']:
        print('You can not add test data in production mode', file=sys.stderr)
        return 1
    if not os.path.isdir(app.config['UPLOAD_DIR']):
        os.mkdir(app.config['UPLOAD_DIR'])

    seed()
    db.session.commit()
    with open(
            f'{os.path.dirname(os.path.abspath(__file__))}/test_data/courses.json',
            'r') as c:
        cs = json.load(c)
        for c in cs:
            if m.Course.query.filter_by(name=c['name']).first() is None:
                db.session.add(m.Course.create_and_add(name=c['name']))
    db.session.commit()
    with open(
            f'{os.path.dirname(os.path.abspath(__file__))}/test_data/assignments.json',
            'r') as c:
        cs = json.load(c)
        for c in cs:
            assig = m.Assignment.query.filter_by(name=c['name']).first()
            if assig is None:
                db.session.add(
                    m.Assignment(
                        name=c['name'],
                        deadline=cg_dt_utils.now() +
                        datetime.timedelta(days=c['deadline']),
                        state=c['state'],
                        description=c['description'],
                        course=m.Course.query.filter_by(
                            name=c['course']).first(),
                        is_lti=False,
                    ))
            else:
                assig.description = c['description']
                assig.state = c['state']
                assig.course = m.Course.query.filter_by(
                    name=c['course']).first()
    db.session.commit()
    with open(
            f'{os.path.dirname(os.path.abspath(__file__))}/test_data/users.json',
            'r') as c:
        cs = json.load(c)
        for c in cs:
            u = m.User.query.filter_by(name=c['name']).first()
            courses = {
                m.Course.query.filter_by(name=name).first(): role
                for name, role in c['courses'].items()
            }
            perms = {
                course.id:
                m.CourseRole.query.filter_by(name=name,
                                             course_id=course.id).first()
                for course, name in courses.items()
            }
            username = c['name'].split(' ')[0].lower()
            if u is not None:
                u.name = c['name']
                u.courses = perms
                u.email = c['name'].replace(' ', '_').lower() + '@example.com'
                u.password = c['name']
                u.username = username
                u.role = m.Role.query.filter_by(name=c['role']).first()
            else:
                u = m.User(name=c['name'],
                           courses=perms,
                           email=c['name'].replace(' ', '_').lower() +
                           '@example.com',
                           password=c['name'],
                           username=username,
                           role=m.Role.query.filter_by(name=c['role']).first())
                db.session.add(u)
                for course, role in courses.items():
                    if role == 'Student':
                        for assig in course.assignments:
                            work = m.Work(assignment=assig, user=u)
                            f = m.File(work=work,
                                       name='Top stub dir ({})'.format(u.name),
                                       is_directory=True)
                            filename = str(uuid.uuid4())
                            shutil.copyfile(
                                __file__,
                                os.path.join(app.config['UPLOAD_DIR'],
                                             filename))
                            f.children = [
                                m.File(work=work,
                                       name='manage.py',
                                       is_directory=False,
                                       filename=filename)
                            ]
                            db.session.add(f)
                            db.session.add(work)
    db.session.commit()
    with open(
            f'{os.path.dirname(os.path.abspath(__file__))}/test_data/rubrics.json',
            'r') as c:
        cs = json.load(c)
        for c in cs:
            for row in c['rows']:
                assignment = m.Assignment.query.filter_by(
                    name=c['assignment']).first()
                if assignment is not None:
                    rubric_row = m.RubricRow.query.filter_by(
                        header=row['header'],
                        description=row['description'],
                        assignment_id=assignment.id,
                    ).first()
                    if rubric_row is None:
                        rubric_row = m.RubricRow(
                            header=row['header'],
                            description=row['description'],
                            assignment=assignment,
                            rubric_row_type='normal',
                        )
                        db.session.add(rubric_row)
                    for item in row['items']:
                        if not db.session.query(
                                m.RubricItem.query.filter_by(
                                    rubricrow_id=rubric_row.id,
                                    **item,
                                ).exists()).scalar():
                            rubric_item = m.RubricItem(
                                description=item['description'] * 5,
                                header=item['header'],
                                points=item['points'],
                                rubricrow=rubric_row)
                            db.session.add(rubric_item)
    db.session.commit()
Пример #9
0
def test_connecting_users_and_courses_lti1p1_provider(
        test_client, describe, logged_in, admin_user, stub_function,
        monkeypatched_passback, session, connect, canvas_lti1p1_provider,
        watch_signal, add_user_data, add_course_data, add_assig_data):
    with describe('setup'), logged_in(admin_user):
        watch_signal(signals.USER_ADDED_TO_COURSE, clear_all_but=[])

        old_lti_context_id = str(uuid.uuid4())
        new_lti_context_id = str(uuid.uuid4())
        old_resource_id = str(uuid.uuid4())
        new_resource_id = str(uuid.uuid4())

        original_user = helpers.create_user_with_role(session, 'Student', [])
        session.commit()

        old_lti_user_id = str(uuid.uuid4())
        assert original_user
        session.add(
            m.UserLTIProvider(user=original_user,
                              lti_provider=canvas_lti1p1_provider,
                              lti_user_id=old_lti_user_id))
        course = m.Course.create_and_add(name='LTI COURSE JEE')
        m.CourseLTIProvider.create_and_add(
            course=course,
            lti_provider=canvas_lti1p1_provider,
            lti_context_id=old_lti_context_id,
            deployment_id=old_lti_context_id,
        )
        assig = m.Assignment(course=course,
                             name='Name',
                             is_lti=True,
                             lti_assignment_id=old_resource_id)
        session.add(assig)
        session.commit()

        provider = helpers.create_lti1p3_provider(
            test_client,
            'Canvas',
            iss='https://canvas.instructure.com',
            client_id=str(uuid.uuid4()) + '_lms=' + 'Canvas')
        provider = helpers.to_db_object(provider, m.LTI1p3Provider)
        if connect:
            provider._updates_lti1p1 = canvas_lti1p1_provider
            session.commit()

        lti_user_id = str(uuid.uuid4())
        data = make_launch_data(
            CANVAS_DATA,
            provider,
            {
                'Assignment.id': new_resource_id,
                'Course.id': new_lti_context_id,
                'User.id': lti_user_id,
            },
        )
        to_merge = {}
        if add_course_data:
            to_merge['context_id'] = old_lti_context_id
        if add_user_data:
            to_merge['user_id'] = old_lti_user_id
        if add_assig_data:
            to_merge['resource_link_id'] = old_resource_id
        extra_data = {
            "https://purl.imsglobal.org/spec/lti/claim/lti1p1": to_merge,
        }

    with describe('should create a user with the given email'):
        complete_data = merge(data, extra_data)

        _, launch = do_oidc_and_lti_launch(test_client, provider,
                                           complete_data, 200)
        new_user = m.UserLTIProvider.query.filter_by(
            lti_user_id=lti_user_id).one().user

        if connect and add_user_data:
            assert new_user.id == original_user.id
        else:
            assert new_user.id != original_user.id

        if connect and add_course_data:
            assert launch['data']['course']['id'] == course.id
        else:
            assert launch['data']['course']['id'] != course.id

        if connect and add_assig_data and add_course_data:
            assert launch['data']['assignment']['id'] == assig.id
            assert m.Assignment.query.get(
                assig.id).lti_assignment_id == new_resource_id
        else:
            assert launch['data']['assignment']['id'] != assig.id