557 lines
24 KiB
Ruby
557 lines
24 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
#
|
|
# 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/>.
|
|
#
|
|
|
|
require File.expand_path(File.dirname(__FILE__) + '/api_spec_helper')
|
|
|
|
shared_examples_for "file uploads api" do
|
|
include ApplicationHelper
|
|
|
|
# send a multipart post request in an integration spec post_params is
|
|
# an array of [k,v] params so that the order of the params can be
|
|
# defined
|
|
def send_multipart(url, post_params = {}, http_headers = {}, method = :post)
|
|
mp = Multipart::Post.new
|
|
query, headers = mp.prepare_query(post_params)
|
|
|
|
# A bug in the testing adapter in Rails 3-2-stable doesn't corretly handle
|
|
# translating this header to the Rack/CGI compatible version:
|
|
# (https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/testing/integration.rb#L289)
|
|
#
|
|
# This issue is fixed in Rails 4-0 stable, by using a newer version of
|
|
# ActionDispatch Http::Headers which correctly handles the merge
|
|
headers = headers.dup.tap { |h| h['CONTENT_TYPE'] ||= h.delete('Content-type') }
|
|
|
|
send(method, url, params: query, headers: headers.merge(http_headers))
|
|
end
|
|
|
|
def attachment_json(attachment, options = {})
|
|
json = {
|
|
'id' => attachment.id,
|
|
'uuid' => attachment.uuid,
|
|
'folder_id' => attachment.folder_id,
|
|
'url' => file_download_url(attachment, :verifier => attachment.uuid, :download => '1', :download_frd => '1'),
|
|
'content-type' => attachment.content_type,
|
|
'display_name' => attachment.display_name,
|
|
'filename' => attachment.filename,
|
|
'upload_status' => "success",
|
|
'size' => attachment.size,
|
|
'unlock_at' => attachment.unlock_at ? attachment.unlock_at.as_json : nil,
|
|
'locked' => !!attachment.locked,
|
|
'hidden' => !!attachment.hidden,
|
|
'lock_at' => attachment.lock_at ? attachment.lock_at.as_json : nil,
|
|
'locked_for_user' => false,
|
|
'hidden_for_user' => false,
|
|
'created_at' => attachment.created_at.as_json,
|
|
'updated_at' => attachment.updated_at.as_json,
|
|
'modified_at' => attachment.modified_at.as_json,
|
|
'thumbnail_url' => attachment.has_thumbnail? ? thumbnail_image_url(attachment, attachment.uuid, host: 'www.example.com') : nil,
|
|
'mime_class' => attachment.mime_class,
|
|
'media_entry_id' => attachment.media_entry_id
|
|
}
|
|
|
|
if options[:include] && options[:include].include?("enhanced_preview_url") && (attachment.context.is_a?(Course) || attachment.context.is_a?(User) || attachment.context.is_a?(Group))
|
|
json['preview_url'] = context_url(attachment.context, :context_file_file_preview_url, attachment, annotate: 0, verifier: attachment.uuid)
|
|
end
|
|
|
|
unless options[:no_doc_preview]
|
|
json.merge!({
|
|
'canvadoc_session_url' => nil,
|
|
'crocodoc_session_url' => nil
|
|
})
|
|
end
|
|
|
|
json
|
|
end
|
|
|
|
it "uploads (local files)" do
|
|
filename = "my_essay.doc"
|
|
content = "this is a test doc"
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
json = preflight({ :name => filename })
|
|
attachment = Attachment.order(:id).last
|
|
exemption_string = has_query_exemption? ? ("?quota_exemption=" + attachment.quota_exemption_key) : ""
|
|
expect(json['upload_url']).to eq "http://www.example.com/files_api#{exemption_string}"
|
|
|
|
# step 2, upload
|
|
tmpfile = Tempfile.new(["test", File.extname(filename)])
|
|
tmpfile.write(content)
|
|
tmpfile.rewind
|
|
post_params = json["upload_params"].merge({ "file" => tmpfile })
|
|
send_multipart(json["upload_url"], post_params)
|
|
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment).to be_deleted
|
|
exemption_string = has_query_exemption? ? ("quota_exemption=" + attachment.quota_exemption_key + "&") : ""
|
|
expect(response).to redirect_to("http://www.example.com/api/v1/files/#{attachment.id}/create_success?#{exemption_string}uuid=#{attachment.uuid}")
|
|
|
|
# step 3, confirmation
|
|
post response['Location'], headers: { 'Authorization' => "Bearer #{access_token_for_user @user}" }
|
|
expect(response).to be_successful
|
|
attachment.reload
|
|
json = json_parse(response.body)
|
|
expected_json = {
|
|
'id' => attachment.id,
|
|
'uuid' => attachment.uuid,
|
|
'folder_id' => attachment.folder_id,
|
|
'url' => file_download_url(attachment, :verifier => attachment.uuid, :download => '1', :download_frd => '1'),
|
|
'content-type' => attachment.content_type,
|
|
'display_name' => attachment.display_name,
|
|
'filename' => attachment.filename,
|
|
'size' => tmpfile.size,
|
|
'unlock_at' => nil,
|
|
'locked' => false,
|
|
'hidden' => false,
|
|
'lock_at' => nil,
|
|
'locked_for_user' => false,
|
|
'hidden_for_user' => false,
|
|
'created_at' => attachment.created_at.as_json,
|
|
'updated_at' => attachment.updated_at.as_json,
|
|
'upload_status' => "success",
|
|
'thumbnail_url' => attachment.has_thumbnail? ? thumbnail_image_url(attachment, attachment.uuid, host: 'www.example.com') : nil,
|
|
'modified_at' => attachment.modified_at.as_json,
|
|
'mime_class' => attachment.mime_class,
|
|
'media_entry_id' => attachment.media_entry_id,
|
|
'canvadoc_session_url' => nil,
|
|
'crocodoc_session_url' => nil
|
|
}
|
|
|
|
if attachment.context.is_a?(User) || attachment.context.is_a?(Course) || attachment.context.is_a?(Group)
|
|
expected_json['preview_url'] = context_url(attachment.context, :context_file_file_preview_url, attachment, annotate: 0, verifier: attachment.uuid)
|
|
end
|
|
|
|
expect(json).to eq(expected_json)
|
|
expect(attachment.file_state).to eq 'available'
|
|
expect(attachment.content_type).to eq "application/msword"
|
|
expect(attachment.open.read).to eq content
|
|
expect(attachment.display_name).to eq filename
|
|
expect(attachment.user.id).to eq @user.id
|
|
attachment
|
|
end
|
|
|
|
it "uploads (s3 files)" do
|
|
filename = "my_essay.doc"
|
|
content = "this is a test doc"
|
|
|
|
s3_storage!
|
|
# step 1, preflight
|
|
json = preflight({ :name => filename })
|
|
expect(json['upload_url']).to eq "https://no-bucket.s3.amazonaws.com"
|
|
attachment = Attachment.order(:id).last
|
|
redir = json['upload_params']['success_action_redirect']
|
|
exemption_string = has_query_exemption? ? ("quota_exemption=" + attachment.quota_exemption_key + "&") : ""
|
|
expect(redir).to eq "http://www.example.com/api/v1/files/#{attachment.id}/create_success?#{exemption_string}uuid=#{attachment.uuid}"
|
|
expect(attachment).to be_deleted
|
|
|
|
# step 2, upload
|
|
# we skip the actual call and double this out, since we can't hit s3 during specs
|
|
expect_any_instance_of(Aws::S3::Object).to receive(:data).and_return({
|
|
:content_type => 'application/msword',
|
|
:content_length => 1234,
|
|
})
|
|
|
|
# step 3, confirmation
|
|
post redir, headers: { 'Authorization' => "Bearer #{access_token_for_user @user}" }
|
|
expect(response).to be_successful
|
|
attachment.reload
|
|
json = json_parse(response.body)
|
|
expect(json).to eq attachment_json(attachment, { include: %w(enhanced_preview_url) })
|
|
|
|
expect(attachment.file_state).to eq 'available'
|
|
expect(attachment.content_type).to eq "application/msword"
|
|
expect(attachment.display_name).to eq filename
|
|
expect(attachment.user.id).to eq @user.id
|
|
attachment
|
|
end
|
|
|
|
it "allows uploading files from a url" do
|
|
filename = "delete.png"
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
json = preflight({ :name => filename, :size => 20, :url => "http://www.example.com/images/delete.png" })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.file_state).to eq 'deleted'
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'queued'
|
|
|
|
expect(CanvasHttp).to receive(:get).with("http://www.example.com/images/delete.png").and_yield(FakeHttpResponse.new(200, "asdf"))
|
|
run_download_job
|
|
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
|
|
expect(json['workflow_state']).to eq('completed')
|
|
expect(json['results']).to be_present
|
|
expect(json['results']['id']).to eq(attachment.id)
|
|
|
|
attachment.reload
|
|
expect(attachment.file_state).to eq 'available'
|
|
expect(attachment.size).to eq 4
|
|
expect(attachment.user.id).to eq @user.id
|
|
end
|
|
|
|
it "fails gracefully with a malformed url" do
|
|
filename = "delete.png"
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
json = preflight({ :name => filename, :size => 20, :url => '#@$YA#Y#AGWREG' })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
run_download_job
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to eq "Could not parse the URL: \#@$YA#Y#AGWREG"
|
|
expect(attachment.reload.file_state).to eq 'errored'
|
|
end
|
|
|
|
it "fails gracefully with a relative url" do
|
|
filename = "delete.png"
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
json = preflight({ :name => filename, :size => 20, :url => '/images/delete.png' })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
run_download_job
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to eq "No host provided for the URL: /images/delete.png"
|
|
expect(attachment.reload.file_state).to eq 'errored'
|
|
end
|
|
|
|
it "fails gracefully with a non-200 and non-300 status return" do
|
|
filename = "delete.png"
|
|
url = 'http://www.example.com/images/delete.png'
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
expect(CanvasHttp).to receive(:get).with(url).and_yield(FakeHttpResponse.new(404))
|
|
json = preflight({ :name => filename, :size => 20, :url => url })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
run_download_job
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to include "Invalid response code, expected 200 got 404"
|
|
expect(attachment.reload.file_state).to eq 'errored'
|
|
end
|
|
|
|
it "fails gracefully with a GET request timeout" do
|
|
filename = "delete.png"
|
|
url = 'http://www.example.com/images/delete.png'
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
expect(CanvasHttp).to receive(:get).with(url).and_raise(Timeout::Error)
|
|
json = preflight({ :name => filename, :size => 20, :url => url })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
run_download_job
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to eq "The request timed out: http://www.example.com/images/delete.png"
|
|
expect(attachment.reload.file_state).to eq 'errored'
|
|
end
|
|
|
|
it "fails gracefully with too many redirects" do
|
|
filename = "delete.png"
|
|
url = 'http://www.example.com/images/delete.png'
|
|
|
|
local_storage!
|
|
# step 1, preflight
|
|
expect(CanvasHttp).to receive(:get).with(url).and_raise(CanvasHttp::TooManyRedirectsError)
|
|
json = preflight({ :name => filename, :size => 20, :url => url })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.workflow_state).to eq 'unattached'
|
|
expect(progress_url).to be_present
|
|
|
|
# step 2, download
|
|
run_download_job
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to include "Too many redirects"
|
|
expect(attachment.reload.file_state).to eq 'errored'
|
|
end
|
|
|
|
def run_download_job
|
|
expect(Delayed::Job.where("tag like '#{Services::SubmitHomeworkService}::%'").count).to be > 0
|
|
run_jobs
|
|
end
|
|
end
|
|
|
|
shared_examples_for "file uploads api with folders" do
|
|
include_examples "file uploads api"
|
|
|
|
it "allows specifying a folder with deprecated argument name" do
|
|
preflight({ :name => "with_path.txt", :folder => "files/a/b/c/mypath" })
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.folder).to eq Folder.assert_path("/files/a/b/c/mypath", context)
|
|
end
|
|
|
|
it "allows specifying a folder" do
|
|
preflight({ :name => "with_path.txt", :parent_folder_path => "files/a/b/c/mypath" })
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.folder).to eq Folder.assert_path("/files/a/b/c/mypath", context)
|
|
end
|
|
|
|
it "allows specifying a parent folder by id" do
|
|
root = Folder.root_folders(context).first
|
|
sub = root.sub_folders.create!(:name => "folder1", :context => context)
|
|
preflight({ :name => "with_path.txt", :parent_folder_id => sub.id.to_param })
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.folder_id).to eq sub.id
|
|
end
|
|
|
|
it "uploads to an existing folder" do
|
|
@folder = Folder.assert_path("/files/a/b/c/mypath", context)
|
|
expect(@folder).to be_present
|
|
expect(@folder).to be_visible
|
|
preflight({ :name => "my_essay.doc", :folder => "files/a/b/c/mypath" })
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.folder).to eq @folder
|
|
end
|
|
|
|
it "overwrites duplicate files by default" do
|
|
local_storage!
|
|
@folder = Folder.assert_path("test", context)
|
|
a1 = Attachment.create!(:folder => @folder, :context => context, :filename => "test.txt", :uploaded_data => StringIO.new("first"))
|
|
json = preflight({ :name => "test.txt", :folder => "test" })
|
|
|
|
tmpfile = Tempfile.new(["test", ".txt"])
|
|
tmpfile.write("second")
|
|
tmpfile.rewind
|
|
post_params = json["upload_params"].merge({ "file" => tmpfile })
|
|
send_multipart(json["upload_url"], post_params)
|
|
post response['Location'], headers: { 'Authorization' => "Bearer #{access_token_for_user @user}" }
|
|
expect(response).to be_successful
|
|
attachment = Attachment.order(:id).last
|
|
expect(a1.reload).to be_deleted
|
|
expect(attachment.reload).to be_available
|
|
expect(attachment.display_name).to eq "test.txt"
|
|
expect(attachment.folder).to eq @folder
|
|
expect(attachment.open.read).to eq "second"
|
|
end
|
|
|
|
it "overwrites duplicate files by default for URL uploads" do
|
|
local_storage!
|
|
@folder = Folder.assert_path("test", context)
|
|
a1 = Attachment.create!(:folder => @folder, :context => context, :filename => "test.txt", :uploaded_data => StringIO.new("first"))
|
|
json = preflight({ :name => "test.txt", :folder => "test", :url => "http://www.example.com/test" })
|
|
attachment = Attachment.order(:id).last
|
|
expect(CanvasHttp).to receive(:get).with("http://www.example.com/test").and_yield(FakeHttpResponse.new(200, "second"))
|
|
run_jobs
|
|
|
|
expect(a1.reload).to be_deleted
|
|
expect(attachment.reload).to be_available
|
|
expect(attachment.display_name).to eq "test.txt"
|
|
expect(attachment.folder).to eq @folder
|
|
expect(attachment.open.read).to eq "second"
|
|
end
|
|
|
|
it "allows renaming instead of overwriting duplicate files (local storage)" do
|
|
local_storage!
|
|
@folder = Folder.assert_path("test", context)
|
|
a1 = Attachment.create!(:folder => @folder, :context => context, :filename => "test.txt", :uploaded_data => StringIO.new("first"))
|
|
json = preflight({ :name => "test.txt", :folder => "test", :on_duplicate => 'rename' })
|
|
|
|
tmpfile = Tempfile.new(["test", ".txt"])
|
|
tmpfile.write("second")
|
|
tmpfile.rewind
|
|
post_params = json["upload_params"].merge({ "file" => tmpfile })
|
|
send_multipart(json["upload_url"], post_params)
|
|
post response['Location'], headers: { 'Authorization' => "Bearer #{access_token_for_user @user}" }
|
|
expect(response).to be_successful
|
|
attachment = Attachment.order(:id).last
|
|
expect(a1.reload).to be_available
|
|
expect(attachment.reload).to be_available
|
|
expect(a1.display_name).to eq "test.txt"
|
|
expect(attachment.display_name).to eq "test-1.txt"
|
|
expect(attachment.folder).to eq @folder
|
|
end
|
|
|
|
it "allows renaming instead of overwriting duplicate files for URL uploads" do
|
|
local_storage!
|
|
@folder = Folder.assert_path("test", context)
|
|
a1 = Attachment.create!(:folder => @folder, :context => context, :filename => "test.txt", :uploaded_data => StringIO.new("first"))
|
|
json = preflight({ :name => "test.txt", :folder => "test", :on_duplicate => 'rename', :url => "http://www.example.com/test" })
|
|
attachment = Attachment.order(:id).last
|
|
expect(CanvasHttp).to receive(:get).with("http://www.example.com/test").and_yield(FakeHttpResponse.new(200, "second"))
|
|
run_jobs
|
|
|
|
expect(a1.reload).to be_available
|
|
expect(attachment.reload).to be_available
|
|
expect(a1.display_name).to eq "test.txt"
|
|
expect(attachment.display_name).to eq "test-1.txt"
|
|
expect(attachment.folder).to eq @folder
|
|
end
|
|
|
|
it "allows renaming instead of overwriting duplicate files (s3 storage)" do
|
|
@folder = Folder.assert_path("test", context)
|
|
a1 = Attachment.create!(:folder => @folder, :context => context, :filename => "test.txt", :uploaded_data => StringIO.new("first"))
|
|
s3_storage!
|
|
json = preflight({ :name => "test.txt", :folder => "test", :on_duplicate => 'rename' })
|
|
|
|
redir = json['upload_params']['success_action_redirect']
|
|
attachment = Attachment.order(:id).last
|
|
expect_any_instance_of(Aws::S3::Object).to receive(:data).and_return({
|
|
:content_type => 'application/msword',
|
|
:content_length => 1234,
|
|
})
|
|
|
|
post redir, headers: { 'Authorization' => "Bearer #{access_token_for_user @user}" }
|
|
expect(response).to be_successful
|
|
expect(a1.reload).to be_available
|
|
expect(attachment.reload).to be_available
|
|
expect(attachment.display_name).to eq "test-1.txt"
|
|
end
|
|
|
|
it "rejects other duplicate file handling params" do
|
|
json = preflight({ :name => "test.txt", :folder => "test", :on_duplicate => 'killall' }, { expected_status: 400 })
|
|
expect(json['message']).to eq "invalid on_duplicate option"
|
|
end
|
|
end
|
|
|
|
shared_examples_for "file uploads api with quotas" do
|
|
before do
|
|
local_storage!
|
|
end
|
|
|
|
it "returns successful preflight for files within quota limits" do
|
|
@context.write_attribute(:storage_quota, 5.megabytes)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :size => 3.megabytes })
|
|
attachment = Attachment.order(:id).last
|
|
expect(attachment.workflow_state).to eq 'unattached'
|
|
expect(attachment.filename).to eq 'test.txt'
|
|
end
|
|
|
|
it "returns unsuccessful preflight for files exceeding quota limits" do
|
|
@context.write_attribute(:storage_quota, 5.megabytes)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :size => 10.megabytes }, expected_status: 400)
|
|
expect(json['message']).to eq "file size exceeds quota"
|
|
end
|
|
|
|
it "returns unsuccessful preflight for files exceeding quota limits (URL uploads)" do
|
|
@context.write_attribute(:storage_quota, 5.megabytes)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :size => 10.megabytes, :url => "http://www.example.com/test" },
|
|
expected_status: 400)
|
|
expect(json['message']).to eq "file size exceeds quota"
|
|
end
|
|
|
|
it "returns successful create_success for files within quota" do
|
|
@context.write_attribute(:storage_quota, 5.megabytes)
|
|
@context.save!
|
|
attachment = @context.attachments.new
|
|
attachment.filename = "smaller_file.txt"
|
|
attachment.file_state = 'deleted'
|
|
attachment.workflow_state = 'unattached'
|
|
attachment.content_type = 'text/plain'
|
|
attachment.size = 4.megabytes
|
|
attachment.save!
|
|
json = api_call(:get, "/api/v1/files/#{attachment.id}/create_success", { :id => attachment.id.to_s, :controller => 'files', :action => 'api_create_success', :format => 'json' }, { :uuid => attachment.uuid })
|
|
expect(json['id']).to eq attachment.id
|
|
attachment.reload
|
|
expect(attachment.file_state).to eq 'available'
|
|
end
|
|
|
|
it "returns unsuccessful create_success for files exceeding quota limits" do
|
|
@context.write_attribute(:storage_quota, 5.megabytes)
|
|
@context.save!
|
|
attachment = @context.attachments.new
|
|
attachment.filename = "bigger_file.txt"
|
|
attachment.file_state = 'deleted'
|
|
attachment.workflow_state = 'unattached'
|
|
attachment.content_type = 'text/plain'
|
|
attachment.size = 6.megabytes
|
|
attachment.save!
|
|
json = api_call(:get, "/api/v1/files/#{attachment.id}/create_success",
|
|
{ :id => attachment.id.to_s, :controller => 'files', :action => 'api_create_success', :format => 'json' },
|
|
{ :uuid => attachment.uuid },
|
|
{},
|
|
expected_status: 400)
|
|
expect(json['message']).to eq 'file size exceeds quota limits'
|
|
attachment.reload
|
|
expect(attachment.file_state).to eq 'deleted'
|
|
end
|
|
|
|
it "fails URL uploads for files exceeding quota limits" do
|
|
@context.write_attribute(:storage_quota, 1.megabyte)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :url => "http://www.example.com/test" })
|
|
progress_url = json['progress']['url']
|
|
progress_id = json['progress']['id']
|
|
attachment = Attachment.order(:id).last
|
|
expect(CanvasHttp).to receive(:get).with("http://www.example.com/test").and_yield(FakeHttpResponse.new(200, (" " * 2.megabytes)))
|
|
run_jobs
|
|
|
|
json = api_call(:get, progress_url, { :id => progress_id, :controller => 'progress', :action => 'show', :format => 'json' })
|
|
expect(json['workflow_state']).to eq 'failed'
|
|
expect(json['message']).to eq "file size exceeds quota limits: #{ActiveSupport::NumberHelper.number_to_delimited(2.megabytes)} bytes"
|
|
expect(attachment.file_state).to eq 'deleted'
|
|
end
|
|
end
|
|
|
|
shared_examples_for "file uploads api without quotas" do
|
|
it "ignores context-related quotas in preflight" do
|
|
local_storage!
|
|
|
|
@context.write_attribute(:storage_quota, 0)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :size => 1.megabyte })
|
|
attachment = Attachment.order(:id).last
|
|
expect(json['upload_url']).to match(/#{attachment.quota_exemption_key}/)
|
|
end
|
|
it "ignores context-related quotas in preflight" do
|
|
s3_storage!
|
|
@context.write_attribute(:storage_quota, 0)
|
|
@context.save!
|
|
json = preflight({ :name => "test.txt", :size => 1.megabyte })
|
|
attachment = Attachment.order(:id).last
|
|
expect(json['upload_params']['success_action_redirect']).to match(/#{attachment.quota_exemption_key}/)
|
|
end
|
|
end
|