From 8bdee631f641607ac0bcd390d32b80fea2ff1cf9 Mon Sep 17 00:00:00 2001 From: Alexey Verkhovsky Date: Sun, 13 Nov 2005 13:37:47 +0000 Subject: [PATCH] [BREAKS BUILD] Some work on File uploads, half-done, committing as a backup --- app/controllers/application.rb | 8 +- app/controllers/file_controller.rb | 56 +++----- app/models/web.rb | 35 ++++- app/models/wiki.rb | 4 - app/models/wiki_file.rb | 57 ++++++++ config/routes.rb | 3 +- db/schema.rb | 20 ++- lib/file_yard.rb | 59 -------- test/functional/file_controller_test.rb | 176 ++++++++++++------------ test/functional/routes_test.rb | 4 +- test/unit/file_yard_test.rb | 70 ---------- test/unit/page_renderer_test.rb | 9 +- test/unit/wiki_file_test.rb | 84 +++++++++++ 13 files changed, 308 insertions(+), 277 deletions(-) create mode 100644 app/models/wiki_file.rb delete mode 100644 lib/file_yard.rb delete mode 100755 test/unit/file_yard_test.rb create mode 100644 test/unit/wiki_file_test.rb diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 6fc309b7..362558fe 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -32,7 +32,7 @@ class ApplicationController < ActionController::Base @web_name = @params['web'] @wiki = wiki if @web_name - @web = @wiki.webs[@web_name] + @web = @wiki.webs[@web_name] if @web.nil? render :status => 404, :text => "Unknown web '#{@web_name}'" return false @@ -53,8 +53,12 @@ class ApplicationController < ActionController::Base '.zip' => 'application/zip' } unless defined? FILE_TYPES + def content_type_header(file) + FILE_TYPES[File.extname(file)] || 'application/octet-stream' + end + def send_file(file, options = {}) - options[:type] ||= (FILE_TYPES[File.extname(file)] || 'application/octet-stream') + options[:type] = content_type_header(file) options[:stream] = false super(file, options) end diff --git a/app/controllers/file_controller.rb b/app/controllers/file_controller.rb index 61e5f000..fdf3b8ae 100644 --- a/app/controllers/file_controller.rb +++ b/app/controllers/file_controller.rb @@ -7,41 +7,32 @@ class FileController < ApplicationController before_filter :check_allow_uploads def file - check_path if @params['file'] # form supplied - file_yard.upload_file(@file_name, @params['file']) - flash[:info] = "File '#{@file_name}' successfully uploaded" - return_to_last_remembered - elsif file_yard.has_file?(@file_name) - send_file(file_yard.file_path(@file_name)) - else - logger.debug("File not found: #{file_yard.files_path}/#{@file_name}") - # go to the template, which is a file upload form + new_file = upload_file(@file_name, @params['file']) + if new_file.valid? + flash[:info] = "File '#{@file_name}' successfully uploaded" + return_to_last_remembered + else + # FIXME handle validation errors more gracefully + flash[:errors] = new_file.errors.to_s + end + else + # no form supplied, this is a request to download the file + file = WikiFile.find_by_file_name(@file_name) + if file + send_data(file.content, :filename => @file_name, :type => content_type_header(@file_name)) + end end + # if it's neither a supplied form for upload, nor a request for a known file, + # display the file/file.rhtml template (which happens to be an upload form) end def cancel_upload return_to_last_remembered end - def pic - check_path - if @params['file'] - # form supplied - file_yard.upload_file(@file_name, @params['file']) - flash[:info] = "Image '#{@file_name}' successfully uploaded" - return_to_last_remembered - elsif file_yard.has_file?(@file_name) - send_file(file_yard.file_path(@file_name)) - else - logger.debug("Image not found: #{file_yard.files_path}/#{@file_name}") - render_action 'file' - end - end - def import - check_authorization if @params['file'] @problems = [] import_file_name = "#{@web.address}-import-#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}.zip" @@ -62,25 +53,16 @@ class FileController < ApplicationController protected def check_allow_uploads - unless @web.allow_uploads? + if @web.allow_uploads? + return true + else render :status => 403, :text => 'File uploads are blocked by the webmaster' return false end end - private - def check_path - raise Instiki::ValidationError.new("Invalid path: no file name") unless @file_name - raise Instiki::ValidationError.new("Invalid path: no web name") unless @web_name - raise Instiki::ValidationError.new("Invalid path: unknown web name") unless @web - end - - def file_yard - @wiki.file_yard(@web) - end - def import_from_archive(archive) logger.info "Importing pages from #{archive}" zip = Zip::ZipInputStream.open(archive) diff --git a/app/models/web.rb b/app/models/web.rb index a53fc25b..1ca17a9e 100644 --- a/app/models/web.rb +++ b/app/models/web.rb @@ -1,5 +1,6 @@ class Web < ActiveRecord::Base has_many :pages + has_many :wiki_files def wiki Wiki.new @@ -40,8 +41,8 @@ class Web < ActiveRecord::Base Page.count(['web_id = ? AND name = ?', id, name]) > 0 end - def has_file?(name) - wiki.file_yard(self).has_file?(name) + def has_file?(file_name) + WikiFile.find_by_file_name(file_name) != nil end def markup @@ -97,6 +98,7 @@ class Web < ActiveRecord::Base protected before_save :sanitize_markup + after_save :create_files_directory before_validation :validate_address validates_uniqueness_of :address validates_length_of :color, :in => 3..6 @@ -111,4 +113,33 @@ class Web < ActiveRecord::Base raise Instiki::ValidationError.new("#{self.class.human_attribute_name('address')} #{errors.on(:address)}") end end + + def create_files_directory + return unless allow_uploads == 1 + dummy_file = self.wiki_files.build(:file_name => '0', :description => '0', :content => '0') + dir = File.dirname(dummy_file.content_path) + begin + require 'fileutils' + FileUtils.mkdir_p dir + dummy_file.save + dummy_file.destroy + rescue => e + logger.error("Failed create files directory for #{self.address}: #{e}") + raise "Instiki could not create directory to store uploaded files. " + + "Please make sure that Instiki is allowed to create directory " + + "#{File.expand_path(dir)} and add files to it." + end + end + + def default_web? + defined? DEFAULT_WEB and self.address == DEFAULT_WEB + end + + def files_path + if default_web? + "#{RAILS_ROOT}/public/#{self.address}/files" + else + "#{RAILS_ROOT}/public/files" + end + end end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index e0da8644..1e7f8d17 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -21,10 +21,6 @@ class Wiki end end - def file_yard(web) - web.file_yard - end - def edit_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false, password = nil, published = false, brackets_only = false, count_pages = false, allow_uploads = true, max_upload_size = nil) diff --git a/app/models/wiki_file.rb b/app/models/wiki_file.rb new file mode 100644 index 00000000..89b166c0 --- /dev/null +++ b/app/models/wiki_file.rb @@ -0,0 +1,57 @@ +class WikiFile < ActiveRecord::Base + belongs_to :web + + before_save :write_content_to_file + before_destroy :delete_content_file + + validates_presence_of %w( web file_name description ) + validates_length_of :file_name, :within=>1..50 + validates_length_of :description, :within=>1..255 + + def self.find_by_file_name(file_name) + find(:first, :conditions => ['file_name = ?', file_name]) + end + + SANE_FILE_NAME = /^[a-zA-Z0-9\-_\. ]*$/ + def validate + if file_name + if file_name !~ SANE_FILE_NAME + errors.add("file_name", "is invalid. Only latin characters, digits, dots, underscores, " + + "dashes and spaces are accepted") + elsif file_name == '.' or file_name == '..' + errors.add("file_name", "cannot be '.' or '..'") + end + end + + if @web and @content + if (@content.size > @web.max_upload_size.kilobytes) + errors.add("content", "size (#{(@content.size / 1024.0).round} kilobytes) exceeds " + + "the maximum (#{web.max_upload_size} kilobytes) set for this wiki") + end + end + + errors.add("content", "is empty") if @content.nil? or @content.empty? + end + + def content=(content) + @content = content + end + + def content + @content ||= ( File.open(content_path, 'rb') { |f| f.read } ) + end + + def content_path + web.files_path + '/' + file_name + end + + def write_content_to_file + File.open(self.content_path, 'wb') { |f| f.write(@content) } + end + + def delete_content_file + require 'fileutils' + FileUtils.rm_f(content_path) if File.exists?(content_path) + end + +end diff --git a/config/routes.rb b/config/routes.rb index 59a8c442..74532f2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,8 +15,7 @@ ActionController::Routing::Routes.draw do |map| map.connect 'web_list', :controller => 'wiki', :action => 'web_list' connect_to_web map, ':web/edit_web', :controller => 'admin', :action => 'edit_web' - connect_to_web map, ':web/file/:id', :controller => 'file', :action => 'file' - connect_to_web map, ':web/pic/:id', :controller => 'file', :action => 'pic' + connect_to_web map, ':web/files/:id', :controller => 'file', :action => 'file' connect_to_web map, ':web/import/:id', :controller => 'file', :action => 'import' connect_to_web map, ':web/login', :controller => 'wiki', :action => 'login' connect_to_web map, ':web/web_list', :controller => 'wiki', :action => 'web_list' diff --git a/db/schema.rb b/db/schema.rb index 48b0cbdf..43d08471 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -22,9 +22,10 @@ ActiveRecord::Schema.define() do t.column "author", :string, :limit => 60 t.column "ip", :string, :limit => 60 end - add_index "revisions", ["page_id"] - add_index "revisions", ["created_at"] - add_index "revisions", ["author"] + + add_index "revisions", ["page_id"], :name => "revisions_page_id_index" + add_index "revisions", ["created_at"], :name => "revisions_created_at_index" + add_index "revisions", ["author"], :name => "revisions_author_index" create_table "sessions", :force => true do |t| t.column "session_id", :string @@ -55,6 +56,14 @@ ActiveRecord::Schema.define() do t.column "brackets_only", :integer, :default => 0 end + create_table "wiki_files", :force => true do |t| + t.column "created_at", :datetime, :null => false + t.column "updated_at", :datetime, :null => false + t.column "web_id", :integer, :null => false + t.column "file_name", :string, :null => false + t.column "description", :string, :null => false + end + create_table "wiki_references", :force => true do |t| t.column "created_at", :datetime, :null => false t.column "updated_at", :datetime, :null => false @@ -62,7 +71,8 @@ ActiveRecord::Schema.define() do t.column "referenced_name", :string, :limit => 60, :null => false t.column "link_type", :string, :limit => 1, :null => false end - add_index "wiki_references", ["page_id"] - add_index "wiki_references", ["referenced_name"] + + add_index "wiki_references", ["page_id"], :name => "wiki_references_page_id_index" + add_index "wiki_references", ["referenced_name"], :name => "wiki_references_referenced_name_index" end diff --git a/lib/file_yard.rb b/lib/file_yard.rb deleted file mode 100644 index 1654c90e..00000000 --- a/lib/file_yard.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'fileutils' -require 'instiki_errors' - -class FileYard - cattr_accessor :restrict_upload_access - restrict_upload_access = true - attr_reader :files_path - - def initialize(files_path, max_upload_size) - @files_path, @max_upload_size = files_path, max_upload_size - FileUtils.mkdir_p(@files_path) unless File.exist?(@files_path) - @files = Dir["#{@files_path}/*"].collect{|path| File.basename(path) if File.file?(path) }.compact - end - - def upload_file(name, io) - sanitize_file_name(name) - if io.kind_of?(Tempfile) - io.close - check_upload_size(io.size) - File.chmod(0600, file_path(name)) if File.exists? file_path(name) - FileUtils.mv(io.path, file_path(name)) - else - content = io.read - check_upload_size(content.length) - File.open(file_path(name), 'wb') { |f| f.write(content) } - end - # just in case, restrict read access and prohibit write access to the uploaded file - FileUtils.chmod(0440, file_path(name)) if restrict_upload_access - end - - def files - Dir["#{files_path}/*"].collect{|path| File.basename(path) if File.file?(path)}.compact - end - - def has_file?(name) - files.include?(name) - end - - def file_path(name) - "#{files_path}/#{name}" - end - - SANE_FILE_NAME = /[a-zA-Z0-9\-_\. ]{1,255}/ - - def sanitize_file_name(name) - unless name =~ SANE_FILE_NAME or name == '.' or name == '..' - raise Instiki::ValidationError.new("Invalid file name: '#{name}'.\n" + - "Only latin characters, digits, dots, underscores, dashes and spaces are accepted.") - end - end - - def check_upload_size(actual_upload_size) - if actual_upload_size > @max_upload_size.kilobytes - raise Instiki::ValidationError.new("Uploaded file size (#{actual_upload_size / 1024} " + - "kbytes) exceeds the maximum (#{@max_upload_size} kbytes) set for this wiki") - end - end - -end diff --git a/test/functional/file_controller_test.rb b/test/functional/file_controller_test.rb index 80b9099e..b18862c0 100755 --- a/test/functional/file_controller_test.rb +++ b/test/functional/file_controller_test.rb @@ -11,41 +11,38 @@ class FileController; def rescue_action(e) logger.error(e); raise e end; end class FileControllerTest < Test::Unit::TestCase fixtures :webs, :pages, :revisions, :system - Wiki.storage_path += "test/" - FILE_AREA = Wiki.storage_path + 'wiki1' - FileUtils.mkdir_p(FILE_AREA) unless File.directory?(FILE_AREA) - FileUtils.rm(Dir["#{FILE_AREA}/*"]) - def setup @controller = FileController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - @wiki = Wiki.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new @web = webs(:test_wiki) - @home = @page = pages(:home_page) + WikiFile.delete_all + require 'fileutils' + FileUtils.rm_rf("#{RAILS_ROOT}/public/wiki1/files/*") end - def test_file - process 'file', 'web' => 'wiki1', 'id' => 'foo.tgz' - + def test_file_upload_form + get :file, :web => 'wiki1', :id => 'new_file.txt' assert_success assert_rendered_file 'file/file' end def test_file_download_text_file - File.open("#{FILE_AREA}/foo.txt", 'wb') { |f| f.write "aaa\nbbb\n" } - - r = process 'file', 'web' => 'wiki1', 'id' => 'foo.txt' + @web.wiki_files.create(:file_name => 'foo.txt', :description => 'Text file', + :content => "Contents of the file") + + r = get :file, :web => 'wiki1', :id => 'foo.txt' assert_success(bypass_body_parsing = true) - assert_equal "aaa\nbbb\n", r.body + assert_equal "Contents of the file", r.body assert_equal 'text/plain', r.headers['Content-Type'] end def test_file_download_pdf_file - File.open("#{FILE_AREA}/foo.pdf", 'wb') { |f| f.write "aaa\nbbb\n" } + @web.wiki_files.create(:file_name => 'foo.pdf', :description => 'PDF file', + :content => "aaa\nbbb\n") - r = process 'file', 'web' => 'wiki1', 'id' => 'foo.pdf' + r = get :file, :web => 'wiki1', :id => 'foo.pdf' assert_success(bypass_body_parsing = true) assert_equal "aaa\nbbb\n", r.body @@ -53,80 +50,83 @@ class FileControllerTest < Test::Unit::TestCase end def test_pic_download_gif - FileUtils.cp("#{RAILS_ROOT}/test/fixtures/rails.gif", FILE_AREA) + pic = File.open("#{RAILS_ROOT}/test/fixtures/rails.gif", 'rb') { |f| f.read } + @web.wiki_files.create(:file_name => 'rails.gif', :description => 'An image', :content => pic) - r = process 'pic', 'web' => 'wiki1', 'id' => 'rails.gif' + r = get :file, :web => 'wiki1', :id => 'rails.gif' assert_success(bypass_body_parsing = true) - assert_equal File.size("#{FILE_AREA}/rails.gif"), r.body.size + assert_equal 'image/gif', r.headers['Content-Type'] + assert_equal pic.size, r.body.size + assert_equal pic, r.body end - def test_pic_unknown_pic - r = process 'pic', 'web' => 'wiki1', 'id' => 'non-existant.gif' - - assert_success - assert_rendered_file 'file/file' - end - - def test_pic_upload_end_to_end - # edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif' - @wiki.revise_page('wiki1', 'HomePage', '[[rails-e2e.gif:pic]]', Time.now, 'AnonymousBrave') - assert_equal "

