2011-02-01 09:57:29 +08:00
#
2014-06-05 02:47:01 +08:00
# Copyright (C) 2011 - 2014 Instructure, Inc.
2011-02-01 09:57:29 +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/>.
#
2012-07-10 23:23:33 +08:00
# @API Sections
#
# API for accessing section information.
#
2014-02-12 07:24:37 +08:00
# @model Section
2012-07-10 23:23:33 +08:00
# {
2014-02-12 07:24:37 +08:00
# "id": "Section",
# "description": "",
# "properties": {
# "id": {
# "description": "The unique identifier for the section.",
# "example": 1,
# "type": "integer"
# },
# "name": {
# "description": "The name of the section.",
# "example": "Section A",
# "type": "string"
# },
# "sis_section_id": {
2014-02-11 08:13:53 +08:00
# "description": "The sis id of the section. This field is only included if the user has permission to view SIS information.",
# "example": "s34643",
2014-02-12 07:24:37 +08:00
# "type": "string"
# },
2014-01-15 14:48:27 +08:00
# "integration_id": {
2014-06-05 02:47:01 +08:00
# "description": "Optional: The integration ID of the section. This field is only included if the user has permission to view SIS information.",
2014-01-15 14:48:27 +08:00
# "example": "3452342345",
# "type": "string"
# },
2014-02-11 08:13:53 +08:00
# "sis_import_id": {
# "description": "The unique identifier for the SIS import if created through SIS. This field is only included if the user has permission to manage SIS information.",
# "example": 47,
# "type": "integer"
# },
2014-02-12 07:24:37 +08:00
# "course_id": {
2014-05-15 23:10:39 +08:00
# "description": "The unique Canvas identifier for the course in which the section belongs",
# "example": 7,
# "type": "integer"
# },
# "sis_course_id": {
2014-06-05 02:47:01 +08:00
# "description": "The unique SIS identifier for the course in which the section belongs. This field is only included if the user has permission to view SIS information.",
2014-02-12 07:24:37 +08:00
# "example": 7,
2014-11-06 04:44:15 +08:00
# "type": "string"
2014-02-12 07:24:37 +08:00
# },
# "start_at": {
# "description": "the start date for the section, if applicable",
# "example": "2012-06-01T00:00:00-06:00",
# "type": "datetime"
# },
# "end_at": {
# "description": "the end date for the section, if applicable",
# "type": "datetime"
# },
# "nonxlist_course_id": {
# "description": "The unique identifier of the original course of a cross-listed section",
# "type": "integer"
2014-12-30 03:44:17 +08:00
# },
# "total_students": {
# "description": "optional: the total number of active and invited students in the section",
# "example": 13,
# "type": "integer"
2014-02-12 07:24:37 +08:00
# }
# }
2012-07-10 23:23:33 +08:00
# }
2014-02-12 07:24:37 +08:00
#
2011-02-01 09:57:29 +08:00
class SectionsController < ApplicationController
before_filter :require_context
2012-11-10 06:32:42 +08:00
before_filter :require_section , :except = > [ :index , :create ]
2012-07-10 23:23:33 +08:00
include Api :: V1 :: Section
# @API List course sections
# Returns the list of sections for this course.
#
2014-12-17 10:36:27 +08:00
# @argument include[] [String, "students"|"avatar_url"|"enrollments"|"total_students"|"passback_status"]
2013-08-15 00:19:44 +08:00
# - "students": Associations to include with the group. Note: this is only
# available if you have permission to view users or grades in the course
# - "avatar_url": Include the avatar URLs for students returned.
2014-11-06 01:22:32 +08:00
# - "enrollments": If 'students' is also included, return the section
# enrollment for each student
2014-12-30 03:44:17 +08:00
# - "total_students": Returns the total amount of active and invited students
# for the course section
2014-12-17 10:36:27 +08:00
# - "passback_status": Include the grade passback status.
2012-07-10 23:23:33 +08:00
#
# @returns [Section]
def index
2013-06-27 23:50:18 +08:00
if authorized_action ( @context , @current_user , [ :read , :read_roster , :view_all_grades , :manage_grades ] )
if params [ :include ] . present? && ! is_authorized_action? ( @context , @current_user , [ :read_roster , :view_all_grades , :manage_grades ] )
params [ :include ] = nil
end
2012-07-10 23:23:33 +08:00
2013-06-27 23:50:18 +08:00
includes = Array ( params [ :include ] )
2012-07-10 23:23:33 +08:00
result = @context . active_course_sections . map { | section | section_json ( section , @current_user , session , includes ) }
render :json = > result
end
end
2012-11-10 06:32:42 +08:00
# @API Create course section
# Creates a new section for this course.
#
2013-08-15 00:19:44 +08:00
# @argument course_section[name] [String]
# The name of the section
#
2014-08-15 07:51:24 +08:00
# @argument course_section[sis_section_id] [String]
2013-08-15 00:19:44 +08:00
# The sis ID of the section
#
2014-08-15 07:51:24 +08:00
# @argument course_section[start_at] [DateTime]
2013-08-15 00:19:44 +08:00
# Section start date in ISO8601 format, e.g. 2011-01-01T01:00Z
#
2014-08-15 07:51:24 +08:00
# @argument course_section[end_at] [DateTime]
2013-08-15 00:19:44 +08:00
# Section end date in ISO8601 format. e.g. 2011-01-01T01:00Z
2012-11-10 06:32:42 +08:00
#
2014-12-27 00:15:03 +08:00
# @argument course_section[restrict_enrollments_to_section_dates] [Boolean]
# Set to true to restrict user enrollments to the start and end dates of the section.
#
2012-11-10 06:32:42 +08:00
# @returns Section
2011-02-01 09:57:29 +08:00
def create
2014-02-20 04:07:15 +08:00
if authorized_action ( @context . course_sections . scoped . new , @current_user , :create )
2012-11-10 06:32:42 +08:00
sis_section_id = params [ :course_section ] . try ( :delete , :sis_section_id )
2011-02-01 09:57:29 +08:00
@section = @context . course_sections . build ( params [ :course_section ] )
2012-11-10 06:32:42 +08:00
@section . sis_source_id = sis_section_id if api_request? && sis_section_id . present? && @context . root_account . grants_right? ( @current_user , session , :manage_sis )
2011-02-01 09:57:29 +08:00
respond_to do | format |
if @section . save
2013-06-28 22:44:31 +08:00
@context . touch
2011-06-22 02:38:28 +08:00
flash [ :notice ] = t ( 'section_created' , " Section successfully created! " )
2011-08-31 04:32:58 +08:00
format . html { redirect_to course_settings_url ( @context ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? section_json ( @section , @current_user , session , [ ] ) : @section ) }
2011-02-01 09:57:29 +08:00
else
2011-06-22 02:38:28 +08:00
flash [ :error ] = t ( 'section_creation_failed' , " Section creation failed " )
2011-08-31 04:32:58 +08:00
format . html { redirect_to course_settings_url ( @context ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > @section . errors , :status = > :bad_request }
2011-02-01 09:57:29 +08:00
end
end
end
end
2012-11-10 06:32:42 +08:00
def require_section
case @context
when Course
section_id = params [ :section_id ] || params [ :id ]
2014-02-12 07:58:09 +08:00
@section = api_find ( @context . active_course_sections , section_id )
2012-11-10 06:32:42 +08:00
when CourseSection
@section = @context
raise ActiveRecord :: RecordNotFound if @section . deleted? || @section . course . try ( :deleted? )
else
raise ActiveRecord :: RecordNotFound
end
end
2011-04-16 14:22:55 +08:00
def crosslist_check
course_id = params [ :new_course_id ]
# cross-listing should only be allowed within the same root account
2014-08-21 06:35:07 +08:00
@new_course = @section . root_account . all_courses . not_deleted . where ( id : course_id ) . first if course_id =~ Api :: ID_REGEX
@new_course || = @section . root_account . all_courses . not_deleted . where ( sis_source_id : course_id ) . first if course_id . present?
2011-04-16 14:22:55 +08:00
allowed = @new_course && @section . grants_right? ( @current_user , session , :update ) && @new_course . grants_right? ( @current_user , session , :manage_admin_users )
res = { :allowed = > ! ! allowed }
if allowed
@account = @new_course . account
2013-08-23 06:22:14 +08:00
res [ :section ] = @section . as_json ( include_root : false )
res [ :course ] = @new_course . as_json ( include_root : false )
res [ :account ] = @account . as_json ( include_root : false )
2011-04-16 14:22:55 +08:00
end
2013-08-23 06:22:14 +08:00
render :json = > res
2011-04-16 14:22:55 +08:00
end
2012-11-10 06:32:42 +08:00
# @API Cross-list a Section
# Move the Section to another course. The new course may be in a different account (department),
# but must belong to the same root account (institution).
#
# @returns Section
2011-04-16 14:22:55 +08:00
def crosslist
2014-02-12 07:58:09 +08:00
@new_course = api_find ( @section . root_account . all_courses . not_deleted , params [ :new_course_id ] )
2011-08-16 06:34:57 +08:00
if authorized_action ( @section , @current_user , :update ) && authorized_action ( @new_course , @current_user , :manage )
2011-04-16 14:22:55 +08:00
@section . crosslist_to_course @new_course
respond_to do | format |
2011-06-22 02:38:28 +08:00
flash [ :notice ] = t ( 'section_crosslisted' , " Section successfully cross-listed! " )
2011-04-16 14:22:55 +08:00
format . html { redirect_to named_context_url ( @new_course , :context_section_url , @section . id ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? section_json ( @section , @current_user , session , [ ] ) : @section ) }
2011-04-16 14:22:55 +08:00
end
end
end
2012-11-10 06:32:42 +08:00
# @API De-cross-list a Section
# Undo cross-listing of a Section, returning it to its original course.
#
# @returns Section
2011-04-16 14:22:55 +08:00
def uncrosslist
@new_course = @section . nonxlist_course
2012-11-10 06:32:42 +08:00
return render ( :json = > { :message = > " section is not cross-listed " } , :status = > :bad_request ) if @new_course . nil?
2011-08-16 06:34:57 +08:00
if authorized_action ( @section , @current_user , :update ) && authorized_action ( @new_course , @current_user , :manage )
2011-04-16 14:22:55 +08:00
@section . uncrosslist
respond_to do | format |
2011-06-22 02:38:28 +08:00
flash [ :notice ] = t ( 'section_decrosslisted' , " Section successfully de-cross-listed! " )
2011-04-16 14:22:55 +08:00
format . html { redirect_to named_context_url ( @new_course , :context_section_url , @section . id ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? section_json ( @section , @current_user , session , [ ] ) : @section ) }
2011-04-16 14:22:55 +08:00
end
end
end
2012-11-10 06:32:42 +08:00
# @API Edit a section
# Modify an existing section. See the documentation for {api:SectionsController#create create API action}.
#
# @returns Section
2011-02-01 09:57:29 +08:00
def update
2012-11-10 06:32:42 +08:00
params [ :course_section ] || = { }
2011-02-01 09:57:29 +08:00
if authorized_action ( @section , @current_user , :update )
2012-11-10 06:32:42 +08:00
params [ :course_section ] [ :sis_source_id ] = params [ :course_section ] . delete ( :sis_section_id ) if api_request?
2011-06-01 04:47:28 +08:00
if sis_id = params [ :course_section ] . delete ( :sis_source_id )
if sis_id != @section . sis_source_id && @section . root_account . grants_right? ( @current_user , session , :manage_sis )
if sis_id == ''
@section . sis_source_id = nil
else
@section . sis_source_id = sis_id
end
end
end
2011-02-01 09:57:29 +08:00
respond_to do | format |
if @section . update_attributes ( params [ :course_section ] )
2013-06-28 22:44:31 +08:00
@context . touch
2011-06-22 02:38:28 +08:00
flash [ :notice ] = t ( 'section_updated' , " Section successfully updated! " )
2011-02-01 09:57:29 +08:00
format . html { redirect_to course_section_url ( @context , @section ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? section_json ( @section , @current_user , session , [ ] ) : @section ) }
2011-02-01 09:57:29 +08:00
else
2011-06-22 02:38:28 +08:00
flash [ :error ] = t ( 'section_update_error' , " Section update failed " )
2011-02-01 09:57:29 +08:00
format . html { redirect_to course_section_url ( @context , @section ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > @section . errors , :status = > :bad_request }
2011-02-01 09:57:29 +08:00
end
end
end
end
2012-01-24 08:21:55 +08:00
2012-07-10 23:23:33 +08:00
# @API Get section information
# Gets details about a specific section
#
# @returns Section
2011-02-01 09:57:29 +08:00
def show
2012-09-20 00:49:03 +08:00
if authorized_action ( @section , @current_user , :read )
respond_to do | format |
format . html do
add_crumb ( @section . name , named_context_url ( @context , :context_section_url , @section ) )
2013-03-08 07:49:24 +08:00
@enrollments_count = @section . enrollments . not_fake . where ( :workflow_state = > 'active' ) . count
@completed_enrollments_count = @section . enrollments . not_fake . where ( :workflow_state = > 'completed' ) . count
@pending_enrollments_count = @section . enrollments . not_fake . where ( :workflow_state = > %w{ invited pending } ) . count
@student_enrollments_count = @section . enrollments . not_fake . where ( :type = > 'StudentEnrollment' ) . count
2012-09-20 00:49:03 +08:00
js_env (
:PERMISSIONS = > {
:manage_students = > @context . grants_right? ( @current_user , session , :manage_students ) || @context . grants_right? ( @current_user , session , :manage_admin_users ) ,
:manage_account_settings = > @context . account . grants_right? ( @current_user , session , :manage_account_settings )
} )
end
format . json { render :json = > section_json ( @section , @current_user , session , [ ] ) }
2012-07-10 23:23:33 +08:00
end
end
2011-02-01 09:57:29 +08:00
end
2012-01-24 08:21:55 +08:00
2012-11-10 06:32:42 +08:00
# @API Delete a section
# Delete an existing section. Returns the former Section.
#
# @returns Section
2011-02-01 09:57:29 +08:00
def destroy
if authorized_action ( @section , @current_user , :delete )
respond_to do | format |
2012-03-14 04:08:19 +08:00
if @section . enrollments . not_fake . empty?
2011-02-01 09:57:29 +08:00
@section . destroy
2013-06-28 22:44:31 +08:00
@context . touch
2011-06-22 02:38:28 +08:00
flash [ :notice ] = t ( 'section_deleted' , " Course section successfully deleted! " )
2011-08-31 04:32:58 +08:00
format . html { redirect_to course_settings_url ( @context ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? section_json ( @section , @current_user , session , [ ] ) : @section ) }
2011-02-01 09:57:29 +08:00
else
2011-06-22 02:38:28 +08:00
flash [ :error ] = t ( 'section_delete_not_allowed' , " You can't delete a section that has enrollments " )
2011-02-01 09:57:29 +08:00
format . html { redirect_to course_section_url ( @context , @section ) }
2013-08-23 06:22:14 +08:00
format . json { render :json = > ( api_request? ? { :message = > " You can't delete a section that has enrollments " } : @section ) , :status = > :bad_request }
2011-02-01 09:57:29 +08:00
end
end
end
end
end