add api for listing visible navigation tabs

test plan:
- fetch tab list using some command like:
curl -H 'Authorization: Bearer <token>' \
 https://<canvas>/api/v1/courses/<course_id>/tabs\?include\="external"
- ensure that the returned list corresponds to the left-hand tab list on the
  web interface

fixes #10891

Change-Id: If3371472b58f849a9736ab6747f69551178e99a4
Reviewed-on: https://gerrit.instructure.com/14615
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Zach Pendleton <zachp@instructure.com>
This commit is contained in:
Joel Hough 2012-10-22 15:22:15 -06:00
parent 181d300e2d
commit 7b93ba46f0
6 changed files with 203 additions and 1 deletions

View File

@ -1328,4 +1328,53 @@ class CoursesController < ApplicationController
:nothing
end
end
include Api::V1::Tab
# @API List available tabs
# Returns a list of navigation tabs available in the current context.
#
# @argument include[] ["external"] Optionally include external tool tabs in the returned list of tabs
#
# @example_request
# curl -H 'Authorization: Bearer <token>' \
# https://<canvas>/api/v1/courses/<course_id>/tabs\?include\="external"
#
# @example_response
# [
# {
# "html_url": "/courses/1",
# "id": "home",
# "label": "Home",
# "type": "internal"
# },
# {
# "html_url": "/courses/1/external_tools/4",
# "id": "context_external_tool_4",
# "label": "WordPress",
# "type": "external"
# },
# {
# "html_url": "/courses/1/grades",
# "id": "grades",
# "label": "Grades",
# "type": "internal"
# }
# ]
def tabs
get_context
includes = Array(params[:include])
tabs = @context.tabs_available(@current_user, :include_external => includes.include?('external'))
tabs = tabs.select do |tab|
if (tab[:id] == @context.class::TAB_CHAT rescue false)
tab[:href] && tab[:label] && feature_enabled?(:tinychat)
elsif (tab[:id] == @context.class::TAB_COLLABORATIONS rescue false)
tab[:href] && tab[:label] && Collaboration.any_collaborations_configured?
elsif (tab[:id] == @context.class::TAB_CONFERENCES rescue false)
tab[:href] && tab[:label] && feature_enabled?(:web_conferences)
else
tab[:href] && tab[:label]
end
end
render :json => tabs_available_json(tabs, @current_user, session)
end
end

View File

@ -2556,12 +2556,13 @@ class Course < ActiveRecord::Base
def tabs_available(user=nil, opts={})
# make sure t() is called before we switch to the slave, in case we update the user's selected locale in the process
default_tabs = Course.default_tabs
opts.reverse_merge!(:include_external => true)
ActiveRecord::Base::ConnectionSpecification.with_environment(:slave) do
# We will by default show everything in default_tabs, unless the teacher has configured otherwise.
tabs = self.tab_configuration.compact
settings_tab = default_tabs[-1]
external_tabs = external_tool_tabs(opts)
external_tabs = (opts[:include_external] && external_tool_tabs(opts)) || []
tabs = tabs.map do |tab|
default_tab = default_tabs.find {|t| t[:id] == tab[:id] } || external_tabs.find{|t| t[:id] == tab[:id] }
if default_tab

View File

@ -661,6 +661,7 @@ ActionController::Routing::Routes.draw do |map|
courses.post 'courses/:course_id/files', :action => :create_file
courses.post 'courses/:course_id/folders', :controller => :folders, :action => :create
courses.get 'courses/:course_id/folders/:id', :controller => :folders, :action => :show, :path_name => 'course_folder'
courses.get 'courses/:course_id/tabs', :action => :tabs, :path_name => "course_tabs"
end
api.with_options(:controller => :sections) do |sections|

42
lib/api/v1/tab.rb Normal file
View File

@ -0,0 +1,42 @@
#
# Copyright (C) 2012 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/>.
#
module Api::V1::Tab
include Api::V1::Json
def tabs_available_json(tabs, user, session)
tabs.map do |tab|
tab_json(tab, user, session)
end
end
def tab_json(tab, user, session)
hash = {}
if tab[:args]
hash[:html_url] = send(tab[:href], *tab[:args])
elsif tab[:no_args]
hash[:html_url] = send(tab[:href])
else
hash[:html_url] = send(tab[:href], @context)
end
hash[:label] = tab[:label]
hash[:id] = tab[:css_class]
hash[:type] = (tab[:external] && 'external') || 'internal'
api_json(hash, user, session)
end
end

View File

@ -951,6 +951,95 @@ describe CoursesController, :type => :integration do
json.map{ |el| el['id'] }.should == [@student2.id, @student3.id, @student1.id]
end
end
describe '/tabs' do
it 'should list navigation tabs' do
@user = @course1.teachers.first
json = api_call(:get, "/api/v1/courses/#{@course1.id}/tabs",
{ :controller => 'courses', :action => 'tabs', :course_id => @course1.to_param, :format => 'json'},
{ :include => ['external']})
json.should == [
{
"id" => "home",
"html_url" => "/courses/#{@course1.id}",
"type" => "internal",
"label" => "Home"
},
{
"id" => "announcements",
"label" => "Announcements",
"html_url" => "/courses/#{@course1.id}/announcements",
"type" => "internal"
},
{
"id" => "assignments",
"html_url" => "/courses/#{@course1.id}/assignments",
"label" => "Assignments",
"type" => "internal"
},
{
"id" => "discussions",
"html_url" => "/courses/#{@course1.id}/discussion_topics",
"label" => "Discussions",
"type" => "internal"
},
{
"id" => "grades",
"html_url" => "/courses/#{@course1.id}/grades",
"label" => "Grades",
"type" => "internal"
},
{
"id" => "people",
"html_url" => "/courses/#{@course1.id}/users",
"label" => "People",
"type" => "internal"
},
{
"id" => "pages",
"html_url" => "/courses/#{@course1.id}/wiki",
"label" => "Pages",
"type" => "internal"
},
{
"id" => "files",
"html_url" => "/courses/#{@course1.id}/files",
"label" => "Files",
"type" => "internal"
},
{
"id" => "syllabus",
"html_url" => "/courses/#{@course1.id}/assignments/syllabus",
"label" => "Syllabus",
"type" => "internal"
},
{
"id" => "outcomes",
"html_url" => "/courses/#{@course1.id}/outcomes",
"label" => "Outcomes",
"type" => "internal"
},
{
"id" => "quizzes",
"html_url" => "/courses/#{@course1.id}/quizzes",
"label" => "Quizzes",
"type" => "internal"
},
{
"id" => "modules",
"html_url" => "/courses/#{@course1.id}/modules",
"label" => "Modules",
"type" => "internal"
},
{
"id" => "settings",
"html_url" => "/courses/#{@course1.id}/settings",
"label" => "Settings",
"type" => "internal"
}
]
end
end
end
def each_copy_option

View File

@ -922,6 +922,26 @@ describe Course, "tabs_available" do
tabs.should be_include(t1.asset_string)
tabs.should_not be_include(t2.asset_string)
end
it "should not include tabs for external tools if opt[:include_external] is false" do
course_with_student(:active_all => true)
t1 = @course.context_external_tools.create!(
:url => "http://example.com/ims/lti",
:consumer_key => "asdf",
:shared_secret => "hjkl",
:name => "external tool 1",
:course_navigation => {
:text => "blah",
:url => "http://example.com/ims/lti",
:default => false,
}
)
tabs = @course.tabs_available(nil, :include_external => false).map { |tab| tab[:id] }
tabs.should_not be_include(t1.asset_string)
end
end
describe Course, "backup" do