rails-e2e.gif" + - "?

", - @home.display_content - - # rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form - r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif' - assert_success - assert_rendered_file 'file/file' - - # User uploads the picture - picture = File.read("#{RAILS_ROOT}/test/fixtures/rails.gif") - r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif', 'file' => StringIO.new(picture) - assert_redirect_url '/' - assert @wiki.file_yard(@web).has_file?('rails-e2e.gif') - assert_equal(picture, File.read("#{RAILS_ROOT}/storage/test/wiki1/rails-e2e.gif")) - - # this should refresh the page display content (cached) - assert_equal "

\"rails-e2e.gif\"

", - @home.display_content - end - - def test_pic_upload_end_to_end - # edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif' - @wiki.revise_page('wiki1', 'HomePage', '[[instiki-e2e.txt:file]]', Time.now, 'AnonymousBrave', - test_renderer) - assert_equal "

instiki-e2e.txt" + - "?

", - test_renderer(@home.revisions.last).display_content - - # rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form - r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt' - assert_success - assert_rendered_file 'file/file' - - # User uploads the picture - file = "abcdefgh\n123" - r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt', 'file' => StringIO.new(file) - assert_redirected_to :controller => 'wiki', :action => 'show', :web => 'wiki1', :id => 'HomePage' - assert @wiki.file_yard(@web).has_file?('instiki-e2e.txt') - assert_equal(file, File.read("#{RAILS_ROOT}/storage/test/wiki1/instiki-e2e.txt")) - - # this should refresh the page display content (cached) - @home = Page.find(@home.id) - assert_equal "

