Skip to content
This repository has been archived by the owner on May 2, 2020. It is now read-only.

Commit

Permalink
Add endpoint to list all external tool collaborations
Browse files Browse the repository at this point in the history
Fixes PLAT-1556

Test Plan:
 - Create a collaboration in the context of a course.
   The collaboration_type should be 'external_tool_collaboration'
   This should be done via rails console or something similar as
   creation of these new types of collaborations is not complete
 - Hit /api/v1/courses/<course_id>/collaborations and notice that your
   newly created collaboration will show up and should include a field
   called user_name that has the creating users name
 - Try accessing the endpoint as a non member of the collaboration
 - you should not see the collaboration
 - Create another collaboration in the context of a group
 - As a member of the group hit /api/v1/groups/<group_id>/collaborations
   and notice the newly create collaboration will show up and should
   include a field called user_name that has the creating users name
Change-Id: I06045fa4bfa25722c3c790d4b7ff493098ec2670
Reviewed-on: https://gerrit.instructure.com/80235
Reviewed-by: Steven Burnett <[email protected]>
Tested-by: Jenkins
QA-Review: Deepeeca Soundarrajan <[email protected]>
Product-Review: Matthew Sessions <[email protected]>
  • Loading branch information
Matthew Sessions committed Jun 6, 2016
1 parent 48a8970 commit 5b8173a
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 8 deletions.
34 changes: 34 additions & 0 deletions app/controllers/collaborations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class CollaborationsController < ApplicationController
before_filter { |c| c.active_tab = "collaborations" }

include Api::V1::Collaborator
include Api::V1::Collaboration

def index
return unless authorized_action(@context, @current_user, :read) &&
Expand All @@ -80,6 +81,39 @@ def index
:collaboration_types => Collaboration.collaboration_types
end

# @API List collaborations
# List collaborations the current user has access to in the context of the course
# provided in the url
#
# curl https://<canvas>/api/v1/courses/1/collaborations/
#
# @returns [Collaboration]
def api_index
return unless authorized_action(@context, @current_user, :read) &&
(tab_enabled?(@context.class::TAB_COLLABORATIONS) || tab_enabled?(@context.class::TAB_COLLABORATIONS_NEW))

url = @context.instance_of?(Course) ? api_v1_course_collaborations_index_url : api_v1_group_collaborations_index_url

collaborations_query = @context.collaborations.active.
eager_load(:user).
where(collaboration_type: 'external_tool_collaboration')

unless @context.grants_right?(@current_user, session, :manage_content)
collaborations_query = collaborations_query.
eager_load(:collaborators).
where(Collaboration.arel_table[:user_id].eq(@current_user.id).
or(Collaborator.arel_table[:user_id].eq(@current_user.id)))
end

collaborations = Api.paginate(
collaborations_query,
self,
url
)

render :json => collaborations.map { |c| collaboration_json(c, @current_user, session) }
end

def show
@collaboration = @context.collaborations.find(params[:id])
if authorized_action(@collaboration, @current_user, :read)
Expand Down
2 changes: 1 addition & 1 deletion app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def inherited_assessment_question_banks(include_self = false)
belongs_to :default_grading_standard, :class_name => 'GradingStandard', :foreign_key => 'grading_standard_id'
has_many :grading_standards, -> { where("workflow_state<>'deleted'") }, as: :context
has_many :web_conferences, -> { order('created_at DESC') }, as: :context, dependent: :destroy
has_many :collaborations, -> { order('title, created_at') }, as: :context, dependent: :destroy
has_many :collaborations, -> { order("#{Collaboration.quoted_table_name}.title, #{Collaboration.quoted_table_name}.created_at") }, as: :context, dependent: :destroy
has_many :context_modules, -> { order(:position) }, as: :context, dependent: :destroy
has_many :context_module_progressions, through: :context_modules
has_many :active_context_modules, -> { where(workflow_state: 'active') }, as: :context, class_name: 'ContextModule'
Expand Down
2 changes: 1 addition & 1 deletion app/models/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Group < ActiveRecord::Base
belongs_to :wiki
has_many :wiki_pages, foreign_key: 'wiki_page', primary_key: 'wiki_page'
has_many :web_conferences, :as => :context, :dependent => :destroy
has_many :collaborations, -> { order('title, created_at') }, as: :context, dependent: :destroy
has_many :collaborations, -> { order("#{Collaboration.quoted_table_name}.title, #{Collaboration.quoted_table_name}.created_at") }, as: :context, dependent: :destroy
has_many :media_objects, :as => :context
has_many :content_migrations, :as => :context
has_many :content_exports, :as => :context
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,7 @@
put 'courses/:course_id/settings', action: :update_settings
get 'courses/:course_id/recent_students', action: :recent_students, as: 'course_recent_students'
get 'courses/:course_id/users', action: :users, as: 'course_users'
get 'courses/:course_id/collaborations', controller: :collaborations, action: :api_index, as: 'course_collaborations_index'
# this api endpoint has been removed, it was redundant with just courses#users
# we keep it around for backward compatibility though
get 'courses/:course_id/search_users', action: :users
Expand Down Expand Up @@ -1369,6 +1370,7 @@
get 'groups/:group_id/activity_stream/summary', action: :activity_stream_summary, as: 'group_activity_stream_summary'
put "groups/:group_id/followers/self", action: :follow
delete "groups/:group_id/followers/self", action: :unfollow
get 'groups/:group_id/collaborations', controller: :collaborations, action: :api_index, as: 'group_collaborations_index'

