def get_course_by_id(course_id: int) -> ExtendedJSONResponse[models.Course]: """Return course data for a given :class:`.models.Course`. .. :quickref: Course; Get data for a given course. :param int course_id: The id of the course :returns: A response containing the JSON serialized course :>json str role: The name of the role the current user has in this course. :>json ``**rest``: JSON serialization of :py:class:`psef.models.Course`. :raises APIException: If there is no course with the given id. (OBJECT_ID_NOT_FOUND) :raises PermissionException: If there is no logged in user. (NOT_LOGGED_IN) """ course = helpers.get_or_404(models.Course, course_id) auth.CoursePermissions(course).ensure_may_see() if not helpers.request_arg_true('no_role_name'): helpers.add_deprecate_warning( 'Getting the role of the current user in the requested course is' ' deprecated and will be removed in the next major version of' ' CodeGrade') helpers.jsonify_options.get_options().add_role_to_course = True return ExtendedJSONResponse.make(course, use_extended=models.Course)
def update_course(course_id: int) -> ExtendedJSONResponse[models.Course]: """Update the given :class:`.models.Course` with new values. .. :quickref: Course; Update course data. :param int course_id: The id of the course you want to update. :returns: The updated course, in extended format. """ data = rqa.FixedMapping( rqa.OptionalArgument( 'name', rqa.SimpleValue.str, 'The new name of the course', ), rqa.OptionalArgument( 'state', rqa.EnumValue(models.CourseState), """ The new state of the course, currently you cannot set the state of a course to 'deleted' """, )).from_flask() course = helpers.get_or_404(models.Course, course_id) checker = auth.CoursePermissions(course) checker.ensure_may_see() if data.name.is_just: if course.is_lti: raise APIException( 'You cannot rename LTI courses', ('LTI courses get their name from the LMS, so renaming is' ' not possible'), APICodes.INVALID_PARAM, 400) if not data.name.value: raise APIException( 'The name of a course should contain at least one character', 'A course name cannot be empty', APICodes.INVALID_PARAM, 400) checker.ensure_may_edit_info() course.name = data.name.value if data.state.is_just: if data.state.value.is_deleted: raise APIException( 'It is not yet possible to delete a course', 'Deleting courses in the API is not yet possible', APICodes.INVALID_PARAM, 400) checker.ensure_may_edit_state() course.state = data.state.value db.session.commit() return ExtendedJSONResponse.make(course, use_extended=models.Course)
def get_register_link( course_id: int, link_id: uuid.UUID ) -> ExtendedJSONResponse[models.CourseRegistrationLink]: """Get a registration link. .. :quickref: Course; Get the data in a registration link. :param course_id: The id of the course to which the registration link is connected. :param link_id: The id of the registration link. :returns: The specified registration link. .. note:: This route can be used without logging in, i.e. you don't have to be enrolled in the course to use this route. This route will not work for expired registration links. """ link = _get_non_expired_link(course_id, link_id) return ExtendedJSONResponse.make( link, use_extended=models.CourseRegistrationLink)
def add_course() -> ExtendedJSONResponse[models.Course]: """Add a new :class:`.models.Course`. .. :quickref: Course; Add a new course. :returns: A response containing the JSON serialization of the new course :raises PermissionException: If there is no logged in user. (NOT_LOGGED_IN) :raises PermissionException: If the user can not create courses. (INCORRECT_PERMISSION) :raises APIException: If the parameter "name" is not in the request. (MISSING_REQUIRED_PARAM) """ with helpers.get_from_request_transaction() as [get, _]: name = get('name', str) new_course = models.Course.create_and_add(name) db.session.flush() role = models.CourseRole.get_initial_course_role(new_course) current_user.courses[new_course.id] = role db.session.commit() return ExtendedJSONResponse.make(new_course, use_extended=models.Course)
def get_user_submissions( course_id: int, user_id: int ) -> ExtendedJSONResponse[t.Mapping[int, t.Sequence[models.Work]]]: """Get all :class:`.models.Work`s by the given :class:`.models.User` in the given :class:`.models.Course`. .. :quickref: Course; Get submissions by user in a course. :qparam boolean latest_only: Only get the latest submission of a user. Please use this option if at all possible, as students have a tendency to submit many attempts and that can make this route quite slow. :param int course_id: The id of the course :param int user_id: The id of the user :returns: A response containing the JSON serialized submissions. :raises NotFoundException: If the course does not exist. (OBJECT_ID_NOT_FOUND) :raises NotFoundException: If the user does not exist. (OBJECT_ID_NOT_FOUND) :raises APIException: If the given user is not member of the course. (INVALID_PARAM) :raises PermissionException: If there is no logged in user. (NOT_LOGGED_IN) :raises PermissionException: If the given user is not the logged in user and the logged in user does not have the permission to see others work. (INCORRECT_PERMISSION) """ course = helpers.get_or_404(models.Course, course_id) auth.ensure_permission(CPerm.can_see_assignments, course.id) assignments = course.get_all_visible_assignments() user = helpers.get_or_404(models.User, user_id) if any(not u.is_enrolled(course_id) for u in user.get_contained_users()): raise APIException( 'User is not enrolled in this course', f'User {user_id} not enrolled in course {course_id}', APICodes.INVALID_PARAM, 400) elif not user.contains_user(current_user): auth.ensure_permission(CPerm.can_see_others_work, course.id) latest_only = helpers.request_arg_true('latest_only') def get_subs(query: models.MyQuery[models.Work]) -> t.List[models.Work]: return models.Work.update_query_for_extended_jsonify( models.Work.limit_to_user_submissions(query, user), ).all() if latest_only: subs = {} for assignment in assignments: subs[assignment.id] = get_subs( assignment.get_all_latest_submissions(), ) else: query = models.Work.query.filter( models.Work.assignment_id.in_([a.id for a in assignments]), # Use _deleted because we already know the assignment exists. ~models.Work._deleted, # pylint: disable=protected-access ).order_by(models.Work.created_at.asc()) subs = {assig.id: [] for assig in assignments} for sub in get_subs(query): subs[sub.assignment_id].append(sub) return ExtendedJSONResponse.make( subs, use_extended=models.Work, )