" + - "instiki-e2e.txt

", - test_renderer(@home.revisions.last).display_content - end - - def test_uploads_blocking - set_web_property :allow_uploads, true - process 'file', 'web' => 'wiki1', 'id' => 'filename' - assert_success - - set_web_property :allow_uploads, false - process 'file', 'web' => 'wiki1', 'id' => 'filename' - assert_response 403 - end +# def test_pic_unknown_pic +# r = process 'pic', 'web' => 'wiki1', 'id' => 'non-existant.gif' +# +# assert_success +# assert_rendered_file 'file/file' +# end +# +# def test_pic_upload_end_to_end +# # edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif' +# @wiki.revise_page('wiki1', 'HomePage', '[[rails-e2e.gif:pic]]', Time.now, 'AnonymousBrave') +# assert_equal "

rails-e2e.gif" + +# "?

", +# @home.display_content +# +# # rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form +# r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif' +# assert_success +# assert_rendered_file 'file/file' +# +# # User uploads the picture +# picture = File.read("#{RAILS_ROOT}/test/fixtures/rails.gif") +# r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif', 'file' => StringIO.new(picture) +# assert_redirect_url '/' +# assert @wiki.file_yard(@web).has_file?('rails-e2e.gif') +# assert_equal(picture, File.read("#{RAILS_ROOT}/storage/test/wiki1/rails-e2e.gif")) +# +# # this should refresh the page display content (cached) +# assert_equal "

