add collections to groups (backend + api); closes #8670
groups are now a valid context for collections. as a group moderator, you are allowed to do anything (create/update/delete) with any collection or item in the group. as a group member, you are not allowed to create/update/delete collections, but you are allowed to post to them, and edit/delete posts you have made. test plan: - nothing visible, but try making calls through the api. make sure the above permissions are accurately represented - make sure the api doc additions are coherent Change-Id: Ic259c6bdf1988420438a8258bf585671f972cd32 Reviewed-on: https://gerrit.instructure.com/10848 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
This commit is contained in:
parent
2b1a7b74fb
commit
efe769d5df
|
@ -166,7 +166,7 @@ class CollectionItemsController < ApplicationController
|
||||||
# }
|
# }
|
||||||
def show
|
def show
|
||||||
find_item_and_collection
|
find_item_and_collection
|
||||||
if authorized_action(@collection, @current_user, :read)
|
if authorized_action(@item, @current_user, :read)
|
||||||
render :json => collection_items_json([@item], @current_user, session).first
|
render :json => collection_items_json([@item], @current_user, session).first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -206,11 +206,12 @@ class CollectionItemsController < ApplicationController
|
||||||
# -H 'Authorization: Bearer <token>'
|
# -H 'Authorization: Bearer <token>'
|
||||||
#
|
#
|
||||||
def create
|
def create
|
||||||
if authorized_action(@collection, @current_user, :update)
|
@item = @collection.collection_items.new(:user => @current_user)
|
||||||
|
if authorized_action(@item, @current_user, :create)
|
||||||
item_data = CollectionItemData.data_for_url(params[:link_url] || "", @current_user)
|
item_data = CollectionItemData.data_for_url(params[:link_url] || "", @current_user)
|
||||||
return render_unauthorized_action unless item_data
|
return render_unauthorized_action unless item_data
|
||||||
item_data.image_url = params[:image_url] if item_data.new_record?
|
item_data.image_url = params[:image_url] if item_data.new_record?
|
||||||
@item = @collection.collection_items.new(:collection_item_data => item_data, :user => @current_user)
|
@item.collection_item_data = item_data
|
||||||
@item.attributes = params.slice(*ITEM_SETTABLE_ATTRIBUTES)
|
@item.attributes = params.slice(*ITEM_SETTABLE_ATTRIBUTES)
|
||||||
|
|
||||||
if @item.errors.empty? && @item.save
|
if @item.errors.empty? && @item.save
|
||||||
|
@ -238,7 +239,7 @@ class CollectionItemsController < ApplicationController
|
||||||
#
|
#
|
||||||
def update
|
def update
|
||||||
find_item_and_collection
|
find_item_and_collection
|
||||||
if authorized_action(@collection, @current_user, :update)
|
if authorized_action(@item, @current_user, :update)
|
||||||
if @item.update_attributes(params.slice(*ITEM_SETTABLE_ATTRIBUTES))
|
if @item.update_attributes(params.slice(*ITEM_SETTABLE_ATTRIBUTES))
|
||||||
render :json => collection_items_json([@item], @current_user, session).first
|
render :json => collection_items_json([@item], @current_user, session).first
|
||||||
else
|
else
|
||||||
|
@ -260,7 +261,7 @@ class CollectionItemsController < ApplicationController
|
||||||
# -H 'Authorization: Bearer <token>'
|
# -H 'Authorization: Bearer <token>'
|
||||||
def destroy
|
def destroy
|
||||||
find_item_and_collection
|
find_item_and_collection
|
||||||
if authorized_action(@collection, @current_user, :update)
|
if authorized_action(@item, @current_user, :delete)
|
||||||
if @item.destroy
|
if @item.destroy
|
||||||
render :json => collection_items_json([@item], @current_user, session).first
|
render :json => collection_items_json([@item], @current_user, session).first
|
||||||
else
|
else
|
||||||
|
@ -296,7 +297,7 @@ class CollectionItemsController < ApplicationController
|
||||||
# }
|
# }
|
||||||
def upvote
|
def upvote
|
||||||
find_item_and_collection
|
find_item_and_collection
|
||||||
if authorized_action(@collection, @current_user, :read)
|
if authorized_action(@item, @current_user, :read)
|
||||||
@upvote = find_upvote
|
@upvote = find_upvote
|
||||||
@upvote ||= @item.collection_item_data.collection_item_upvotes.create!({ :user => @current_user })
|
@upvote ||= @item.collection_item_data.collection_item_upvotes.create!({ :user => @current_user })
|
||||||
render :json => collection_item_upvote_json(@item, @upvote, @current_user, session)
|
render :json => collection_item_upvote_json(@item, @upvote, @current_user, session)
|
||||||
|
@ -316,7 +317,7 @@ class CollectionItemsController < ApplicationController
|
||||||
# -H 'Authorization: Bearer <token>'
|
# -H 'Authorization: Bearer <token>'
|
||||||
def remove_upvote
|
def remove_upvote
|
||||||
find_item_and_collection
|
find_item_and_collection
|
||||||
if authorized_action(@collection, @current_user, :read)
|
if authorized_action(@item, @current_user, :read)
|
||||||
@upvote = find_upvote
|
@upvote = find_upvote
|
||||||
if @upvote
|
if @upvote
|
||||||
@upvote.destroy
|
@upvote.destroy
|
||||||
|
|
|
@ -22,10 +22,15 @@
|
||||||
#
|
#
|
||||||
# Collections are buckets of content that can be used to organize links to
|
# Collections are buckets of content that can be used to organize links to
|
||||||
# helpful resources. For instance, a user could create a collection storing a
|
# helpful resources. For instance, a user could create a collection storing a
|
||||||
# set of links to various web sites containing potential discussion questions.
|
# set of links to various web sites containing potential discussion questions,
|
||||||
|
# or members of a group could all contribute to a collection focused on
|
||||||
|
# potential assessment questions.
|
||||||
#
|
#
|
||||||
# A user can have multiple collections, and each can be marked as private
|
# A user/group can have multiple collections, and each can be marked as private
|
||||||
# (viewable only to the user) or public (viewable by the world).
|
# (viewable only to the user/group) or public (viewable by the world).
|
||||||
|
#
|
||||||
|
# Group collections can only be created, updated, or deleted by group
|
||||||
|
# moderators.
|
||||||
#
|
#
|
||||||
# A Collection object looks like:
|
# A Collection object looks like:
|
||||||
#
|
#
|
||||||
|
@ -109,7 +114,8 @@ class CollectionsController < ApplicationController
|
||||||
|
|
||||||
# @API Create a collection
|
# @API Create a collection
|
||||||
#
|
#
|
||||||
# Creates a new collection. You can only create collections on your own user.
|
# Creates a new collection. You can only create collections on your own user,
|
||||||
|
# or on a group to which you belong.
|
||||||
#
|
#
|
||||||
# @argument name
|
# @argument name
|
||||||
# @argument visibility
|
# @argument visibility
|
||||||
|
|
|
@ -53,5 +53,11 @@ class Collection < ActiveRecord::Base
|
||||||
|
|
||||||
given { |user| self.context == user }
|
given { |user| self.context == user }
|
||||||
can :read and can :create and can :update and can :delete and can :comment
|
can :read and can :create and can :update and can :delete and can :comment
|
||||||
|
|
||||||
|
given { |user| self.context.respond_to?(:has_member?) && self.context.has_member?(user) }
|
||||||
|
can :read and can :comment
|
||||||
|
|
||||||
|
given { |user| self.context.respond_to?(:has_moderator?) && self.context.has_moderator?(user) }
|
||||||
|
can :read and can :create and can :update and can :delete and can :comment
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -101,10 +101,19 @@ class CollectionItem < ActiveRecord::Base
|
||||||
given { |user, session| self.collection.grants_right?(user, session, :comment) }
|
given { |user, session| self.collection.grants_right?(user, session, :comment) }
|
||||||
can :comment
|
can :comment
|
||||||
|
|
||||||
|
given { |user, session| self.collection.grants_right?(user, session, :create) }
|
||||||
|
can :create
|
||||||
|
|
||||||
given { |user, session| self.collection.grants_right?(user, session, :delete) }
|
given { |user, session| self.collection.grants_right?(user, session, :delete) }
|
||||||
can :delete
|
can :delete
|
||||||
|
|
||||||
given { |user, session| self.collection.grants_right?(user, session, :update) }
|
given { |user, session| self.collection.grants_right?(user, session, :update) }
|
||||||
can :update
|
can :update
|
||||||
|
|
||||||
|
given { |user| self.user == user }
|
||||||
|
can :read and can :update and can :delete
|
||||||
|
|
||||||
|
given { |user| self.collection.context.respond_to?(:has_member?) && self.collection.context.has_member?(user) }
|
||||||
|
can :create
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,6 +58,7 @@ class Group < ActiveRecord::Base
|
||||||
has_many :short_messages, :through => :short_message_associations, :dependent => :destroy
|
has_many :short_messages, :through => :short_message_associations, :dependent => :destroy
|
||||||
has_many :media_objects, :as => :context
|
has_many :media_objects, :as => :context
|
||||||
has_many :zip_file_imports, :as => :context
|
has_many :zip_file_imports, :as => :context
|
||||||
|
has_many :collections, :as => :context
|
||||||
|
|
||||||
before_save :ensure_defaults, :maintain_category_attribute
|
before_save :ensure_defaults, :maintain_category_attribute
|
||||||
after_save :close_memberships_if_deleted
|
after_save :close_memberships_if_deleted
|
||||||
|
|
|
@ -91,6 +91,10 @@ class GroupCategory < ActiveRecord::Base
|
||||||
self.role.present?
|
self.role.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Group categories generally restrict students to only be in one group per
|
||||||
|
# category, but we sort of cheat and implement student organized groups and
|
||||||
|
# communities as one big group category, and then relax that membership
|
||||||
|
# restriction.
|
||||||
def allows_multiple_memberships?
|
def allows_multiple_memberships?
|
||||||
self.student_organized? || self.communities?
|
self.student_organized? || self.communities?
|
||||||
end
|
end
|
||||||
|
|
|
@ -840,6 +840,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
|
|
||||||
api.with_options(:controller => :collections) do |collections|
|
api.with_options(:controller => :collections) do |collections|
|
||||||
collections.resources :collections, :path_prefix => "users/:user_id", :name_prefix => "user_"
|
collections.resources :collections, :path_prefix => "users/:user_id", :name_prefix => "user_"
|
||||||
|
collections.resources :collections, :path_prefix => "groups/:group_id", :name_prefix => "group_"
|
||||||
|
|
||||||
collections.with_options(:controller => :collection_items) do |items|
|
collections.with_options(:controller => :collection_items) do |items|
|
||||||
items.get "collections/:collection_id/items", :action => :index, :path_name => 'collection_items_list'
|
items.get "collections/:collection_id/items", :action => :index, :path_name => 'collection_items_list'
|
||||||
|
|
|
@ -19,27 +19,7 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')
|
require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')
|
||||||
|
|
||||||
describe "Collections API", :type => :integration do
|
describe "Collections API", :type => :integration do
|
||||||
before do
|
shared_examples_for "full access to collections" do
|
||||||
user_with_pseudonym
|
|
||||||
@collections_path = "/api/v1/users/#{@user.id}/collections"
|
|
||||||
@collections_path_options = { :controller => "collections", :action => "index", :format => "json", :user_id => @user.to_param }
|
|
||||||
@c1 = @user.collections.create!(:name => 'test1', :visibility => 'private')
|
|
||||||
@c2 = @user.collections.create!(:name => 'test2', :visibility => 'public')
|
|
||||||
@c1_json =
|
|
||||||
{
|
|
||||||
'id' => @c1.id,
|
|
||||||
'name' => @c1.name,
|
|
||||||
'visibility' => 'private',
|
|
||||||
}
|
|
||||||
@c2_json =
|
|
||||||
{
|
|
||||||
'id' => @c2.id,
|
|
||||||
'name' => @c2.name,
|
|
||||||
'visibility' => 'public',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
context "a user's own collections" do
|
|
||||||
it "should allow retrieving a paginated collection list" do
|
it "should allow retrieving a paginated collection list" do
|
||||||
json = api_call(:get, @collections_path, @collections_path_options)
|
json = api_call(:get, @collections_path, @collections_path_options)
|
||||||
response['Link'].should be_present
|
response['Link'].should be_present
|
||||||
|
@ -102,7 +82,7 @@ describe "Collections API", :type => :integration do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "another user's collections" do
|
shared_examples_for "public only access to collections" do
|
||||||
before do
|
before do
|
||||||
user_with_pseudonym
|
user_with_pseudonym
|
||||||
end
|
end
|
||||||
|
@ -123,6 +103,15 @@ describe "Collections API", :type => :integration do
|
||||||
json['message'].should match /not authorized/
|
json['message'].should match /not authorized/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should not allow creating a collection" do
|
||||||
|
expect {
|
||||||
|
json = api_call(:post, @collections_path, @collections_path_options.merge(:action => "create"), {
|
||||||
|
:name => "test3",
|
||||||
|
:visibility => 'public',
|
||||||
|
}, {}, :expected_status => 401)
|
||||||
|
}.to change(CollectionItem, :count).by(0)
|
||||||
|
end
|
||||||
|
|
||||||
it "should not allow updating a collection" do
|
it "should not allow updating a collection" do
|
||||||
json = api_call(:put, @collections_path + "/#{@c2.id}", @collections_path_options.merge(:collection_id => @c2.to_param, :action => "update"), {
|
json = api_call(:put, @collections_path + "/#{@c2.id}", @collections_path_options.merge(:collection_id => @c2.to_param, :action => "update"), {
|
||||||
:name => "test2 edited",
|
:name => "test2 edited",
|
||||||
|
@ -136,234 +125,400 @@ describe "Collections API", :type => :integration do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Collection Items" do
|
def create_collections(context)
|
||||||
before do
|
@c1 = context.collections.create!(:name => 'test1', :visibility => 'private')
|
||||||
@i1 = collection_item_model(:description => "item 1", :user => @c1.context, :collection => @c1, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/one"))
|
@c2 = context.collections.create!(:name => 'test2', :visibility => 'public')
|
||||||
@i2 = collection_item_model(:description => "item 2", :user => @c1.context, :collection => @c1, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/two"))
|
@c1_json =
|
||||||
@i3 = collection_item_model(:description => "item 3", :user => @c2.context, :collection => @c2, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/three"))
|
|
||||||
@items1_path = "/api/v1/collections/#{@c1.id}/items"
|
|
||||||
@items2_path = "/api/v1/collections/#{@c2.id}/items"
|
|
||||||
@items1_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c1.to_param }
|
|
||||||
@items2_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c2.to_param }
|
|
||||||
|
|
||||||
@user1 = @user
|
|
||||||
user_with_pseudonym
|
|
||||||
@user2 = @user
|
|
||||||
@user = @user1
|
|
||||||
@c3 = @user2.collections.create!(:name => 'user2', :visibility => 'public')
|
|
||||||
@i4 = collection_item_model(:description => "cloned item 3", :user => @c3.context, :collection => @c3, :collection_item_data => @i3.collection_item_data); @i3.reload
|
|
||||||
@items3_path = "/api/v1/collections/#{@c3.id}/items"
|
|
||||||
@items3_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c3.to_param }
|
|
||||||
end
|
|
||||||
|
|
||||||
def item_json(item, upvoted_by_user = false)
|
|
||||||
{
|
{
|
||||||
'id' => item.id,
|
'id' => @c1.id,
|
||||||
'collection_id' => item.collection_id,
|
'name' => @c1.name,
|
||||||
'item_type' => item.collection_item_data.item_type,
|
'visibility' => 'private',
|
||||||
'link_url' => item.collection_item_data.link_url,
|
|
||||||
'post_count' => item.collection_item_data.post_count,
|
|
||||||
'upvote_count' => item.collection_item_data.upvote_count,
|
|
||||||
'upvoted_by_user' => upvoted_by_user,
|
|
||||||
'root_item_id' => item.collection_item_data.root_item_id,
|
|
||||||
'image_url' => item.data.image_attachment && "http://www.example.com/images/thumbnails/#{item.data.image_attachment.id}/#{item.data.image_attachment.uuid}?size=640x%3E",
|
|
||||||
'image_pending' => item.data.image_pending,
|
|
||||||
'html_preview' => item.data.html_preview,
|
|
||||||
'description' => item.description,
|
|
||||||
'url' => "http://www.example.com/api/v1/collections/items/#{item.id}",
|
|
||||||
}
|
}
|
||||||
|
@c2_json =
|
||||||
|
{
|
||||||
|
'id' => @c2.id,
|
||||||
|
'name' => @c2.name,
|
||||||
|
'visibility' => 'public',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_collection_items(user)
|
||||||
|
@i1 = collection_item_model(:description => "item 1", :user => user, :collection => @c1, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/one"))
|
||||||
|
@i2 = collection_item_model(:description => "item 2", :user => user, :collection => @c1, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/two"))
|
||||||
|
@i3 = collection_item_model(:description => "item 3", :user => user, :collection => @c2, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/three"))
|
||||||
|
@unscoped_items_path = "/api/v1/collections/items"
|
||||||
|
@c1_items_path = "/api/v1/collections/#{@c1.id}/items"
|
||||||
|
@c2_items_path = "/api/v1/collections/#{@c2.id}/items"
|
||||||
|
@unscoped_items_path_options = { :controller => "collection_items", :action => "index", :format => "json" }
|
||||||
|
@c1_items_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c1.to_param }
|
||||||
|
@c2_items_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c2.to_param }
|
||||||
|
end
|
||||||
|
|
||||||
|
def item_json(item, upvoted_by_user = false)
|
||||||
|
{
|
||||||
|
'id' => item.id,
|
||||||
|
'collection_id' => item.collection_id,
|
||||||
|
'item_type' => item.collection_item_data.item_type,
|
||||||
|
'link_url' => item.collection_item_data.link_url,
|
||||||
|
'post_count' => item.collection_item_data.post_count,
|
||||||
|
'upvote_count' => item.collection_item_data.upvote_count,
|
||||||
|
'upvoted_by_user' => upvoted_by_user,
|
||||||
|
'root_item_id' => item.collection_item_data.root_item_id,
|
||||||
|
'image_url' => item.data.image_attachment && "http://www.example.com/images/thumbnails/#{item.data.image_attachment.id}/#{item.data.image_attachment.uuid}?size=640x%3E",
|
||||||
|
'image_pending' => item.data.image_pending,
|
||||||
|
'html_preview' => item.data.html_preview,
|
||||||
|
'description' => item.description,
|
||||||
|
'url' => "http://www.example.com/api/v1/collections/items/#{item.id}",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context "user scoped collections" do
|
||||||
|
before do
|
||||||
|
user_with_pseudonym
|
||||||
|
@collections_path = "/api/v1/users/#{@user.id}/collections"
|
||||||
|
@collections_path_options = { :controller => "collections", :action => "index", :format => "json", :user_id => @user.to_param }
|
||||||
|
create_collections(@user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should allow retrieving a pagniated item list from a private collection" do
|
context "a user's own collections" do
|
||||||
json = api_call(:get, @items1_path, @items1_path_options)
|
it_should_behave_like "full access to collections"
|
||||||
response['Link'].should be_present
|
|
||||||
json.should == [ item_json(@i2), item_json(@i1) ]
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "item creation" do
|
|
||||||
it "should allow creating from a http url" do
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
|
||||||
new_item = @c1.collection_items.last(:order => :id)
|
|
||||||
new_item.collection_item_data.link_url.should == "http://www.example.com/a/b/c"
|
|
||||||
new_item.user.should == @user
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should allow cloning an existing item" do
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "http://localhost/api/v1/collections/items/#{@i3.id}", :description => 'cloned' })
|
|
||||||
json['post_count'].should == 3
|
|
||||||
new_item = @c1.collection_items.last(:order => :id)
|
|
||||||
new_item.collection_item_data.should == @i3.collection_item_data
|
|
||||||
new_item.user.should == @user
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow cloning an item the user can't access" do
|
|
||||||
@user = @user2
|
|
||||||
expect {
|
|
||||||
json = api_call(:post, @items3_path, @items3_path_options.merge(:action => "create"), { :link_url => "http://localhost/api/v1/collections/items/#{@i1.id}", :description => 'cloned' }, {}, :expected_status => 401)
|
|
||||||
}.to change(CollectionItem, :count).by(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should reject non-http urls" do
|
|
||||||
expect {
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "javascript:alert(1)", :description => 'new item' }, {}, :expected_status => 400)
|
|
||||||
}.to change(CollectionItem, :count).by(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "images" do
|
|
||||||
it "should take a snapshot of the link url if no image is provided and there is no embedly image" do
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
|
||||||
@item = CollectionItem.find(json['id'])
|
|
||||||
@item.data.image_pending.should == true
|
|
||||||
@att = Attachment.new(:uploaded_data => stub_png_data)
|
|
||||||
CutyCapt.expects(:snapshot_attachment_for_url).with(@item.data.link_url).returns(@att)
|
|
||||||
run_job()
|
|
||||||
|
|
||||||
@att.reload.context.should == Account.default
|
|
||||||
|
|
||||||
@item.reload.data.image_pending.should == false
|
|
||||||
@item.data.image_attachment.should == @att
|
|
||||||
|
|
||||||
json = api_call(:get, "/api/v1/collections/items/#{@item.id}", { :controller => "collection_items", :item_id => @item.to_param, :action => "show", :format => "json" })
|
|
||||||
json['image_pending'].should == false
|
|
||||||
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should clone and use the image if provided" do
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :image_url => "http://www.example.com/my/image.png", :description => 'new item' })
|
|
||||||
@item = CollectionItem.find(json['id'])
|
|
||||||
@item.data.image_pending.should == true
|
|
||||||
http_res = mock('Net::HTTPOK', :body => File.read(Rails.root+"public/images/cancel.png"), :code => 200)
|
|
||||||
Canvas::HTTP.expects(:get).with("http://www.example.com/my/image.png").returns(http_res)
|
|
||||||
run_job()
|
|
||||||
|
|
||||||
@item.reload.data.image_pending.should == false
|
|
||||||
@att = @item.data.image_attachment
|
|
||||||
@att.should be_present
|
|
||||||
@att.context.should == Account.default
|
|
||||||
|
|
||||||
json = api_call(:get, "/api/v1/collections/items/#{@item.id}", { :controller => "collection_items", :item_id => @item.to_param, :action => "show", :format => "json" })
|
|
||||||
json['image_pending'].should == false
|
|
||||||
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should use the embedly image if no image is provided" do
|
|
||||||
json = api_call(:post, @items1_path, @items1_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
|
||||||
@item = CollectionItem.find(json['id'])
|
|
||||||
@item.data.image_pending.should == true
|
|
||||||
Canvas::Embedly.any_instance.expects(:get_embedly_data).with("http://www.example.com/a/b/c").returns(stub_everything('embedly api', :type => 'test', :images => [{'url' => 'http://www.example.com/image1'}], :html => "<iframe>test</iframe>"))
|
|
||||||
http_res = mock('Net::HTTPOK', :body => File.read(Rails.root+"public/images/cancel.png"), :code => 200)
|
|
||||||
Canvas::HTTP.expects(:get).with("http://www.example.com/image1").returns(http_res)
|
|
||||||
run_job()
|
|
||||||
|
|
||||||
@item.reload.data.image_pending.should == false
|
|
||||||
@att = @item.data.image_attachment
|
|
||||||
@att.should be_present
|
|
||||||
@att.context.should == Account.default
|
|
||||||
|
|
||||||
@item.data.html_preview.should == "<iframe>test</iframe>"
|
|
||||||
|
|
||||||
json = api_call(:get, "/api/v1/collections/items/#{@item.id}", { :controller => "collection_items", :item_id => @item.to_param, :action => "show", :format => "json" })
|
|
||||||
json['image_pending'].should == false
|
|
||||||
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should allow editing mutable fields" do
|
|
||||||
json = api_call(:put, "/api/v1/collections/items/#{@i1.id}", { :controller => "collection_items", :item_id => @i1.to_param, :action => "update", :format => "json" }, { :description => "modified", :link_url => 'cant change', :item_type => 'cant change', :image_url => "http://www.example.com/cant_change" })
|
|
||||||
json.should == item_json(@i1.reload)
|
|
||||||
@i1.description.should == "modified"
|
|
||||||
@i1.collection_item_data.item_type.should == "url"
|
|
||||||
@i1.data.image_pending.should == false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should allow deleting an owned item" do
|
|
||||||
json = api_call(:delete, "/api/v1/collections/items/#{@i1.id}", { :controller => "collection_items", :item_id => @i1.to_param, :action => "destroy", :format => "json" })
|
|
||||||
@i1.reload.state.should == :deleted
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow getting from a deleted collection" do
|
|
||||||
@i1.collection.destroy
|
|
||||||
# deleting the collection doesn't mark all the items as deleted, though
|
|
||||||
# they can't be retrieved through the api
|
|
||||||
# this makes undeleting work better
|
|
||||||
@i1.reload.should be_active
|
|
||||||
json = api_call(:get, "/api/v1/collections/items/#{@i1.id}", { :controller => "collection_items", :item_id => @i1.to_param, :action => "show", :format => "json" }, {}, {}, :expected_status => 404)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "deleted item" do
|
|
||||||
before do
|
|
||||||
@i1.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not return in the list" do
|
|
||||||
json = api_call(:get, @items1_path, @items1_path_options)
|
|
||||||
json.should == [ item_json(@i2) ]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow getting" do
|
|
||||||
json = api_call(:get, "/api/v1/collections/items/#{@i1.id}", { :controller => "collection_items", :item_id => @i1.to_param, :action => "show", :format => "json" }, {}, {}, :expected_status => 404)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "another user's collections" do
|
context "another user's collections" do
|
||||||
|
it_should_behave_like "public only access to collections"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Collection Items" do
|
||||||
before do
|
before do
|
||||||
|
create_collection_items(@user)
|
||||||
|
@user1 = @user
|
||||||
user_with_pseudonym
|
user_with_pseudonym
|
||||||
|
@user2 = @user
|
||||||
|
@user = @user1
|
||||||
|
@c3 = @user2.collections.create!(:name => 'user2', :visibility => 'public')
|
||||||
|
@i4 = collection_item_model(:description => "cloned item 3", :user => @c3.context, :collection => @c3, :collection_item_data => @i3.collection_item_data); @i3.reload
|
||||||
|
@items3_path = "/api/v1/collections/#{@c3.id}/items"
|
||||||
|
@items3_path_options = { :controller => "collection_items", :action => "index", :format => "json", :collection_id => @c3.to_param }
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not allow listing from a private collection" do
|
it "should allow retrieving a pagniated item list from a private collection" do
|
||||||
json = api_call(:get, @items1_path, @items1_path_options, {}, {}, :expected_status => 401)
|
json = api_call(:get, @c1_items_path, @c1_items_path_options)
|
||||||
end
|
|
||||||
|
|
||||||
it "should allow listing a public collection" do
|
|
||||||
json = api_call(:get, @items2_path, @items2_path_options)
|
|
||||||
response['Link'].should be_present
|
response['Link'].should be_present
|
||||||
json.should == [ item_json(@i3) ]
|
json.should == [ item_json(@i2), item_json(@i1) ]
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "item creation" do
|
||||||
|
it "should allow creating from a http url" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
||||||
|
new_item = @c1.collection_items.last(:order => :id)
|
||||||
|
new_item.collection_item_data.link_url.should == "http://www.example.com/a/b/c"
|
||||||
|
new_item.user.should == @user
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow cloning an existing item" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://localhost/api/v1/collections/items/#{@i3.id}", :description => 'cloned' })
|
||||||
|
json['post_count'].should == 3
|
||||||
|
new_item = @c1.collection_items.last(:order => :id)
|
||||||
|
new_item.collection_item_data.should == @i3.collection_item_data
|
||||||
|
new_item.user.should == @user
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow cloning an item the user can't access" do
|
||||||
|
@user = @user2
|
||||||
|
expect {
|
||||||
|
json = api_call(:post, @items3_path, @items3_path_options.merge(:action => "create"), { :link_url => "http://localhost/api/v1/collections/items/#{@i1.id}", :description => 'cloned' }, {}, :expected_status => 401)
|
||||||
|
}.to change(CollectionItem, :count).by(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should reject non-http urls" do
|
||||||
|
expect {
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "javascript:alert(1)", :description => 'new item' }, {}, :expected_status => 400)
|
||||||
|
}.to change(CollectionItem, :count).by(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "images" do
|
||||||
|
it "should take a snapshot of the link url if no image is provided and there is no embedly image" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
||||||
|
@item = CollectionItem.find(json['id'])
|
||||||
|
@item.data.image_pending.should == true
|
||||||
|
@att = Attachment.new(:uploaded_data => stub_png_data)
|
||||||
|
CutyCapt.expects(:snapshot_attachment_for_url).with(@item.data.link_url).returns(@att)
|
||||||
|
run_job()
|
||||||
|
|
||||||
|
@att.reload.context.should == Account.default
|
||||||
|
|
||||||
|
@item.reload.data.image_pending.should == false
|
||||||
|
@item.data.image_attachment.should == @att
|
||||||
|
|
||||||
|
json = api_call(:get, "#{@unscoped_items_path}/#{@item.id}", @unscoped_items_path_options.merge(:item_id => @item.to_param, :action => "show"))
|
||||||
|
json['image_pending'].should == false
|
||||||
|
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should clone and use the image if provided" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :image_url => "http://www.example.com/my/image.png", :description => 'new item' })
|
||||||
|
@item = CollectionItem.find(json['id'])
|
||||||
|
@item.data.image_pending.should == true
|
||||||
|
http_res = mock('Net::HTTPOK', :body => File.read(Rails.root+"public/images/cancel.png"), :code => 200)
|
||||||
|
Canvas::HTTP.expects(:get).with("http://www.example.com/my/image.png").returns(http_res)
|
||||||
|
run_job()
|
||||||
|
|
||||||
|
@item.reload.data.image_pending.should == false
|
||||||
|
@att = @item.data.image_attachment
|
||||||
|
@att.should be_present
|
||||||
|
@att.context.should == Account.default
|
||||||
|
|
||||||
|
json = api_call(:get, "#{@unscoped_items_path}/#{@item.id}", @unscoped_items_path_options.merge(:item_id => @item.to_param, :action => "show"))
|
||||||
|
json['image_pending'].should == false
|
||||||
|
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should use the embedly image if no image is provided" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
||||||
|
@item = CollectionItem.find(json['id'])
|
||||||
|
@item.data.image_pending.should == true
|
||||||
|
Canvas::Embedly.any_instance.expects(:get_embedly_data).with("http://www.example.com/a/b/c").returns(stub_everything('embedly api', :type => 'test', :images => [{'url' => 'http://www.example.com/image1'}], :html => "<iframe>test</iframe>"))
|
||||||
|
http_res = mock('Net::HTTPOK', :body => File.read(Rails.root+"public/images/cancel.png"), :code => 200)
|
||||||
|
Canvas::HTTP.expects(:get).with("http://www.example.com/image1").returns(http_res)
|
||||||
|
run_job()
|
||||||
|
|
||||||
|
@item.reload.data.image_pending.should == false
|
||||||
|
@att = @item.data.image_attachment
|
||||||
|
@att.should be_present
|
||||||
|
@att.context.should == Account.default
|
||||||
|
|
||||||
|
@item.data.html_preview.should == "<iframe>test</iframe>"
|
||||||
|
|
||||||
|
json = api_call(:get, "#{@unscoped_items_path}/#{@item.id}", @unscoped_items_path_options.merge(:item_id => @item.to_param, :action => "show"))
|
||||||
|
json['image_pending'].should == false
|
||||||
|
json['image_url'].should == "http://www.example.com/images/thumbnails/#{@att.id}/#{@att.uuid}?size=640x%3E"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow editing mutable fields" do
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "update"), {
|
||||||
|
:description => "modified",
|
||||||
|
:link_url => 'cant change',
|
||||||
|
:item_type => 'cant change',
|
||||||
|
:image_url => "http://www.example.com/cant_change"
|
||||||
|
})
|
||||||
|
json.should == item_json(@i1.reload)
|
||||||
|
@i1.description.should == "modified"
|
||||||
|
@i1.collection_item_data.item_type.should == "url"
|
||||||
|
@i1.data.image_pending.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow deleting an owned item" do
|
||||||
|
json = api_call(:delete, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "destroy"))
|
||||||
|
@i1.reload.state.should == :deleted
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow getting from a deleted collection" do
|
||||||
|
@i1.collection.destroy
|
||||||
|
# deleting the collection doesn't mark all the items as deleted, though
|
||||||
|
# they can't be retrieved through the api
|
||||||
|
# this makes undeleting work better
|
||||||
|
@i1.reload.should be_active
|
||||||
|
json = api_call(:get, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "show"), {}, {}, :expected_status => 404)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "deleted item" do
|
||||||
|
before do
|
||||||
|
@i1.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not return in the list" do
|
||||||
|
json = api_call(:get, @c1_items_path, @c1_items_path_options)
|
||||||
|
json.should == [ item_json(@i2) ]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow getting" do
|
||||||
|
json = api_call(:get, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "show"), {}, {}, :expected_status => 404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "another user's collections" do
|
||||||
|
before do
|
||||||
|
user_with_pseudonym
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow listing from a private collection" do
|
||||||
|
json = api_call(:get, @c1_items_path, @c1_items_path_options, {}, {}, :expected_status => 401)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow listing a public collection" do
|
||||||
|
json = api_call(:get, @c2_items_path, @c2_items_path_options)
|
||||||
|
response['Link'].should be_present
|
||||||
|
json.should == [ item_json(@i3) ]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "upvoting" do
|
||||||
|
it "should allow upvoting an item" do
|
||||||
|
@user = @user2
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i3.id}/upvote", @unscoped_items_path_options.merge(:action => "upvote", :item_id => @i3.to_param))
|
||||||
|
json.slice('item_id', 'root_item_id', 'user_id').should == {
|
||||||
|
'item_id' => @i3.id,
|
||||||
|
'root_item_id' => @i3.id,
|
||||||
|
'user_id' => @user.id,
|
||||||
|
}
|
||||||
|
@i3.reload.collection_item_data.upvote_count.should == 1
|
||||||
|
|
||||||
|
# upvoting again is a no-op
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i3.id}/upvote", @unscoped_items_path_options.merge(:action => "upvote", :item_id => @i3.to_param))
|
||||||
|
json.slice('item_id', 'root_item_id', 'user_id').should == {
|
||||||
|
'item_id' => @i3.id,
|
||||||
|
'root_item_id' => @i3.id,
|
||||||
|
'user_id' => @user.id,
|
||||||
|
}
|
||||||
|
@i3.reload.collection_item_data.upvote_count.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow upvoting a non-visible item" do
|
||||||
|
@user = @user2
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i1.id}/upvote", @unscoped_items_path_options.merge(:action => "upvote", :item_id => @i1.to_param), {}, {}, :expected_status => 401)
|
||||||
|
@i1.reload.collection_item_data.upvote_count.should == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "de-upvoting" do
|
||||||
|
before do
|
||||||
|
@user = @user2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow removing an upvote" do
|
||||||
|
@i3.collection_item_data.collection_item_upvotes.create!(:user => @user)
|
||||||
|
@i3.reload.collection_item_data.upvote_count.should == 1
|
||||||
|
json = api_call(:delete, "#{@unscoped_items_path}/#{@i3.id}/upvote", @unscoped_items_path_options.merge(:action => "remove_upvote", :item_id => @i3.to_param))
|
||||||
|
@i3.reload.collection_item_data.upvote_count.should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should ignore if the user hasn't upvoted the item" do
|
||||||
|
json = api_call(:delete, "#{@unscoped_items_path}/#{@i3.id}/upvote", @unscoped_items_path_options.merge(:action => "remove_upvote", :item_id => @i3.to_param))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "upvoting" do
|
context "group scoped collections" do
|
||||||
it "should allow upvoting an item" do
|
before do
|
||||||
@user = @user2
|
user_with_pseudonym
|
||||||
json = api_call(:put, "/api/v1/collections/items/#{@i3.id}/upvote", { :controller => "collection_items", :action => "upvote", :item_id => @i3.to_param, :format => "json" })
|
group_model({:group_category => GroupCategory.communities_for(Account.default), :is_public => true})
|
||||||
json.slice('item_id', 'root_item_id', 'user_id').should == {
|
@collections_path = "/api/v1/groups/#{@group.id}/collections"
|
||||||
'item_id' => @i3.id,
|
@collections_path_options = { :controller => "collections", :action => "index", :format => "json", :group_id => @group.to_param }
|
||||||
'root_item_id' => @i3.id,
|
create_collections(@group)
|
||||||
'user_id' => @user.id,
|
|
||||||
}
|
|
||||||
@i3.reload.collection_item_data.upvote_count.should == 1
|
|
||||||
|
|
||||||
# upvoting again is a no-op
|
|
||||||
json = api_call(:put, "/api/v1/collections/items/#{@i3.id}/upvote", { :controller => "collection_items", :action => "upvote", :item_id => @i3.to_param, :format => "json" })
|
|
||||||
json.slice('item_id', 'root_item_id', 'user_id').should == {
|
|
||||||
'item_id' => @i3.id,
|
|
||||||
'root_item_id' => @i3.id,
|
|
||||||
'user_id' => @user.id,
|
|
||||||
}
|
|
||||||
@i3.reload.collection_item_data.upvote_count.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow upvoting a non-visible item" do
|
|
||||||
@user = @user2
|
|
||||||
json = api_call(:put, "/api/v1/collections/items/#{@i1.id}/upvote", { :controller => "collection_items", :action => "upvote", :item_id => @i1.to_param, :format => "json" }, {}, {}, :expected_status => 401)
|
|
||||||
@i1.reload.collection_item_data.upvote_count.should == 0
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "de-upvoting" do
|
context "a group's collections, as moderator" do
|
||||||
before do
|
before do
|
||||||
@user = @user2
|
@group_membership = @group.add_user(@user)
|
||||||
|
@group_membership.moderator = true
|
||||||
|
@group_membership.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should allow removing an upvote" do
|
it_should_behave_like "full access to collections"
|
||||||
@i3.collection_item_data.collection_item_upvotes.create!(:user => @user)
|
end
|
||||||
@i3.reload.collection_item_data.upvote_count.should == 1
|
|
||||||
json = api_call(:delete, "/api/v1/collections/items/#{@i3.id}/upvote", { :controller => "collection_items", :action => "remove_upvote", :item_id => @i3.to_param, :format => "json" })
|
context "a group's collections, as member" do
|
||||||
@i3.reload.collection_item_data.upvote_count.should == 0
|
before do
|
||||||
|
@group_membership = @group.add_user(@user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should ignore if the user hasn't upvoted the item" do
|
it "should allow retrieving a paginated collection list" do
|
||||||
json = api_call(:delete, "/api/v1/collections/items/#{@i3.id}/upvote", { :controller => "collection_items", :action => "remove_upvote", :item_id => @i3.to_param, :format => "json" })
|
json = api_call(:get, @collections_path, @collections_path_options)
|
||||||
|
response['Link'].should be_present
|
||||||
|
json.should == [ @c2_json, @c1_json ]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow retrieving a private collection" do
|
||||||
|
json = api_call(:get, @collections_path + "/#{@c1.id}", @collections_path_options.merge(:collection_id => @c1.to_param, :action => "show"))
|
||||||
|
json.should == @c1_json
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow creating a collection" do
|
||||||
|
expect {
|
||||||
|
json = api_call(:post, @collections_path, @collections_path_options.merge(:action => "create"), {
|
||||||
|
:name => "test3",
|
||||||
|
:visibility => 'public',
|
||||||
|
}, {}, :expected_status => 401)
|
||||||
|
}.to change(CollectionItem, :count).by(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow updating a collection" do
|
||||||
|
json = api_call(:put, @collections_path + "/#{@c2.id}", @collections_path_options.merge(:collection_id => @c2.to_param, :action => "update"), {
|
||||||
|
:name => "test2 edited",
|
||||||
|
}, {}, :expected_status => 401)
|
||||||
|
@c2.reload.name.should == "test2"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow deleting a collection" do
|
||||||
|
json = api_call(:delete, @collections_path + "/#{@c2.id}", @collections_path_options.merge(:collection_id => @c2.to_param, :action => "destroy"), {}, {}, :expected_status => 401)
|
||||||
|
@c2.reload.should be_active
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "a group's collections, as a non-member" do
|
||||||
|
it_should_behave_like "public only access to collections"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Collection Items" do
|
||||||
|
before do
|
||||||
|
create_collection_items(@user)
|
||||||
|
@user1 = @user
|
||||||
|
@user2 = user_with_pseudonym
|
||||||
|
@group_membership2 = @group.add_user(@user2)
|
||||||
|
|
||||||
|
@i4 = collection_item_model(:description => "item 4", :user => @user2, :collection => @c2, :collection_item_data => collection_item_data_model(:link_url => "http://www.example.com/three"))
|
||||||
|
end
|
||||||
|
|
||||||
|
context "as a group member" do
|
||||||
|
before do
|
||||||
|
@group_membership = @group.add_user(@user1)
|
||||||
|
@group_membership2 = @group.add_user(@user2)
|
||||||
|
@user = @user2
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow creating a new item" do
|
||||||
|
json = api_call(:post, @c1_items_path, @c1_items_path_options.merge(:action => "create"), { :link_url => "http://www.example.com/a/b/c", :description => 'new item' })
|
||||||
|
new_item = @c1.collection_items.last(:order => :id)
|
||||||
|
new_item.collection_item_data.link_url.should == "http://www.example.com/a/b/c"
|
||||||
|
new_item.user.should == @user
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow updating an item created by someone else" do
|
||||||
|
orig_description = @i1.description
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "update"), {
|
||||||
|
:description => "item1 description edited",
|
||||||
|
}, {}, :expected_status => 401)
|
||||||
|
@i1.reload.description.should == orig_description
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow deleting an item created by someone else" do
|
||||||
|
json = api_call(:delete, "#{@unscoped_items_path}/#{@i1.id}", @unscoped_items_path_options.merge(:item_id => @i1.to_param, :action => "destroy"), {}, {}, :expected_status => 401)
|
||||||
|
@i1.reload.should be_active
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "as a group moderator" do
|
||||||
|
before do
|
||||||
|
@group_membership = @group.add_user(@user1)
|
||||||
|
@group_membership.moderator = true
|
||||||
|
@group_membership.save!
|
||||||
|
@group_membership2 = @group.add_user(@user2)
|
||||||
|
@user = @user1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow updating an item created by someone else" do
|
||||||
|
json = api_call(:put, "#{@unscoped_items_path}/#{@i4.id}", @unscoped_items_path_options.merge(:item_id => @i4.to_param, :action => "update"), { :description => "modified" })
|
||||||
|
json.should == item_json(@i4.reload)
|
||||||
|
@i4.description.should == "modified"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow deleting an item created by someone else" do
|
||||||
|
json = api_call(:delete, "#{@unscoped_items_path}/#{@i4.id}", @unscoped_items_path_options.merge(:item_id => @i4.to_param, :action => "destroy"))
|
||||||
|
@i4.reload.should be_deleted
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue