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)
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
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)
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)
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
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
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()
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()
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