\"rails-e2e.gif\"

", +# @home.display_content +# end +# +# def test_pic_upload_end_to_end +# # edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif' +# @wiki.revise_page('wiki1', 'HomePage', '[[instiki-e2e.txt:file]]', Time.now, 'AnonymousBrave', +# test_renderer) +# assert_equal "

instiki-e2e.txt" + +# "?

", +# test_renderer(@home.revisions.last).display_content +# +# # rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form +# r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt' +# assert_success +# assert_rendered_file 'file/file' +# +# # User uploads the picture +# file = "abcdefgh\n123" +# r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt', 'file' => StringIO.new(file) +# assert_redirected_to :controller => 'wiki', :action => 'show', :web => 'wiki1', :id => 'HomePage' +# assert @wiki.file_yard(@web).has_file?('instiki-e2e.txt') +# assert_equal(file, File.read("#{RAILS_ROOT}/storage/test/wiki1/instiki-e2e.txt")) +# +# # this should refresh the page display content (cached) +# @home = Page.find(@home.id) +# assert_equal "

" + +# "instiki-e2e.txt

", +# test_renderer(@home.revisions.last).display_content +# end +# +# def test_uploads_blocking +# set_web_property :allow_uploads, true +# process 'file', 'web' => 'wiki1', 'id' => 'filename' +# assert_success +# +# set_web_property :allow_uploads, false +# process 'file', 'web' => 'wiki1', 'id' => 'filename' +# assert_response 403 +# end end diff --git a/test/functional/routes_test.rb b/test/functional/routes_test.rb index b07a6438..4ba2cec5 100644 --- a/test/functional/routes_test.rb +++ b/test/functional/routes_test.rb @@ -33,10 +33,8 @@ class RoutesTest < Test::Unit::TestCase :controller => 'wiki', :web => 'web', :action => 'show', :id => 'HomePage?arg1=value1&arg2=value2') - assert_routing('web/file/abc.zip', + assert_routing('web/files/abc.zip', :web => 'web', :controller => 'file', :action => 'file', :id => 'abc.zip') - assert_routing('web/pic/abc.jpg', - :web => 'web', :controller => 'file', :action => 'pic', :id => 'abc.jpg') assert_routing('web/import', :web => 'web', :controller => 'file', :action => 'import') # default option is wiki assert_recognizes({:controller => 'wiki', :web => 'unknown_path', :action => 'index', }, diff --git a/test/unit/file_yard_test.rb b/test/unit/file_yard_test.rb deleted file mode 100755 index b1859ec2..00000000 --- a/test/unit/file_yard_test.rb +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../test_helper' -require 'fileutils' -require 'file_yard' -require 'stringio' - -class FileYardTest < Test::Unit::TestCase - - def setup - FileUtils.mkdir_p(file_path) - FileUtils.rm(Dir["#{file_path}/*"]) - @yard = FileYard.new(file_path, 100) - end - - def test_check_upload_size - assert_nothing_raised { @yard.check_upload_size(100.kilobytes) } - assert_raises(Instiki::ValidationError) { @yard.check_upload_size(100.kilobytes + 1) } - end - - def test_files - assert_equal [], @yard.files - - # FileYard gets the list of files from directory in the constructor - @yard.upload_file('aaa', StringIO.new('file contents')) - assert_equal ["#{file_path}/aaa"], Dir["#{file_path}/*"] - assert_equal ['aaa'], @yard.files - assert @yard.has_file?('aaa') - assert_equal 'file contents', File.read(@yard.file_path('aaa')) - end - - def test_file_path - assert_equal "#{file_path}/abcd", @yard.file_path('abcd') - end - - def test_size_limit - @yard = FileYard.new(file_path, 1) - one_kilobyte_string = "a" * 1.kilobyte - - # as StringIO - assert_nothing_raised { - @yard.upload_file('acceptable_file', StringIO.new(one_kilobyte_string)) - } - assert_raises(Instiki::ValidationError) { - @yard.upload_file('one_byte_too_long', StringIO.new(one_kilobyte_string + 'a')) - } - - # as Tempfile - require 'tempfile' - - Tempfile.open('acceptable_file') do |f| - f.write(one_kilobyte_string) - assert_nothing_raised { - @yard.upload_file('acceptable_file', f) - } - end - - Tempfile.open('one_byte_too_long') do |f| - f.write(one_kilobyte_string + 'a') - assert_nothing_raised { - @yard.upload_file('one_byte_too_long_2', f) - } - end - end - - def file_path - "#{RAILS_ROOT}/storage/test/instiki" - end - -end diff --git a/test/unit/page_renderer_test.rb b/test/unit/page_renderer_test.rb index 50ce9e6a..00746bff 100644 --- a/test/unit/page_renderer_test.rb +++ b/test/unit/page_renderer_test.rb @@ -277,9 +277,10 @@ class PageRendererTest < Test::Unit::TestCase end def test_link_to_pic - FileUtils.mkdir_p "#{RAILS_ROOT}/storage/test/wiki1" - FileUtils.rm(Dir["#{RAILS_ROOT}/storage/test/wiki1/*"]) - @wiki.file_yard(@web).upload_file('square.jpg', StringIO.new('')) + WikiFile.delete_all + require 'fileutils' + FileUtils.rm_rf("#{RAILS_ROOT}/public/wiki1/files/*") + @web.wiki_files.create(:file_name => 'square.jpg', :description => 'Square', :content => 'never mind') assert_markup_parsed_as( '

