2011-12-08 04:47:19 +08:00
#
2014-01-12 15:02:42 +08:00
# Copyright (C) 2011 - 2014 Instructure, Inc.
2011-12-08 04:47:19 +08:00
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @API Enrollments
2014-01-12 15:02:42 +08:00
#
2011-12-08 04:47:19 +08:00
# API for creating and viewing course enrollments
2014-01-12 15:02:42 +08:00
#
2014-02-12 07:29:57 +08:00
# @model Grade
2014-01-12 15:02:42 +08:00
# {
2014-02-12 07:29:57 +08:00
# "id": "Grade",
# "description": "",
# "properties": {
# "html_url": {
# "description": "The URL to the Canvas web UI page for the user's grades, if this is a student enrollment.",
# "example": "",
# "type": "string"
# },
# "current_grade": {
# "description": "The user's current grade in the class. Only included if user has permissions to view this grade.",
# "example": "",
# "type": "string"
# },
# "final_grade": {
# "description": "The user's final grade for the class. Only included if user has permissions to view this grade.",
# "example": "",
# "type": "string"
# },
# "current_score": {
# "description": "The user's current score in the class. Only included if user has permissions to view this score.",
# "example": "",
# "type": "string"
# },
# "final_score": {
# "description": "The user's final score for the class. Only included if user has permissions to view this score.",
# "example": "",
# "type": "string"
# }
2014-01-12 15:02:42 +08:00
# }
# }
#
2014-02-12 07:29:57 +08:00
# @model Enrollment
# {
# "id": "Enrollment",
# "description": "",
# "properties": {
# "id": {
# "description": "The ID of the enrollment.",
# "example": 1,
# "type": "integer"
# },
# "course_id": {
# "description": "The unique id of the course.",
# "example": 1,
# "type": "integer"
# },
2014-01-15 14:48:27 +08:00
# "sis_course_id": {
2014-06-05 02:47:01 +08:00
# "description": "The SIS Course ID in which the enrollment is associated. Only displayed if present. This field is only included if the user has permission to view SIS information.",
2014-01-15 14:48:27 +08:00
# "example": "SHEL93921",
# "type": "string"
# },
# "course_integration_id": {
2014-06-05 02:47:01 +08:00
# "description": "The Course Integration ID in which the enrollment is associated. This field is only included if the user has permission to view SIS information.",
2014-01-15 14:48:27 +08:00
# "example": "SHEL93921",
# "type": "string"
# },
2014-02-12 07:29:57 +08:00
# "course_section_id": {
# "description": "The unique id of the user's section.",
# "example": 1,
# "type": "integer"
# },
2014-01-15 14:48:27 +08:00
# "section_integration_id": {
2014-06-05 02:47:01 +08:00
# "description": "The Section Integration ID in which the enrollment is associated. This field is only included if the user has permission to view SIS information.",
2014-01-15 14:48:27 +08:00
# "example": "SHEL93921",
# "type": "string"
# },
# "sis_section_id": {
2014-06-05 02:47:01 +08:00
# "description": "The SIS Section ID in which the enrollment is associated. Only displayed if present. This field is only included if the user has permission to view SIS information.",
2014-01-15 14:48:27 +08:00
# "example": "SHEL93921",
# "type": "string"
# },
2014-02-12 07:29:57 +08:00
# "enrollment_state": {
# "description": "The state of the user's enrollment in the course.",
# "example": "active",
# "type": "string"
# },
# "limit_privileges_to_course_section": {
# "description": "User can only access his or her own course section.",
# "example": true,
# "type": "boolean"
# },
2014-02-11 07:56:39 +08:00
# "sis_import_id": {
# "description": "The unique identifier for the SIS import. This field is only included if the user has permission to manage SIS information.",
# "example": 83,
# "type": "integer"
# },
2014-02-12 07:29:57 +08:00
# "root_account_id": {
# "description": "The unique id of the user's account.",
# "example": 1,
# "type": "integer"
# },
# "type": {
2014-03-29 03:47:47 +08:00
# "description": "The enrollment type. One of 'StudentEnrollment', 'TeacherEnrollment', 'TaEnrollment', 'DesignerEnrollment', 'ObserverEnrollment'.",
2014-02-12 07:29:57 +08:00
# "example": "StudentEnrollment",
# "type": "string"
# },
# "user_id": {
# "description": "The unique id of the user.",
# "example": 1,
# "type": "integer"
# },
# "associated_user_id": {
2014-04-12 05:49:02 +08:00
# "description": "The unique id of the associated user. Will be null unless type is ObserverEnrollment.",
2014-02-12 07:29:57 +08:00
# "example": null,
# "type": "integer"
# },
# "role": {
2014-03-29 03:47:47 +08:00
# "description": "The enrollment role, for course-level permissions. This field will match `type` if the enrollment role has not been customized.",
# "example": "StudentEnrollment",
2014-02-12 07:29:57 +08:00
# "type": "string"
# },
# "updated_at": {
# "description": "The updated time of the enrollment, in ISO8601 format.",
# "example": "2012-04-18T23:08:51Z",
# "type": "datetime"
# },
2014-02-14 06:44:47 +08:00
# "start_at": {
# "description": "The start time of the enrollment, in ISO8601 format.",
# "example": "2012-04-18T23:08:51Z",
# "type": "datetime"
# },
# "end_at": {
# "description": "The end time of the enrollment, in ISO8601 format.",
# "example": "2012-04-18T23:08:51Z",
# "type": "datetime"
# },
2014-02-12 07:29:57 +08:00
# "last_activity_at": {
# "description": "The last activity time of the user for the enrollment, in ISO8601 format.",
# "example": "2012-04-18T23:08:51Z",
# "type": "datetime"
# },
2014-05-23 07:44:07 +08:00
# "total_activity_time": {
# "description": "The total activity time of the user for the enrollment, in seconds.",
# "example": 260,
# "type": "integer"
# },
2014-02-12 07:29:57 +08:00
# "html_url": {
# "description": "The URL to the Canvas web UI page for this course enrollment.",
# "example": "https://...",
# "type": "string"
# },
# "grades": {
# "description": "The URL to the Canvas web UI page the grades associated with this enrollment.",
# "$ref": "Grade"
# },
# "user": {
# "description": "A description of the user.",
# "type": "User"
# }
# }
# }
#
2011-12-08 04:47:19 +08:00
class EnrollmentsApiController < ApplicationController
2012-03-13 04:32:20 +08:00
before_filter :get_course_from_section , :require_context
2011-12-08 04:47:19 +08:00
@@errors = {
2012-05-23 03:55:23 +08:00
:missing_parameters = > 'No parameters given' ,
2011-12-08 04:47:19 +08:00
:missing_user_id = > " Can't create an enrollment without a user. Include enrollment[user_id] to create an enrollment " ,
2012-10-31 05:59:37 +08:00
:bad_type = > 'Invalid type' ,
2012-11-28 06:26:39 +08:00
:bad_role = > 'Invalid role' ,
:inactive_role = > 'Cannot create an enrollment with this role because it is inactive.' ,
:base_type_mismatch = > 'The specified type must match the base type for the role' ,
2012-10-31 05:59:37 +08:00
:concluded_course = > 'Can\'t add an enrollment to a concluded course.'
2011-12-08 04:47:19 +08:00
}
2012-03-27 06:25:50 +08:00
include Api :: V1 :: User
2012-05-04 00:14:19 +08:00
# @API List enrollments
2012-02-04 05:48:21 +08:00
# Depending on the URL given, return either (1) all of the enrollments in
2012-03-13 04:32:20 +08:00
# a course, (2) all of the enrollments in a section or (3) all of a user's
# enrollments. This includes student, teacher, TA, and observer enrollments.
2012-01-04 04:43:22 +08:00
#
2012-02-04 05:48:21 +08:00
# If a user has multiple enrollments in a context (e.g. as a teacher
# and a student or in multiple course sections), each enrollment will be
2012-01-24 05:38:31 +08:00
# listed separately.
2012-01-04 04:43:22 +08:00
#
2012-02-04 05:48:21 +08:00
# note: Currently, only an admin user can return other users' enrollments. A
# user can, however, return his/her own enrollments.
#
2013-08-14 07:02:38 +08:00
# @argument type[] [String]
# A list of enrollment types to return. Accepted values are
# 'StudentEnrollment', 'TeacherEnrollment', 'TaEnrollment',
# 'DesignerEnrollment', and 'ObserverEnrollment.' If omitted, all enrollment
# types are returned. This argument is ignored if `role` is given.
#
# @argument role[] [String]
# A list of enrollment roles to return. Accepted values include course-level
# roles created by the {api:RoleOverridesController#add_role Add Role API}
# as well as the base enrollment types accepted by the `type` argument above.
#
# @argument state[] [String, "active"|"invited"|"creation_pending"|"deleted"|"rejected"|"completed"|"inactive"]
# Filter by enrollment state. If omitted, 'active' and 'invited' enrollments
2014-05-17 06:36:00 +08:00
# are returned. When querying a user's enrollments (either via user_id
# argument or via user enrollments endpoint), the following additional
# synthetic states are supported: "current_and_invited"|"current_and_future"|"current_and_concluded"
#
# @argument user_id [String]
# Filter by user_id (only valid for course or section enrollment
# queries). If set to the current user's id, this is a way to
# determine if the user has any enrollments in the course or section,
# independent of whether the user has permission to view other people
# on the roster.
2012-01-24 05:38:31 +08:00
#
2014-01-12 15:02:42 +08:00
# @returns [Enrollment]
2012-01-04 04:43:22 +08:00
def index
2012-03-13 04:32:20 +08:00
endpoint_scope = ( @context . is_a? ( Course ) ? ( @section . present? ? " section " : " course " ) : " user " )
2012-05-23 03:55:23 +08:00
2012-02-04 05:48:21 +08:00
return unless enrollments = @context . is_a? ( Course ) ?
2013-10-03 04:12:50 +08:00
course_index_enrollments :
user_index_enrollments
2013-12-17 02:11:52 +08:00
enrollments = enrollments . joins ( :user ) . select ( " enrollments.* " ) .
2013-10-03 04:12:50 +08:00
order ( " enrollments.type, #{ User . sortable_name_order_by_clause ( " users " ) } " )
2014-01-29 04:47:12 +08:00
has_courses = enrollments . where_values . any? { | cond | cond . is_a? ( String ) && cond =~ / courses \ . / }
2013-12-17 02:11:52 +08:00
enrollments = enrollments . joins ( :course ) if has_courses
2012-05-23 03:55:23 +08:00
2012-01-04 04:43:22 +08:00
enrollments = Api . paginate (
2012-02-04 05:48:21 +08:00
enrollments ,
2012-10-18 05:43:39 +08:00
self , send ( " api_v1_ #{ endpoint_scope } _enrollments_url " ) )
2013-12-17 02:11:52 +08:00
Enrollment . send ( :preload_associations , enrollments , [ :user , :course , :course_section ] )
2012-02-04 14:59:20 +08:00
includes = [ :user ] + Array ( params [ :include ] )
2012-05-23 03:55:23 +08:00
2012-08-21 00:41:17 +08:00
user_json_preloads ( enrollments . map ( & :user ) )
2012-02-04 14:59:20 +08:00
render :json = > enrollments . map { | e | enrollment_json ( e , @current_user , session , includes ) }
2012-01-04 04:43:22 +08:00
end
2011-12-08 04:47:19 +08:00
2014-06-24 14:29:08 +08:00
# @API Enrollment by ID
# Get an Enrollment object by Enrollment ID
#
2014-08-06 23:10:20 +08:00
# @argument id [Required, Integer]
2014-06-24 14:29:08 +08:00
# The ID of the enrollment object
# @returns Enrollment
def show
enrollment = Enrollment . find ( params [ :id ] )
if enrollment . user_id == @current_user . id || enrollment . root_account == @context && authorized_action ( @context , @current_user , [ :read_roster ] )
#render enrollment object if requesting user is the current_user or user is authorized to read enrollment.
render :json = > enrollment_json ( enrollment , @current_user , session )
end
end
2012-05-04 00:14:19 +08:00
# @API Enroll a user
2012-03-13 04:32:20 +08:00
# Create a new user enrollment for a course or section.
2011-12-08 04:47:19 +08:00
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[user_id] [Required, String]
2013-08-14 07:02:38 +08:00
# The ID of the user to be enrolled in the course.
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[type] [Required, String, "StudentEnrollment"|"TeacherEnrollment"|"TaEnrollment"|"ObserverEnrollment"|"DesignerEnrollment"]
2013-08-14 07:02:38 +08:00
# Enroll the user as a student, teacher, TA, observer, or designer. If no
# value is given, the type will be inferred by enrollment[role] if supplied,
# otherwise 'StudentEnrollment' will be used.
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[role] [String]
2013-08-14 07:02:38 +08:00
# Assigns a custom course-level role to the user.
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[enrollment_state] [String, "active"|"invited"]
2013-08-14 07:02:38 +08:00
# If set to 'active,' student will be immediately enrolled in the course.
# Otherwise they will be required to accept a course invitation. Default is
# 'invited.'
2014-01-12 15:02:42 +08:00
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[course_section_id] [Integer]
2013-08-14 07:02:38 +08:00
# The ID of the course section to enroll the student in. If the
# section-specific URL is used, this argument is redundant and will be
# ignored.
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[limit_privileges_to_course_section] [Boolean]
2013-08-14 07:02:38 +08:00
# If a teacher or TA enrollment, teacher/TA will be restricted to the
# section given by course_section_id.
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[notify] [Boolean]
2013-10-29 00:13:59 +08:00
# If true, a notification will be sent to the enrolled user.
# Notifications are not sent by default.
2014-01-12 15:02:42 +08:00
#
2014-08-06 23:10:20 +08:00
# @argument enrollment[self_enrollment_code] [String]
2014-01-14 08:39:45 +08:00
# If the current user is not allowed to manage enrollments in this
# course, but the course allows self-enrollment, the user can self-
# enroll as a student in the default section by passing in a valid
# code. When self-enrolling, the user_id must be 'self'. The
# enrollment_state will be set to 'active' and all other arguments
# will be ignored.
#
2014-01-12 15:02:42 +08:00
# @example_request
# curl https://<canvas>/api/v1/courses/:course_id/enrollments \
# -X POST \
# -F 'user_id=1' \
# -F 'type=StudentEnrollment' \
# -F 'enrollment_state=active' \
# -F 'course_section_id=1' \
# -F 'limit_privileges_to_course_section=true' \
# -F 'notify=false'
#
# @example_request
# curl https://<canvas>/api/v1/courses/:course_id/enrollments \
# -X POST \
# -F 'user_id=2' \
# -F 'type=StudentEnrollment'
#
# @returns Enrollment
2011-12-08 04:47:19 +08:00
def create
# error handling
errors = [ ]
2012-11-28 06:26:39 +08:00
2011-12-08 04:47:19 +08:00
if params [ :enrollment ] . blank?
errors << @@errors [ :missing_parameters ] if params [ :enrollment ] . blank?
else
2014-01-14 08:39:45 +08:00
return create_self_enrollment if params [ :enrollment ] [ :self_enrollment_code ]
2012-11-28 06:26:39 +08:00
role_name = params [ :enrollment ] . delete ( :role )
type = params [ :enrollment ] . delete ( :type )
2012-12-21 07:30:03 +08:00
if Enrollment . valid_type? ( role_name )
type = role_name
role_name = nil
end
2012-11-28 06:26:39 +08:00
if role_name . present?
params [ :enrollment ] [ :role_name ] = role_name
course_role = @context . account . get_course_role ( role_name )
if course_role . nil?
errors << @@errors [ :bad_role ]
elsif course_role . workflow_state != 'active'
errors << @@errors [ :inactive_role ]
else
if type . blank?
type = course_role . base_role_type
elsif type != course_role . base_role_type
errors << @@errors [ :base_type_mismatch ]
end
end
end
if type . present?
2012-12-13 03:46:09 +08:00
errors << @@errors [ :bad_type ] unless Enrollment . valid_type? ( type )
2012-11-28 06:26:39 +08:00
else
type = 'StudentEnrollment'
end
2011-12-08 04:47:19 +08:00
errors << @@errors [ :missing_user_id ] unless params [ :enrollment ] [ :user_id ] . present?
end
2014-04-14 06:09:19 +08:00
errors << @@errors [ :concluded_course ] if @context . concluded?
2014-01-14 08:39:45 +08:00
return render_create_errors ( errors ) if errors . present?
2011-12-08 04:47:19 +08:00
2012-01-24 05:38:31 +08:00
# create enrollment
2012-11-28 06:26:39 +08:00
2013-10-29 00:13:59 +08:00
params [ :enrollment ] [ :no_notify ] = true unless value_to_boolean ( params [ :enrollment ] [ :notify ] )
2011-12-08 04:47:19 +08:00
unless @current_user . can_create_enrollment_for? ( @context , session , type )
2013-11-09 07:52:21 +08:00
render_unauthorized_action && return
2011-12-08 04:47:19 +08:00
end
2012-03-13 04:32:20 +08:00
params [ :enrollment ] [ :course_section_id ] = @section . id if @section . present?
2011-12-08 04:47:19 +08:00
if params [ :enrollment ] [ :course_section_id ] . present?
params [ :enrollment ] [ :section ] = @context . course_sections . active . find params [ :enrollment ] . delete ( :course_section_id )
end
2014-03-26 06:13:29 +08:00
api_user_id = params [ :enrollment ] . delete ( :user_id )
user = api_find ( User , api_user_id )
raise ( ActiveRecord :: RecordNotFound , " Couldn't find User with API id ' #{ api_user_id } ' " ) unless user . can_be_enrolled_in_course? ( @context )
2012-04-16 23:27:28 +08:00
@enrollment = @context . enroll_user ( user , type , params [ :enrollment ] . merge ( :allow_multiple_enrollments = > true ) )
2011-12-08 04:47:19 +08:00
@enrollment . valid? ?
2013-08-23 06:22:14 +08:00
render ( :json = > enrollment_json ( @enrollment , @current_user , session ) ) :
2014-01-14 08:39:45 +08:00
render ( :json = > @enrollment . errors , :status = > :bad_request )
end
def render_create_errors ( errors )
render json : { message : errors . join ( ', ' ) } , status : 403
end
def create_self_enrollment
require_user
options = params [ :enrollment ]
code = options [ :self_enrollment_code ]
# we don't just do a straight-up comparison of the code, since
# plugins can override Account#self_enrollment_course_for to allow
# for synthetic ones
errors = [ ]
if @context != @context . root_account . self_enrollment_course_for ( code )
errors << " enrollment[self_enrollment_code] is invalid "
end
if options [ :user_id ] != 'self'
errors << " enrollment[user_id] must be 'self' when self-enrolling "
end
return render_create_errors ( errors ) if errors . present?
@current_user . validation_root_account = @domain_root_account
@current_user . require_self_enrollment_code = true
@current_user . self_enrollment_code = code
if @current_user . save
render ( json : enrollment_json ( @current_user . self_enrollment , @current_user , session ) )
else
render ( json : { user : @current_user . errors } , status : :bad_request )
end
2011-12-08 04:47:19 +08:00
end
2012-02-04 05:48:21 +08:00
2012-05-04 00:14:19 +08:00
# @API Conclude an enrollment
2012-04-03 01:29:03 +08:00
# Delete or conclude an enrollment.
#
2013-08-14 07:02:38 +08:00
# @argument task [String, "conclude"|"delete"]
# The action to take on the enrollment.
2012-04-03 01:29:03 +08:00
#
# @example_request
# curl https://<canvas>/api/v1/courses/:course_id/enrollments/:enrollment_id \
# -X DELETE \
# -F 'task=conclude'
#
2014-01-12 15:02:42 +08:00
# @returns Enrollment
2012-04-03 01:29:03 +08:00
def destroy
2014-03-07 05:04:11 +08:00
@enrollment = @context . enrollments . find ( params [ :id ] )
2012-04-03 01:29:03 +08:00
task = %w{ conclude delete } . include? ( params [ :task ] ) ? params [ :task ] : 'conclude'
unless @enrollment . send ( " can_be_ #{ task } d_by " , @current_user , @context , session )
2013-11-09 07:52:21 +08:00
return render_unauthorized_action
2012-04-03 01:29:03 +08:00
end
task = 'destroy' if task == 'delete'
if @enrollment . send ( task )
render :json = > enrollment_json ( @enrollment , @current_user , session )
else
2013-08-23 06:22:14 +08:00
render :json = > @enrollment . errors , :status = > :bad_request
2012-04-03 01:29:03 +08:00
end
end
2012-02-04 05:48:21 +08:00
protected
2012-05-17 04:43:06 +08:00
# Internal: Collect course enrollments that @current_user has permissions to
# read.
#
# Returns an ActiveRecord scope of enrollments on success, false on failure.
2013-10-03 04:12:50 +08:00
def course_index_enrollments
2014-05-17 06:36:00 +08:00
if params [ :user_id ]
# if you pass in your own id, you can see if you are enrolled in the
# course, regardless of whether you have read_roster
scope = user_index_enrollments
return scope && scope . where ( course_id : @context . id )
end
2012-09-19 05:37:24 +08:00
if authorized_action ( @context , @current_user , [ :read_roster , :view_all_grades , :manage_grades ] )
2013-10-03 04:12:50 +08:00
scope = @context . enrollments_visible_to ( @current_user , :type = > :all , :include_priors = > true ) . where ( enrollment_index_conditions )
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
unless params [ :state ] . present?
2013-03-08 07:49:24 +08:00
scope = scope . where ( " enrollments.workflow_state NOT IN ('rejected', 'completed', 'deleted', 'inactive') " )
2012-06-20 01:42:43 +08:00
end
scope
2012-02-04 05:48:21 +08:00
else
false
end
end
2012-05-17 04:43:06 +08:00
# Internal: Collect user enrollments that @current_user has permissions to
# read.
#
# Returns an ActiveRecord scope of enrollments on success, false on failure.
2013-10-03 04:12:50 +08:00
def user_index_enrollments
2012-02-04 05:48:21 +08:00
user = api_find ( User , params [ :user_id ] )
2012-05-23 03:55:23 +08:00
if user == @current_user
2013-10-03 04:12:50 +08:00
# if user is requesting for themselves, just return all of their
# enrollments without any extra checking.
if params [ :state ] . present?
enrollments = user . enrollments . where ( enrollment_index_conditions ( true ) )
else
enrollments = user . current_and_invited_enrollments . where ( enrollment_index_conditions )
end
else
# otherwise check for read_roster rights on all of the requested
# user's accounts
approved_accounts = user . associated_root_accounts . inject ( [ ] ) do | accounts , ra |
accounts << ra . id if ra . grants_right? ( @current_user , session , :read_roster )
accounts
end
2012-02-04 05:48:21 +08:00
2013-10-03 04:12:50 +08:00
# if there aren't any ids in approved_accounts, then the user doesn't have
# permissions.
2013-11-09 07:52:21 +08:00
render_unauthorized_action and return false if approved_accounts . empty?
2012-05-17 04:43:06 +08:00
2013-10-03 04:12:50 +08:00
enrollments = user . enrollments . where ( enrollment_index_conditions ) .
where ( root_account_id : approved_accounts )
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
2013-10-03 04:12:50 +08:00
# by default, return active and invited courses. don't use the existing
# current_and_invited_enrollments scope because it won't return enrollments
# on unpublished courses.
enrollments = enrollments . where ( workflow_state : %w{ active invited } ) unless params [ :state ] . present?
end
2012-05-23 03:55:23 +08:00
2013-10-03 04:12:50 +08:00
enrollments
2012-05-23 03:55:23 +08:00
end
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
# Internal: Collect type, section, state, and role info from params and format them
2012-05-23 03:55:23 +08:00
# for use in a request for the requester's own enrollments.
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
# index is :course or :user
2012-05-23 03:55:23 +08:00
#
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
# Returns [ sql fragment string, replacement hash ]
def enrollment_index_conditions ( use_course_state = false )
type , state , role = params . values_at ( :type , :state , :role )
clauses = [ ]
replacements = { }
2012-05-23 03:55:23 +08:00
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
if role . present?
clauses << 'COALESCE (enrollments.role_name, enrollments.type) IN (:role)'
replacements [ :role ] = Array ( role )
elsif type . present?
clauses << 'enrollments.type IN (:type)'
replacements [ :type ] = Array ( type )
2012-05-23 03:55:23 +08:00
end
if state . present?
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
if use_course_state
2014-05-17 06:36:00 +08:00
conditions = state . map { | s | Enrollment :: QueryBuilder . new ( s . to_sym ) . conditions } . compact
clauses << " ( #{ conditions . join ( ' OR ' ) } ) "
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
else
clauses << 'enrollments.workflow_state IN (:workflow_state)'
replacements [ :workflow_state ] = Array ( state )
2012-05-23 03:55:23 +08:00
end
end
if @section . present?
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
clauses << 'enrollments.course_section_id = :course_section_id'
replacements [ :course_section_id ] = @section . id
2012-05-23 03:55:23 +08:00
end
2012-02-04 05:48:21 +08:00
make other APIs deal with course roles
fixes #11938
test plan:
- generate the documentation
- for CoursesController#index "List your courses"
- enroll a user in two different courses, using a base
enrollment type in one course (e.g., TA) and a
derived custom enrollment type in the other
(e.g., AwesomeTA; use the Add Role API to generate it).
- publish the courses, accept the enrollments, etc.
- as the created user,
- GET /api/v1/courses and make sure both courses show.
Also make sure (here and below) that the custom role
shows up in the results, i.e.
'enrollments' => [{'type' => 'ta', 'role' => 'AwesomeTA'}]
- GET /api/v1/courses?enrollment_type=ta and make sure
both courses show.
- GET /api/v1/courses?enrollment_role=TaEnrollment
and make sure only one course is returned.
- GET /api/v1/courses?enrollment_role=AwesomeTA
and make sure the other course is returned.
- for CoursesController#users "List users"
- enroll multiple users in the same course with
a base and a derived enrollment type
(kind of the opposite of the previous)
- As an admin,
- GET /api/v1/courses/:course_id/users and make sure
both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_type=ta
and make sure both users are returned.
- GET /api/v1/courses/:course_id/users?enrollment_role=TaEnrollment
and make sure only the plain TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role=AwesomeTA
and make sure only the awesome TA is returned
- GET /api/v1/courses/:course_id/users?enrollment_role[]=TaEnrollment&enrollment_role[]=AwesomeTA
and make sure both users are returned.
- for EnrollmentsApiController#index "List enrollments",
exercise the 'role' parameter, using all three contexts
(course, section, and user), testing cases like those
outlined above
- also make sure enrollment['role'] shows the custom role
type in the returned JSON
Change-Id: Icefe662538c2fc6df19f7a6fe82e8009a3bd25e3
Reviewed-on: https://gerrit.instructure.com/15598
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
2012-11-27 06:43:57 +08:00
[ clauses . join ( ' AND ' ) , replacements ]
2012-02-04 05:48:21 +08:00
end
2011-12-08 04:47:19 +08:00
end