Add create content share API
closes ADMIN-2809 flag=direct_share Test plan - Ensure you can create a content export and share content between users - Users cannot create shares for other users or share content they do not have access to Change-Id: Ic3c748ad800f85eddd24ac6f0995a363619eed2b Reviewed-on: https://gerrit.instructure.com/204338 Reviewed-by: Jeremy Stanley <jeremy@instructure.com> Tested-by: Jenkins QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Mysti Lilla <mysti@instructure.com>
This commit is contained in:
parent
45d23e3ab6
commit
6d9e4516b1
|
@ -78,6 +78,7 @@
|
|||
# }
|
||||
#
|
||||
class ContentExportsApiController < ApplicationController
|
||||
include ContentExportApiHelper
|
||||
include Api::V1::ContentExport
|
||||
before_action :require_context
|
||||
|
||||
|
@ -147,48 +148,9 @@ class ContentExportsApiController < ApplicationController
|
|||
valid_types = %w(zip)
|
||||
valid_types += %w(qti common_cartridge quizzes2) if @context.is_a?(Course)
|
||||
return render json: { message: 'invalid export_type' }, status: :bad_request unless valid_types.include?(params[:export_type])
|
||||
export = @context.content_exports.build
|
||||
export.user = @current_user
|
||||
export.workflow_state = 'created'
|
||||
export.settings[:skip_notifications] = true if value_to_boolean(params[:skip_notifications])
|
||||
|
||||
# ZipExporter accepts unhashed asset strings, to avoid having to instantiate all the files and folders
|
||||
if params[:select]
|
||||
selected_content = ContentMigration.process_copy_params(params[:select]&.to_unsafe_h,
|
||||
for_content_export: true,
|
||||
return_asset_strings: params[:export_type] == ContentExport::ZIP,
|
||||
global_identifiers: export.can_use_global_identifiers?)
|
||||
end
|
||||
|
||||
case params[:export_type]
|
||||
when 'qti'
|
||||
export.export_type = ContentExport::QTI
|
||||
export.selected_content = selected_content || { all_quizzes: true }
|
||||
when 'zip'
|
||||
export.export_type = ContentExport::ZIP
|
||||
export.selected_content = selected_content || { all_attachments: true }
|
||||
when 'quizzes2'
|
||||
if params[:quiz_id].nil? || params[:quiz_id] !~ Api::ID_REGEX
|
||||
return render json: { message: 'quiz_id required and must be a valid ID' },
|
||||
status: :bad_request
|
||||
elsif !@context.quizzes.exists?(params[:quiz_id])
|
||||
return render json: { message: 'Quiz could not be found' }, status: :bad_request
|
||||
else
|
||||
export.export_type = ContentExport::QUIZZES2
|
||||
# we pass the quiz_id of the quiz we want to clone here
|
||||
export.selected_content = params[:quiz_id]
|
||||
end
|
||||
else
|
||||
export.export_type = ContentExport::COMMON_CARTRIDGE
|
||||
export.selected_content = selected_content || { everything: true }
|
||||
end
|
||||
# recheck, since the export type influences permissions (e.g., students can download zips of non-locked files, but not common cartridges)
|
||||
return unless authorized_action(export, @current_user, :create)
|
||||
|
||||
opts = params.permit(:version).to_unsafe_h
|
||||
export.progress = 0
|
||||
if export.save
|
||||
export.queue_api_job(opts)
|
||||
export = create_content_export_from_api(params, @context, @current_user)
|
||||
return unless export.class == ContentExport
|
||||
if export.id
|
||||
render json: content_export_json(export, @current_user, session)
|
||||
else
|
||||
render json: export.errors, status: :bad_request
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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 Content Shares
|
||||
#
|
||||
# API for creating, accessing and updating Content Sharing. Content shares are used
|
||||
# to share content directly between users.
|
||||
#
|
||||
# @model ContentShare
|
||||
# {
|
||||
# "id": "ContentShare",
|
||||
# "description": "Content shared between two users",
|
||||
# "properties": {
|
||||
# "id": {
|
||||
# "description": "The id of the content share for the current user",
|
||||
# "example": 1,
|
||||
# "type": "integer"
|
||||
# },
|
||||
# "name": {
|
||||
# "description": "The name of the shared content",
|
||||
# "example": "War of 1812 homework",
|
||||
# "type": "string"
|
||||
# },
|
||||
# "created_at": {
|
||||
# "description": "The datetime the content was shared with this user.",
|
||||
# "example": "2017-05-09T10:12:00Z",
|
||||
# "type": "datetime"
|
||||
# },
|
||||
# "updated_at": {
|
||||
# "description": "The datetime the content was updated.",
|
||||
# "example": "2017-05-09T10:12:00Z",
|
||||
# "type": "datetime"
|
||||
# },
|
||||
# "user_id": {
|
||||
# "description": "The id of the user who sent or received the content share.",
|
||||
# "example": 1578941,
|
||||
# "type": "integer"
|
||||
# },
|
||||
# "sender": {
|
||||
# "description": "The user who shared the content. No sender information will be given for the sharing user.",
|
||||
# "example": {"id": 1, "display_name": "Matilda Vargas", "avatar_image_url": "http:\/\/localhost:3000\/image_url", "html_url": "http:\/\/localhost:3000\/users\/1"},
|
||||
# "type": "object"
|
||||
# },
|
||||
# "receivers": {
|
||||
# "description": "An Array of users the content is shared with. An empty array will be returned for the receiving users.",
|
||||
# "example": [{"id": 1, "display_name": "Jon Snow", "avatar_image_url": "http:\/\/localhost:3000\/image_url2", "html_url": "http:\/\/localhost:3000\/users\/2"}],
|
||||
# "type": "array",
|
||||
# "items": {"type": "object"}
|
||||
# },
|
||||
# "read_state": {
|
||||
# "description": "Whether the recipient has viewed the content share.",
|
||||
# "example": "read",
|
||||
# "type": "string"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
class ContentSharesController < ApplicationController
|
||||
include ContentExportApiHelper
|
||||
include Api::V1::ContentShare
|
||||
CONTENT_TYPES = {
|
||||
assignment: Assignment,
|
||||
discussion_topic: DiscussionTopic,
|
||||
page: WikiPage,
|
||||
quiz: Quizzes::Quiz,
|
||||
module: ContextModule,
|
||||
module_item: ContentTag,
|
||||
content_share: ContentShare
|
||||
}.freeze
|
||||
|
||||
before_action :require_user
|
||||
before_action :require_direct_share_enabled
|
||||
|
||||
def require_direct_share_enabled
|
||||
render json: { message: "Feature disabled" }, status: :forbidden unless @domain_root_account.feature_enabled?(:direct_share)
|
||||
end
|
||||
|
||||
|
||||
# @API Create a content share
|
||||
# Share content directly between two or more users
|
||||
#
|
||||
# @argument receiver_ids [Array]
|
||||
# IDs of users to share the content with.
|
||||
#
|
||||
# @argument content_type [Required, String, "assignment"|"discussion_topic"|"page"|"quiz"|"module"|"module_item"]
|
||||
# Type of content you are sharing. 'content_share' allows you to re-share content that is already shared.
|
||||
#
|
||||
# @argument content_id [Required, Integer]
|
||||
# The id of the content that you are sharing
|
||||
#
|
||||
#
|
||||
# @example_request
|
||||
#
|
||||
# curl 'https://<canvas>/api/v1/content_shares \
|
||||
# -d 'content_type=assignment' \
|
||||
# -d 'content_id=1' \
|
||||
# -H 'Authorization: Bearer <token>' \
|
||||
# -X POST
|
||||
#
|
||||
# @returns ContentShare
|
||||
#
|
||||
def create
|
||||
unless @current_user == api_find(User, params[:user_id])
|
||||
return render(json: { message: 'Cannot create content shares for other users'}, status: :forbidden)
|
||||
end
|
||||
create_params = params.permit(:content_type, :content_id, receiver_ids: [])
|
||||
allowed_types = ['assignment', 'discussion_topic', 'page', 'quiz', 'module', 'module_item']
|
||||
receivers = User.active.where(id: create_params[:receiver_ids])
|
||||
return render(json: { message: 'No valid receiving users found' }, status: :bad_request) unless receivers.any?
|
||||
unless create_params[:content_type] && create_params[:content_id]
|
||||
return render(json: { message: 'Content type and id required'}, status: :bad_request)
|
||||
end
|
||||
unless allowed_types.include?(create_params[:content_type])
|
||||
return render(json: { message: "Content type not allowed. Allowed types: #{allowed_types.join(',')}" }, status: :bad_request)
|
||||
end
|
||||
content_type = CONTENT_TYPES[create_params[:content_type]&.to_sym]
|
||||
content = content_type&.where(id: create_params[:content_id])
|
||||
content = if content_type.respond_to? :not_deleted
|
||||
content&.not_deleted
|
||||
elsif content_type.respond_to? :active
|
||||
content&.active
|
||||
end
|
||||
content = content&.where(tag_type: 'context_module') if content_type == ContentTag
|
||||
content = content&.take
|
||||
return render(json: { message: 'Requested share content not found'}, status: :bad_request) unless content
|
||||
|
||||
export_params = ActionController::Parameters.new(skip_notifications: true,
|
||||
select: {create_params[:content_type].pluralize => [create_params[:content_id]]},
|
||||
export_type: ContentExport::COMMON_CARTRIDGE)
|
||||
export = create_content_export_from_api(export_params, content.context, @current_user)
|
||||
return unless export.class == ContentExport
|
||||
return render(json: { message: 'Unable to export content'}, status: :bad_request) unless export.id
|
||||
|
||||
name = Context.asset_name(content)
|
||||
sender_share = @current_user.sent_content_shares.create(content_export: export, name: name, read_state: 'read')
|
||||
receivers.each do |receiver|
|
||||
receiver.received_content_shares.create(content_export: export, sender: @current_user, name: name, read_state: 'unread')
|
||||
end
|
||||
render json: content_share_json(sender_share, @current_user, session), status: :created
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
#
|
||||
|
||||
module ContentExportApiHelper
|
||||
def create_content_export_from_api(params, context, current_user)
|
||||
export = context.content_exports.build
|
||||
export.user = current_user
|
||||
export.workflow_state = 'created'
|
||||
export.settings[:skip_notifications] = true if value_to_boolean(params[:skip_notifications])
|
||||
|
||||
# ZipExporter accepts unhashed asset strings, to avoid having to instantiate all the files and folders
|
||||
if params[:select]
|
||||
selected_content = ContentMigration.process_copy_params(params[:select]&.to_unsafe_h,
|
||||
for_content_export: true,
|
||||
return_asset_strings: params[:export_type] == ContentExport::ZIP,
|
||||
global_identifiers: export.can_use_global_identifiers?)
|
||||
end
|
||||
|
||||
case params[:export_type]
|
||||
when 'qti'
|
||||
export.export_type = ContentExport::QTI
|
||||
export.selected_content = selected_content || { all_quizzes: true }
|
||||
when 'zip'
|
||||
export.export_type = ContentExport::ZIP
|
||||
export.selected_content = selected_content || { all_attachments: true }
|
||||
when 'quizzes2'
|
||||
if params[:quiz_id].nil? || params[:quiz_id] !~ Api::ID_REGEX
|
||||
return render json: { message: 'quiz_id required and must be a valid ID' },
|
||||
status: :bad_request
|
||||
elsif !context.quizzes.exists?(params[:quiz_id])
|
||||
return render json: { message: 'Quiz could not be found' }, status: :bad_request
|
||||
else
|
||||
export.export_type = ContentExport::QUIZZES2
|
||||
# we pass the quiz_id of the quiz we want to clone here
|
||||
export.selected_content = params[:quiz_id]
|
||||
end
|
||||
else
|
||||
export.export_type = ContentExport::COMMON_CARTRIDGE
|
||||
export.selected_content = selected_content || { everything: true }
|
||||
end
|
||||
# recheck, since the export type influences permissions (e.g., students can download zips of non-locked files, but not common cartridges)
|
||||
return unless authorized_action(export, current_user, :create)
|
||||
|
||||
opts = params.permit(:version).to_unsafe_h
|
||||
export.progress = 0
|
||||
if export.save
|
||||
export.queue_api_job(opts)
|
||||
end
|
||||
export
|
||||
end
|
||||
end
|
|
@ -23,8 +23,8 @@ class ContentExport < ActiveRecord::Base
|
|||
belongs_to :attachment
|
||||
belongs_to :content_migration
|
||||
has_many :attachments, :as => :context, :inverse_of => :context, :dependent => :destroy
|
||||
has_many :content_shares
|
||||
has_many :sent_content_shares, -> { where.not(sender_id: nil) }, class_name: 'ContentShare', inverse_of: :content_export
|
||||
has_one :sent_content_share
|
||||
has_many :received_content_shares
|
||||
has_one :epub_export
|
||||
has_a_broadcast_policy
|
||||
serialize :settings
|
||||
|
|
|
@ -20,8 +20,5 @@ class ContentShare < ActiveRecord::Base
|
|||
|
||||
belongs_to :user
|
||||
belongs_to :content_export
|
||||
belongs_to :sender, class_name: 'User', inverse_of: :content_shares
|
||||
has_many :receiver_content_shares, through: :content_export, source: :sent_content_shares
|
||||
has_many :receivers, through: :receiver_content_shares, source: :user
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
#
|
||||
|
||||
class ReceivedContentShare < ContentShare
|
||||
|
||||
belongs_to :sender, class_name: 'User', inverse_of: :received_content_shares
|
||||
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
#
|
||||
|
||||
class SentContentShare < ContentShare
|
||||
|
||||
has_many :received_content_shares, through: :content_export, source: :received_content_shares
|
||||
has_many :receivers, through: :received_content_shares, source: :user
|
||||
|
||||
end
|
|
@ -147,8 +147,8 @@ class User < ActiveRecord::Base
|
|||
has_many :user_generated_media_objects, :class_name => 'MediaObject'
|
||||
has_many :user_notes
|
||||
has_many :content_shares, dependent: :destroy
|
||||
has_many :received_content_shares, -> { where.not(content_shares: {sender: nil}) }, class_name: 'ContentShare', inverse_of: :user
|
||||
has_many :sent_content_shares, -> { where(content_shares: {sender: nil}) }, class_name: 'ContentShare', inverse_of: :user
|
||||
has_many :received_content_shares
|
||||
has_many :sent_content_shares
|
||||
has_many :account_reports, inverse_of: :user
|
||||
has_many :stream_item_instances, :dependent => :delete_all
|
||||
has_many :all_conversations, -> { preload(:conversation) }, class_name: 'ConversationParticipant'
|
||||
|
|
|
@ -2185,6 +2185,10 @@ CanvasRails::Application.routes.draw do
|
|||
delete 'planner_notes/:id', action: :destroy
|
||||
end
|
||||
|
||||
scope(controller: :content_shares) do
|
||||
post 'users/:user_id/content_shares', action: :create
|
||||
end
|
||||
|
||||
scope(:controller => :csp_settings) do
|
||||
%w(course account).each do |context|
|
||||
get "#{context.pluralize}/:#{context}_id/csp_settings", :action => :get_csp_settings
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
#
|
||||
|
||||
class AddTypeToContentShares < ActiveRecord::Migration[5.2]
|
||||
tag :predeploy
|
||||
|
||||
def up
|
||||
add_column :content_shares, :type, :string, limit: 255
|
||||
# there shouldn't be any ContentShares in production, so we shouldn't have to worry
|
||||
# about long jobs
|
||||
ContentShare.where(type: nil, sender_id: nil).update_all(type: 'SentContentShare')
|
||||
ContentShare.where(type: nil).where.not(sender_id: nil).update_all(type: 'ReceivedContentShare')
|
||||
change_column :content_shares, :type, :string, limit: 255, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :content_shares, :type, :string, limit: 255
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
|
||||
module Api::V1::ContentShare
|
||||
include Api::V1::Json
|
||||
include Api::V1::ContentExport
|
||||
|
||||
def content_share_json(content_share, user, session, opts = {})
|
||||
json = api_json(content_share, user, session, opts.merge(only: %w(id name created_at updated_at user_id read_state)))
|
||||
json['sender'] = content_share.respond_to?(:sender) ? user_display_json(content_share.sender) : nil
|
||||
json['receivers'] = content_share.respond_to?(:receivers) ? content_share.receivers.map {|rec| user_display_json(rec)} : []
|
||||
json
|
||||
end
|
||||
end
|
|
@ -0,0 +1,86 @@
|
|||
#
|
||||
# Copyright (C) 2019 - 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/>.
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ContentSharesController do
|
||||
before :once do
|
||||
course_with_teacher(active_all: true)
|
||||
@course_1 = @course
|
||||
@teacher_1 = @teacher
|
||||
course_with_teacher(active_all: true)
|
||||
@course_2 = @course
|
||||
@teacher_2 = @teacher
|
||||
assignment_model(course: @course_1, name: 'assignment share')
|
||||
@course.root_account.enable_feature!(:direct_share)
|
||||
end
|
||||
|
||||
describe "POST #create" do
|
||||
before :each do
|
||||
user_session(@teacher_1)
|
||||
end
|
||||
|
||||
it "returns http success" do
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'assignment', content_id: @assignment.id, receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(SentContentShare.where(user_id: @teacher_1.id)).to exist
|
||||
expect(ReceivedContentShare.where(user_id: @teacher_2.id, sender_id: @teacher_1.id)).to exist
|
||||
expect(ContentExport.where(context: @assignment.context)).to exist
|
||||
json = JSON.parse(response.body)
|
||||
expect(json).to include({
|
||||
"name" => @assignment.title,
|
||||
"user_id" => @teacher_1.id,
|
||||
"read_state" => 'read',
|
||||
"sender" => nil,
|
||||
})
|
||||
expect(json['receivers'].first).to include({'id' => @teacher_2.id})
|
||||
end
|
||||
|
||||
it "returns 400 if required parameters aren't included" do
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'assignment', content_id: @assignment.id}
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'assignment', receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
|
||||
post :create, params: {user_id: @teacher_1.id, content_id: @assignment.id, receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
|
||||
announcement_model(context: @course_1)
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'announcement', content_id: @a.id, receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
end
|
||||
|
||||
it 'returns 400 if the associated content cannot be found' do
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'discussion_topic', content_id: @assignment.id, receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
end
|
||||
|
||||
it "returns 401 if the user doesn't have access to export the associated content" do
|
||||
user_session(@teacher_2)
|
||||
post :create, params: {user_id: @teacher_2.id, content_type: 'assignment', content_id: @assignment.id, receiver_ids: [@teacher_1.id]}
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it "returns 401 if the sharing user doesn't match current user" do
|
||||
user_session(@teacher_2)
|
||||
post :create, params: {user_id: @teacher_1.id, content_type: 'assignment', content_id: @assignment.id, receiver_ids: [@teacher_2.id]}
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -176,7 +176,7 @@ describe Attachments::GarbageCollector do
|
|||
export.attachment = att
|
||||
export.save
|
||||
Attachment.where(id: att.id).update_all(created_at: 1.year.ago)
|
||||
export.content_shares.create!(name: 'content export', read_state: 'read', user: user_model)
|
||||
SentContentShare.create!(name: 'content export', read_state: 'read', user: user_model, content_export: export)
|
||||
|
||||
gc.delete_content
|
||||
expect(att.reload).not_to be_deleted
|
||||
|
|
Loading…
Reference in New Issue