Square

', '[[square.jpg|Square:pic]]') @@ -305,8 +306,6 @@ class PageRendererTest < Test::Unit::TestCase '[[With:Colon]]') end - # TODO Remove the leading underscores from this test when upgrading to RedCloth 3.0.1; - # also add a test for the "Unhappy Face" problem (another interesting RedCloth bug) def test_list_with_tildas list_with_tildas = <<-EOL * "a":~b diff --git a/test/unit/wiki_file_test.rb b/test/unit/wiki_file_test.rb new file mode 100644 index 00000000..c4556117 --- /dev/null +++ b/test/unit/wiki_file_test.rb @@ -0,0 +1,84 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'fileutils' + +class WikiFileTest < Test::Unit::TestCase + include FileUtils + fixtures :webs, :pages, :revisions, :system, :wiki_references + + def setup + @web = webs(:test_wiki) + mkdir_p("#{RAILS_ROOT}/public/wiki1/files/") + rm_rf("#{RAILS_ROOT}/public/wiki1/files/*") + WikiFile.delete_all + end + + def test_basic_store_and_retrieve_ascii_file + @web.wiki_files.create(:file_name => 'binary_file', :description => 'Binary file', :content => "\001\002\003") + binary = WikiFile.find_by_file_name('binary_file') + assert_equal "\001\002\003", binary.content + end + + def test_basic_store_and_retrieve_binary_file + @web.wiki_files.create(:file_name => 'text_file', :description => 'Text file', :content => "abc") + text = WikiFile.find_by_file_name('text_file') + assert_equal "abc", text.content + end + + def test_storing_an_image + rails_gif = File.open("#{RAILS_ROOT}/test/fixtures/rails.gif", 'rb') { |f| f.read } + assert_equal rails_gif.size, File.size("#{RAILS_ROOT}/test/fixtures/rails.gif") + + @web.wiki_files.create(:file_name => 'rails.gif', :description => 'Rails logo', :content => rails_gif) + + rails_gif_from_db = WikiFile.find_by_file_name('rails.gif') + assert_equal rails_gif.size, rails_gif_from_db.content.size + assert_equal rails_gif, rails_gif_from_db.content + end + + def test_mandatory_fields_validations + assert_validation(:file_name, '', :fail) + assert_validation(:file_name, nil, :fail) + assert_validation(:content, '', :fail) + assert_validation(:content, nil, :fail) + end + + def test_upload_size_validation + assert_validation(:content, 'a' * 100.kilobytes, :pass) + assert_validation(:content, 'a' * (100.kilobytes + 1), :fail) + end + + def test_file_name_size_validation + assert_validation(:file_name, '', :fail) + assert_validation(:file_name, 'a', :pass) + assert_validation(:file_name, 'a' * 50, :pass) + assert_validation(:file_name, 'a' * 51, :fail) + end + + def test_file_name_pattern_validation + assert_validation(:file_name, ".. Accep-table File.name", :pass) + assert_validation(:file_name, "/bad", :fail) + assert_validation(:file_name, "~bad", :fail) + assert_validation(:file_name, "..\bad", :fail) + assert_validation(:file_name, "\001bad", :fail) + assert_validation(:file_name, ".", :fail) + assert_validation(:file_name, "..", :fail) + end + + def test_find_by_file_name + assert_equal @file1, WikiFile.find_by_file_name('file1.txt') + assert_nil WikiFile.find_by_file_name('unknown_file') + end + + def assert_validation(field, value, expected_result) + values = {:file_name => '0', :description => '0', :content => '0'} + raise "WikiFile has no attribute named #{field.inspect}" unless values.has_key?(field) + values[field] = value + + new_object = @web.wiki_files.create(values) + if expected_result == :pass then assert(new_object.valid?, new_object.errors.inspect) + elsif expected_result == :fail then assert(!new_object.valid?) + else raise "Unknown value of expected_result: #{expected_result.inspect}" + end + end + +end