scope(controller: :group_memberships) do
resources :memberships, path: "groups/:group_id/memberships", name_prefix: "group_", controller: :group_memberships
Expand Down
28 changes: 28 additions & 0 deletions lib/api/v1/collaboration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# Copyright (C) 2016 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::Collaboration
include Api::V1::Json

def collaboration_json(collaboration, current_user, session)
attribute_whitelist = %w{id collaboration_type document_id user_id context_id context_type url created_at updated_at description title}
api_json(collaboration, current_user, session, :only => attribute_whitelist).tap do |hash|
hash['user_name'] = collaboration.user[:name]
end
end
end
1 change: 0 additions & 1 deletion lib/api/v1/collaborator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ def collaborator_json(collaborator, current_user, session)
end
end
end

58 changes: 58 additions & 0 deletions spec/apis/v1/collaboration_json_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#
# Copyright (C) 2016 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/>.
#

require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')

include Api::V1::Collaboration

describe Api::V1::Collaboration do
before(:once) do
@current_user = user_with_pseudonym(:active_all => true)
@collaboration = Collaboration.new(:title => 'Test collaboration',
:description => 'Let us collaborate',
:collaboration_type => 'external_tool_collaboration',
:url => 'https://google.com',
:user => @current_user)
@collaboration.save!
end

it 'should properly serialize' do
json = collaboration_json(@collaboration, @current_user, nil)

expect(json['id']).to eq @collaboration.id
expect(json['collaboration_type']).to eq @collaboration.collaboration_type
expect(json['document_id']).to eq @collaboration.document_id
expect(json['user_id']).to eq @collaboration.user_id
expect(json['context_id']).to eq @collaboration.context_id
expect(json['context_type']).to eq @collaboration.context_type
expect(json['url']).to eq @collaboration.url
expect(json['created_at']).to eq @collaboration.created_at
expect(json['updated_at']).to eq @collaboration.updated_at
expect(json['title']).to eq @collaboration.title
expect(json['description']).to eq @collaboration.description

expect(json['data']).to eq nil
expect(json['deleted_at']).to eq nil
end

it 'should includes the owning users name' do
json = collaboration_json(@collaboration, @current_user, nil)

expect(json['user_name']).to eq @current_user.name
end
end
103 changes: 98 additions & 5 deletions spec/apis/v1/collaborations_api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,110 @@
before :once do
PluginSetting.new(:name => 'etherpad', :settings => {}).save!
course_with_teacher(:active_all => true)
@members = (1..5).map do
end

context '/api/v1/course/:course_id/collaborations' do
before :once do
group_model(:context => @course)
@student = user_with_pseudonym(:active_all => true)
@course.enroll_student(@student).accept!
@course_collaboration = collaboration_model(
:user => @student,
:context => @course,
:collaboration_type => "external_tool_collaboration"
)
@group_collaboration = collaboration_model(
:user => @student,
:context => @group,
:collaboration_type => "external_tool_collaboration"
)
@user = @student
end

let(:url) { "/api/v1/courses/#{@course.id}/collaborations"}
let(:url_options) do
{
:controller => 'collaborations',
:action => 'api_index',
:course_id => @course.id,
:format => 'json'
}
end

let(:group_url) { "/api/v1/groups/#{@group.id}/collaborations"}
let(:group_url_options) do
{
:controller => 'collaborations',
:action => 'api_index',
:group_id => @group.id,
:format => 'json'
}
end

it 'should require authorization' do
user
raw_api_call(:get, url, url_options)
expect(response.code).to eq '401'
end

it 'is unauthorized when trying to access a courses collaboration when they are not a member of the course' do
user = user_with_pseudonym(:active_all => true)
raw_api_call(:get, url, url_options)
expect(response.code).to eq '401'
end

it 'is unauthorized when trying to access a groups collaborations they are not a member of' do
raw_api_call(:get, group_url, group_url_options)
expect(response.code).to eq '401'
end

it 'doesnt return course collaborations for which the user is not a collaborator on' do
user = user_with_pseudonym(:active_all => true)
@course.enroll_student(user).accept!
user
json = api_call(:get, url, url_options)
expect(json.count).to eq 0
end

it 'only returns collaborations of type external_tool_collaboration' do
json = api_call(:get, url, url_options)
expect(json.count).to eq 1
expect(json[0]['collaboration_type']).to eq "external_tool_collaboration"
end

it 'returns the creating users name in the response' do
json = api_call(:get, url, url_options)
expect(json.count).to eq 1
expect(json[0]['user_name']).to eq @student.name
end

it 'returns collaborations the user is a collaborator on' do
user = user_with_pseudonym(:active_all => true)
@course.enroll_student(user).accept!
@course_collaboration.update_members([user])
json = api_call(:get, url, url_options)
expect(json.count).to eq 1
end

it 'returns collaborations for which a user has access to through their group membership' do
@group.add_user(@user)
json = api_call(:get, group_url, group_url_options)
expect(json.count).to eq 1
end
collaboration_model(:user => @teacher, :context => @course)
@user = @teacher
@collaboration.update_members(@members)

end

context '/api/v1/collaborations/:id/members' do
before :once do
@members = (1..5).map do
user = user_with_pseudonym(:active_all => true)
@course.enroll_student(user).accept!
user
end
collaboration_model(:user => @teacher, :context => @course)
@user = @teacher
@collaboration.update_members(@members)
end

let(:url) { "/api/v1/collaborations/#{@collaboration.to_param}/members.json" }
let(:url_options) { { :controller => 'collaborations',
:action => 'members',
Expand Down

0 comments on commit 5b8173a

Please sign in to comment.