2011-02-01 09:57:29 +08:00
|
|
|
#
|
|
|
|
# Copyright (C) 2011 Instructure, Inc.
|
|
|
|
#
|
|
|
|
# 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": {
|
|
|
|
# "description": "The sis id of the section. Ignored if the calling user does not have permission to manage SIS.",
|
|
|
|
# "type": "string"
|
|
|
|
# },
|
|
|
|
# "course_id": {
|
|
|
|
# "description": "The unique identifier for the course the section belongs to",
|
|
|
|
# "example": 7,
|
|
|
|
# "type": "integer"
|
|
|
|
# },
|
|
|
|
# "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"
|
|
|
|
# }
|
|
|
|
# }
|
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.
|
|
|
|
#
|
2013-08-15 00:19:44 +08:00
|
|
|
# @argument include[] [Optional, String, "students"|"avatar_url"]
|
|
|
|
# - "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.
|
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
|
|
|
|
#
|
|
|
|
# @argument course_section[sis_section_id] [Optional, String]
|
|
|
|
# The sis ID of the section
|
|
|
|
#
|
|
|
|
# @argument course_section[start_at] [Optional, DateTime]
|
|
|
|
# Section start date in ISO8601 format, e.g. 2011-01-01T01:00Z
|
|
|
|
#
|
|
|
|
# @argument course_section[end_at] [Optional, DateTime]
|
|
|
|
# Section end date in ISO8601 format. e.g. 2011-01-01T01:00Z
|
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-01-24 02:19:52 +08:00
|
|
|
@new_course = @section.root_account.all_courses.not_deleted.find_by_id(course_id) if course_id =~ Api::ID_REGEX
|
2012-11-10 06:32:42 +08:00
|
|
|
@new_course ||= @section.root_account.all_courses.not_deleted.find_by_sis_source_id(course_id) 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
|