diff --git a/app/controllers/folders_controller.rb b/app/controllers/folders_controller.rb index 01d54052f59..89bf4ec4642 100644 --- a/app/controllers/folders_controller.rb +++ b/app/controllers/folders_controller.rb @@ -35,7 +35,7 @@ class FoldersController < ApplicationController else @folder.visible_file_attachments end - files_options = {:permissions => {:user => @current_user}, :methods => [:currently_locked, :mime_class, :readable_size, :scribdable?], :only => [:id, :comments, :content_type, :context_id, :context_type, :display_name, :folder_id, :position, :media_entry_id, :scribd_doc]} + files_options = {:permissions => {:user => @current_user}, :methods => [:currently_locked, :mime_class, :readable_size, :scribdable?], :only => [:id, :comments, :content_type, :context_id, :context_type, :display_name, :folder_id, :position, :media_entry_id, :scribd_doc, :filename]} folders_options = {:permissions => {:user => @current_user}, :methods => [:currently_locked, :mime_class], :only => [:id, :context_id, :context_type, :lock_at, :last_lock_at, :last_unlock_at, :name, :parent_folder_id, :position, :unlock_at]} res = { :actual_folder => @folder.as_json(folders_options), diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 19c887ce65d..395a01586a5 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -462,11 +462,17 @@ class Attachment < ActiveRecord::Base def self.file_store_config # Return existing value, even if nil, as long as it's defined @file_store_config ||= YAML.load_file(RAILS_ROOT + "/config/file_store.yml")[RAILS_ENV] rescue nil - @file_store_config ||= {'path_prefix' => 'tmp/files', 'storage' => 'local'} + @file_store_config ||= {'storage' => 'local'} + @file_store_config['path_prefix'] ||= @file_store_config['path'] || 'tmp/files' + if RAILS_ENV == "test" + file_storage_test_override = Setting.get("file_storage_test_override", nil) + return @file_store_config.merge({"storage" => file_storage_test_override}) if file_storage_test_override + end + return @file_store_config end def self.s3_storage? - (RAILS_ENV == "test" && Setting.get("file_storage_test_override", nil) || file_store_config['storage'] rescue nil) == 's3' && s3_config + (file_store_config['storage'] rescue nil) == 's3' && s3_config end def self.local_storage? @@ -487,7 +493,7 @@ class Attachment < ActiveRecord::Base # too, it cares about local vs s3 storage. if local_storage? has_attachment( - :path_prefix => (file_store_config['path_prefix'] || 'tmp/files'), + :path_prefix => file_store_config['path_prefix'], :thumbnails => { :thumb => '200x50' }, :thumbnail_class => 'Thumbnail' ) diff --git a/lib/multipart.rb b/lib/multipart.rb index 4bbc90b3239..e877c4a85c0 100644 --- a/lib/multipart.rb +++ b/lib/multipart.rb @@ -45,7 +45,7 @@ module Multipart BOUNDARY = AutoHandle.generate('canvas-rules', 15) HEADER = {"Content-type" => "multipart/form-data, boundary=" + BOUNDARY + " "} - def prepare_query (params) + def prepare_query (params, field_priority=[]) fp = [] creds = params.delete :basic_auth if creds @@ -54,13 +54,22 @@ module Multipart puts creds[:password] puts Base64.encode64("#{creds[:username]}:#{creds[:password]}") end - params.each {|k,v| - if v.respond_to?(:read) - fp.push(FileParam.new(k, v.path, v.read)) + def file_param(k, v) + file_data = v.read rescue nil + if file_data + FileParam.new(k, v.path, file_data) else - fp.push(Param.new(k,v)) + Param.new(k,v) end - } + end + completed_fields = {} + field_priority.each do |k| + if params.has_key?(k) && !completed_fields.has_key?(k) + fp.push(file_param(k, params[k])) + completed_fields[k] = true + end + end + params.each {|k,v| fp.push(file_param(k, v)) unless completed_fields.has_key?(k) } query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--" return query, HEADER end diff --git a/lib/ssl_common.rb b/lib/ssl_common.rb index 9b8b3f42103..162af874dbb 100644 --- a/lib/ssl_common.rb +++ b/lib/ssl_common.rb @@ -20,7 +20,7 @@ require 'net/https' class SSLCommon SSL_CA_PATH = "/etc/ssl/certs/" - + class << self def get_http_conn(host, port, ssl) http = Net::HTTP.new(host, port) @@ -29,24 +29,34 @@ class SSLCommon http.ca_path = SSL_CA_PATH http.verify_mode = OpenSSL::SSL::VERIFY_PEER end - http + http end - - def post_form(url, form_data) + + def raw_post(url, payload, headers = {}, form_data = nil) url = URI.parse(url) http = self.get_http_conn(url.host, url.port, url.scheme.downcase == 'https') - req = Net::HTTP::Post.new(url.path) - req.form_data = form_data - http.start {|http| http.request(req) } + req = Net::HTTP::Post.new(url.request_uri, headers) + req.form_data = form_data if form_data + http.start {|http| http.request(req, payload) } end - - def post_data(url, data, content_type) + + def get(url, headers={}) url = URI.parse(url) http = self.get_http_conn(url.host, url.port, url.scheme.downcase == 'https') - req = Net::HTTP::Post.new(url.path) - req['Content-Type'] = content_type - http.start {|http| http.request(req, data) } + http.get(url.request_uri, headers) + end + + def post_form(url, form_data, headers={}) + self.raw_post(url, nil, headers, form_data) + end + + def post_multipart_form(url, form_data, headers={}, field_priority=[]) + payload, mp_headers = Multipart::MultipartPost.new.prepare_query(form_data, field_priority) + self.raw_post(url, payload, mp_headers.merge(headers)) + end + + def post_data(url, data, content_type, headers={}) + self.raw_post(url, data, {"Content-Type" => content_type}.merge(headers)) end end end - diff --git a/public/javascripts/full_files.js b/public/javascripts/full_files.js index a8cedbc3363..93a81a3775f 100644 --- a/public/javascripts/full_files.js +++ b/public/javascripts/full_files.js @@ -1672,7 +1672,7 @@ var fileStructureData = []; var url = $item.find(".download_url").attr('href'); var display_name = $item.find(".name:first").text(); var $dialog = $("#edit_content_dialog"); - $dialog.data('update_url', $item.find(".rename_item_link").attr('href')).data('content_type', data.content_type || '').data('filename', data.filename || ''); + $dialog.data('update_url', $item.find(".rename_item_link").attr('href')).data('content_type', data.content_type || '').data('filename', data.filename || 'file_to_update'); $dialog.find(".display_name").text(display_name); $dialog.find(".loading_message").text("Loading File Contents...").show().end() .find(".content").hide(); diff --git a/spec/fixtures/files/html-editing-test.html b/spec/fixtures/files/html-editing-test.html new file mode 100644 index 00000000000..75abe122db4 --- /dev/null +++ b/spec/fixtures/files/html-editing-test.html @@ -0,0 +1,3 @@ + +test12 + diff --git a/spec/selenium/files_sel.rb b/spec/selenium/files_sel.rb index 3b459728ef6..295f34e951a 100644 --- a/spec/selenium/files_sel.rb +++ b/spec/selenium/files_sel.rb @@ -1,13 +1,114 @@ require File.expand_path(File.dirname(__FILE__) + '/common') -describe "files view" do - it_should_behave_like "in-process server selenium tests" +shared_examples_for "files selenium tests" do + it_should_behave_like "forked server selenium tests" + + def fixture_file_path(file) + path = ActionController::TestCase.respond_to?(:fixture_path) ? ActionController::TestCase.send(:fixture_path) : nil + return "#{path}#{file}" + end + + def fixture_file_upload(file, mimetype) + ActionController::TestUploadedFile.new(fixture_file_path(file), mimetype) + end + + def login(username, password) + resp, body = SSLCommon.get "#{app_host}/login" + resp.code.should == "200" + @cookie = resp.response['set-cookie'] + resp, body = SSLCommon.post_form("#{app_host}/login", { + "pseudonym_session[unique_id]" => username, + "pseudonym_session[password]" => password, + "redirect_to_ssl" => "0", + "pseudonym_session[remember_me]" => "0" }, + { "Cookie" => @cookie }) + resp.code.should == "302" + @cookie = resp.response['set-cookie'] + login_as username, password + end + + def add_file(fixture, course, name) + resp, body = SSLCommon.get "#{app_host}/courses/#{course.id}/files", + "Cookie" => @cookie + resp.code.should == "200" + body.should =~ /
([^<]*)<\/div>/ + authenticity_token = $1 + resp, body = SSLCommon.post_form("#{app_host}/files/pending", { + "attachment[folder_id]" => course.folders.active.first.id, + "attachment[filename]" => name, + "attachment[context_code]" => "Course_#{course.id}", + "authenticity_token" => authenticity_token, + "no_redirect" => true}, { "Cookie" => @cookie }) + resp.code.should == "200" + data = ActiveSupport::JSON.decode(body) + data["upload_url"] = data["proxied_upload_url"] || data["upload_url"] + data["upload_url"] = "#{app_host}#{data["upload_url"]}" if data["upload_url"] =~ /^\// + data["success_url"] = "#{app_host}#{data["success_url"]}" if data["success_url"] =~ /^\// + data["upload_params"]["file"] = fixture + resp, body = SSLCommon.post_multipart_form(data["upload_url"], data["upload_params"], { "Cookie" => @cookie }, ["bucket", "key", "acl"]) + resp.code.should =~ /^20/ + if body =~ // + resp, body = SSLCommon.get data["success_url"] + resp.code.should == "200" + end + end it "should show students link to download zip of folder" do - course_with_student_logged_in + user_with_pseudonym :username => "nobody3@example.com", + :password => "asdfasdf3" + course_with_student_logged_in :user => @user + login_as "nobody3@example.com", "asdfasdf3" get "/courses/#{@course.id}/files" link = keep_trying_until { driver.find_element(:css, "div.links a.download_zip_link") } link.should be_displayed link.attribute('href').should match(%r"/courses/#{@course.id}/folders/\d+/download") end + + it "should allow you to edit html files" do + user_with_pseudonym :username => "nobody2@example.com", + :password => "asdfasdf2" + course_with_teacher_logged_in :user => @user + login "nobody2@example.com", "asdfasdf2" + add_file(fixture_file_upload('files/html-editing-test.html', 'text/html'), + @course, "html-editing-test.html") + get "/courses/#{@course.id}/files" + link = keep_trying_until { driver.find_element(:css, "li.editable_folder_item div.header a.download_url") } + link.should be_displayed + link.text.should == "html-editing-test.html" + current_content = File.read(fixture_file_path("files/html-editing-test.html")) + 4.times do + get "/courses/#{@course.id}/files" + new_content = "#{ActiveSupport::SecureRandom.hex(10)}" + link = keep_trying_until { driver.find_element(:css, "li.editable_folder_item div.header a.edit_item_content_link") } + link.should be_displayed + link.text.should == "edit content" + link.click + keep_trying_until { driver.find_element(:css, "#edit_content_dialog").displayed?} + keep_trying_until { driver.execute_script("return $('#edit_content_textarea')[0].value;") == current_content } + driver.execute_script("$('#edit_content_textarea')[0].value = '#{new_content}';") + current_content = new_content + driver.find_element(:css, "#edit_content_dialog button.save_button").click + keep_trying_until { !driver.find_element(:css, "#edit_content_dialog").displayed?} + end + end +end + +describe "files Windows-Firefox-Local-Tests" do + it_should_behave_like "files selenium tests" + prepend_before(:each) { + Setting.set("file_storage_test_override", "local") + } + prepend_before(:all) { + Setting.set("file_storage_test_override", "local") + } +end + +describe "files Windows-Firefox-S3-Tests" do + it_should_behave_like "files selenium tests" + prepend_before(:each) { + Setting.set("file_storage_test_override", "s3") + } + prepend_before(:all) { + Setting.set("file_storage_test_override", "s3") + } end