canvas-lms/app/controllers/favorites_controller.rb

281 lines
9.3 KiB
Ruby

#
# Copyright (C) 2011 - present 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/>.
# @API Favorites
#
# @model Favorite
# {
# "id": "Favorite",
# "description": "",
# "required": [""],
# "properties": {
# "context_id": {
# "description": "The ID of the object the Favorite refers to",
# "example": 1170,
# "type": "integer"
# },
# "context_type": {
# "description": "The type of the object the Favorite refers to (currently, only 'Course' is supported)",
# "example": "Course",
# "type": "string",
# "allowableValues": {
# "values": [
# "Course"
# ]
# }
# }
# }
# }
#
class FavoritesController < ApplicationController
before_action :require_user
before_action :check_defaults, :only => [:remove_favorite_course]
after_action :touch_user, :only => [:add_favorite_course, :remove_favorite_course, :reset_course_favorites]
include Api::V1::Favorite
include Api::V1::Course
include Api::V1::Group
# @API List favorite courses
# Retrieve the paginated list of favorite courses for the current user. If the user has not chosen
# any favorites, then a selection of currently enrolled courses will be returned.
#
# @argument exclude_blueprint_courses [Boolean]
# When set, only return courses that are not configured as blueprint courses.
#
# See the {api:CoursesController#index List courses API} for details on accepted include[] parameters.
#
# @returns [Course]
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/courses \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def list_favorite_courses
includes = Set.new(Array(params[:include]))
courses = @current_user.menu_courses
if courses.any? && value_to_boolean(params[:exclude_blueprint_courses])
mc_ids = MasterCourses::MasterTemplate.active.where(:course_id => courses).pluck(:course_id)
courses.reject!{|c| mc_ids.include?(c.id)}
end
render :json => courses.map { |course|
enrollments = nil
unless Array(params[:exclude]).include?('enrollments')
enrollments = course.current_enrollments.where(:user_id => @current_user).to_a
if includes.include?('observed_users') &&
enrollments.any?(&:assigned_observer?)
enrollments.concat(ObserverEnrollment.observed_enrollments_for_courses(course, @current_user))
end
end
course_json(course, @current_user, session, includes, enrollments)
}
end
# @API List favorite groups
# Retrieve the paginated list of favorite groups for the current user. If the user has not chosen
# any favorites, then a selection of groups that the user is a member of will be returned.
#
#
#
# @returns [Group]
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/groups \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def list_favorite_groups
fave_group_memberships = nil
@current_user.shard.activate do
fave_group_memberships = @current_user.groups.active.shard(@current_user).where(id: @current_user.favorite_context_ids("Group"))
end
if fave_group_memberships.any?
render :json => fave_group_memberships.map{ |g| group_json(g, @current_user,session)}
else
render :json => @current_user.groups.active.shard(@current_user).map{ |g| group_json(g, @current_user,session)}
end
end
# @API Add course to favorites
# Add a course to the current user's favorites. If the course is already
# in the user's favorites, nothing happens.
#
# @argument id [Required, String]
# The ID or SIS ID of the course to add. The current user must be
# registered in the course.
#
# @returns Favorite
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/courses/1170 \
# -X POST \
# -H 'Authorization: Bearer <ACCESS_TOKEN>' \
# -H 'Content-Length: 0'
#
def add_favorite_course
course = api_find(Course, params[:id])
fave = nil
@current_user.shard.activate do
Favorite.unique_constraint_retry do
fave = @current_user.favorites.where(:context_type => 'Course', :context_id => course).first
fave ||= @current_user.favorites.create!(:context => course)
end
end
render :json => favorite_json(fave, @current_user, session)
end
# @API Add group to favorites
# Add a group to the current user's favorites. If the group is already
# in the user's favorites, nothing happens.
#
# @argument id [Required, String]
# The ID or SIS ID of the group to add. The current user must be
# a member of the group.
#
# @returns Favorite
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/group/1170 \
# -X POST \
# -H 'Authorization: Bearer <ACCESS_TOKEN>' \
# -H 'Content-Length: 0'
#
def add_favorite_groups
group = api_find(Group, params[:id])
fave = nil
@current_user.shard.activate do
Favorite.unique_constraint_retry do
fave = @current_user.favorites.where(:context_type => 'Group', :context_id => group).first
fave ||= @current_user.favorites.create!(:context => group)
end
end
render :json => favorite_json(fave, @current_user, session)
end
# @API Remove course from favorites
# Remove a course from the current user's favorites.
#
# @argument id [Required, String]
# the ID or SIS ID of the course to remove
#
# @returns Favorite
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/courses/1170 \
# -X DELETE \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def remove_favorite_course
# allow removing a Favorite whose context object no longer exists
# but also allow referencing by sis id, if possible
courses = api_find_all(Course, [params[:id]])
course_id = Shard.relative_id_for(courses.any? ? courses.first.id : params[:id], Shard.current, @current_user.shard)
fave = @current_user.favorites.where(:context_type => 'Course', :context_id => course_id).first
if fave
result = favorite_json(fave, @current_user, session)
fave.destroy
render :json => result
else
# can't really return a 404 here without making browsers freak out
# in the Courses UI (it's easy for the client's state to get out of
# sync with the server's, especially with multiple browsers open)
render :json => {}
end
end
# @API Remove group from favorites
# Remove a group from the current user's favorites.
#
# @argument id [Required, String]
# the ID or SIS ID of the group to remove
#
# @returns Favorite
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/groups/1170 \
# -X DELETE \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def remove_favorite_groups
group = api_find_all(Group, [params[:id]])
group_id= Shard.relative_id_for(group.any? ? group.first.id : params[:id], Shard.current, @current_user.shard)
fave = @current_user.favorites.where(:context_type => 'Group', :context_id => group_id).first
if fave
result = favorite_json(fave, @current_user, session)
fave.destroy
render :json => result
else
# can't really return a 404 here without making browsers freak out
# in the Group UI (it's easy for the client's state to get out of
# sync with the server's, especially with multiple browsers open)
render :json => {}
end
end
# @API Reset course favorites
# Reset the current user's course favorites to the default
# automatically generated list of enrolled courses
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/courses \
# -X DELETE \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def reset_course_favorites
@current_user.favorites.by('Course').destroy_all
render :json => { :status => 'ok' }
end
# @API Reset group favorites
# Reset the current user's group favorites to the default
# automatically generated list of enrolled group
#
# @example_request
# curl https://<canvas>/api/v1/users/self/favorites/group \
# -X DELETE \
# -H 'Authorization: Bearer <ACCESS_TOKEN>'
#
def reset_groups_favorites
@current_user.favorites.by('Group').destroy_all
render :json => { :status => 'ok' }
end
protected
# When we have other favorites, this needs to be modified to handle the other
# types, rather than just courses.
def check_defaults
return unless @current_user.favorites.count == 0
@current_user.menu_courses.each do |course|
@current_user.favorites.create :context => course
end
end
def touch_user
# Menu is cached, clear it
@current_user.touch
end
end