mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 17:46:05 -05:00
FIX: create an upload when FastImage throws an exception
FastImage might throw an exception when it isn't able to recognize a file as being an image (ie. happens when users changes the extension manually) Also improved upload specs a lot
This commit is contained in:
parent
2aa487d2c8
commit
6f2ce93ab2
3 changed files with 156 additions and 47 deletions
|
@ -17,7 +17,7 @@ class Upload < ActiveRecord::Base
|
||||||
validates_presence_of :original_filename
|
validates_presence_of :original_filename
|
||||||
|
|
||||||
def thumbnail
|
def thumbnail
|
||||||
@thumbnail ||= optimized_images.where(width: width, height: height).first
|
optimized_images.where(width: width, height: height).first
|
||||||
end
|
end
|
||||||
|
|
||||||
def thumbnail_url
|
def thumbnail_url
|
||||||
|
@ -48,23 +48,25 @@ class Upload < ActiveRecord::Base
|
||||||
sha1 = Digest::SHA1.file(file.tempfile).hexdigest
|
sha1 = Digest::SHA1.file(file.tempfile).hexdigest
|
||||||
# check if the file has already been uploaded
|
# check if the file has already been uploaded
|
||||||
unless upload = Upload.where(sha1: sha1).first
|
unless upload = Upload.where(sha1: sha1).first
|
||||||
|
# deal with width & heights for images
|
||||||
|
if SiteSetting.authorized_image?(file)
|
||||||
|
# retrieve image info
|
||||||
|
image_info = FastImage.new(file.tempfile, raise_on_failure: true)
|
||||||
|
# compute image aspect ratio
|
||||||
|
width, height = ImageSizer.resize(*image_info.size)
|
||||||
|
# make sure we're at the beginning of the file (FastImage is moving the pointer)
|
||||||
|
file.rewind
|
||||||
|
end
|
||||||
# create a db record (so we can use the id)
|
# create a db record (so we can use the id)
|
||||||
upload = Upload.create!({
|
upload = Upload.create!({
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
original_filename: file.original_filename,
|
original_filename: file.original_filename,
|
||||||
filesize: File.size(file.tempfile),
|
filesize: File.size(file.tempfile),
|
||||||
sha1: sha1,
|
sha1: sha1,
|
||||||
url: ""
|
url: "",
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
})
|
})
|
||||||
# deal with width & heights for images
|
|
||||||
if SiteSetting.authorized_image?(file)
|
|
||||||
# retrieve image info
|
|
||||||
image_info = FastImage.new(file.tempfile, raise_on_failure: true)
|
|
||||||
# compute image aspect ratio
|
|
||||||
upload.width, upload.height = ImageSizer.resize(*image_info.size)
|
|
||||||
# make sure we're at the beginning of the file (FastImage is moving the pointer)
|
|
||||||
file.rewind
|
|
||||||
end
|
|
||||||
# store the file and update its url
|
# store the file and update its url
|
||||||
upload.url = Upload.store_file(file, sha1, upload.id)
|
upload.url = Upload.store_file(file, sha1, upload.id)
|
||||||
# save the url
|
# save the url
|
||||||
|
@ -80,8 +82,8 @@ class Upload < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.remove_file(url)
|
def self.remove_file(url)
|
||||||
S3.remove_file(url) if SiteSetting.enable_s3_uploads?
|
return S3.remove_file(url) if SiteSetting.enable_s3_uploads?
|
||||||
LocalStore.remove_file(url)
|
return LocalStore.remove_file(url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.has_been_uploaded?(url)
|
def self.has_been_uploaded?(url)
|
||||||
|
|
7
spec/fabricators/optimized_image_fabricator.rb
Normal file
7
spec/fabricators/optimized_image_fabricator.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Fabricator(:optimized_image) do
|
||||||
|
upload
|
||||||
|
sha1 "abcdef"
|
||||||
|
extension ".png"
|
||||||
|
width 100
|
||||||
|
height 200
|
||||||
|
end
|
|
@ -13,52 +13,142 @@ describe Upload do
|
||||||
it { should validate_presence_of :original_filename }
|
it { should validate_presence_of :original_filename }
|
||||||
it { should validate_presence_of :filesize }
|
it { should validate_presence_of :filesize }
|
||||||
|
|
||||||
context '.create_for' do
|
let(:upload) { build(:upload) }
|
||||||
|
let(:thumbnail) { build(:optimized_image, upload: upload) }
|
||||||
|
|
||||||
let(:user_id) { 1 }
|
let(:user_id) { 1 }
|
||||||
|
let(:url) { "http://domain.com" }
|
||||||
|
|
||||||
let(:logo) do
|
let(:image) do
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
filename: 'logo.png',
|
filename: 'logo.png',
|
||||||
content_type: 'image/png',
|
|
||||||
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo.png")
|
tempfile: File.new("#{Rails.root}/spec/fixtures/images/logo.png")
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:upload) { Upload.create_for(user_id, logo) }
|
let(:image_sha1) { Digest::SHA1.file(image.tempfile).hexdigest }
|
||||||
|
|
||||||
let(:url) { "http://domain.com" }
|
let(:attachment) do
|
||||||
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
|
filename: File.basename(__FILE__),
|
||||||
|
tempfile: File.new(__FILE__)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
shared_examples_for "upload" do
|
context ".create_thumbnail!" do
|
||||||
it "is valid" do
|
|
||||||
|
it "does not create a thumbnail when disabled" do
|
||||||
|
SiteSetting.stubs(:create_thumbnails?).returns(false)
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).never
|
||||||
|
upload.create_thumbnail!
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not create a thumbnail when using S3" do
|
||||||
|
SiteSetting.expects(:create_thumbnails?).returns(true)
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).returns(true)
|
||||||
|
upload.expects(:has_thumbnail?).never
|
||||||
|
upload.create_thumbnail!
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not create another thumbnail" do
|
||||||
|
SiteSetting.expects(:create_thumbnails?).returns(true)
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).returns(false)
|
||||||
|
upload.expects(:has_thumbnail?).returns(true)
|
||||||
|
OptimizedImage.expects(:create_for).never
|
||||||
|
upload.create_thumbnail!
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a thumbnail" do
|
||||||
|
upload = Fabricate(:upload)
|
||||||
|
thumbnail = Fabricate(:optimized_image, upload: upload)
|
||||||
|
SiteSetting.expects(:create_thumbnails?).returns(true)
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).returns(false)
|
||||||
|
upload.expects(:has_thumbnail?).returns(false)
|
||||||
|
OptimizedImage.expects(:create_for).returns(thumbnail)
|
||||||
|
upload.create_thumbnail!
|
||||||
|
upload.reload
|
||||||
|
upload.optimized_images.count.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context ".create_for" do
|
||||||
|
|
||||||
|
it "does not create another upload if it already exists" do
|
||||||
|
Upload.expects(:where).with(sha1: image_sha1).returns([upload])
|
||||||
|
Upload.expects(:create!).never
|
||||||
|
Upload.create_for(user_id, image).should == upload
|
||||||
|
end
|
||||||
|
|
||||||
|
it "computes width & height for images" do
|
||||||
|
SiteSetting.expects(:authorized_image?).returns(true)
|
||||||
|
FastImage.any_instance.expects(:size).returns([100, 200])
|
||||||
|
ImageSizer.expects(:resize)
|
||||||
|
ActionDispatch::Http::UploadedFile.any_instance.expects(:rewind)
|
||||||
|
Upload.create_for(user_id, image)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not create an upload when there is an error with FastImage" do
|
||||||
|
SiteSetting.expects(:authorized_image?).returns(true)
|
||||||
|
Upload.expects(:create!).never
|
||||||
|
expect { Upload.create_for(user_id, attachment) }.to raise_error(FastImage::UnknownImageType)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not compute width & height for non-image" do
|
||||||
|
SiteSetting.expects(:authorized_image?).returns(false)
|
||||||
|
FastImage.any_instance.expects(:size).never
|
||||||
|
Upload.create_for(user_id, image)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "saves proper information" do
|
||||||
|
Upload.expects(:store_file).returns(url)
|
||||||
|
upload = Upload.create_for(user_id, image)
|
||||||
upload.user_id.should == user_id
|
upload.user_id.should == user_id
|
||||||
upload.original_filename.should == logo.original_filename
|
upload.original_filename.should == image.original_filename
|
||||||
upload.filesize.should == File.size(logo.tempfile)
|
upload.filesize.should == File.size(image.tempfile)
|
||||||
upload.sha1.should == Digest::SHA1.file(logo.tempfile).hexdigest
|
upload.sha1.should == Digest::SHA1.file(image.tempfile).hexdigest
|
||||||
upload.width.should == 244
|
upload.width.should == 244
|
||||||
upload.height.should == 66
|
upload.height.should == 66
|
||||||
upload.url.should == url
|
upload.url.should == url
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context "s3" do
|
|
||||||
before(:each) do
|
|
||||||
SiteSetting.stubs(:enable_s3_uploads?).returns(true)
|
|
||||||
S3.stubs(:store_file).returns(url)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like "upload"
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "locally" do
|
context ".store_file" do
|
||||||
before(:each) { LocalStore.stubs(:store_file).returns(url) }
|
|
||||||
it_behaves_like "upload"
|
it "store files on s3 when enabled" do
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).returns(true)
|
||||||
|
LocalStore.expects(:store_file).never
|
||||||
|
S3.expects(:store_file)
|
||||||
|
Upload.store_file(image, image_sha1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "store files locally by default" do
|
||||||
|
S3.expects(:store_file).never
|
||||||
|
LocalStore.expects(:store_file)
|
||||||
|
Upload.store_file(image, image_sha1, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'has_been_uploaded?' do
|
context ".remove_file" do
|
||||||
|
|
||||||
|
it "remove files on s3 when enabled" do
|
||||||
|
SiteSetting.expects(:enable_s3_uploads?).returns(true)
|
||||||
|
LocalStore.expects(:remove_file).never
|
||||||
|
S3.expects(:remove_file)
|
||||||
|
Upload.remove_file(upload.url)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "remove files locally by default" do
|
||||||
|
S3.expects(:remove_file).never
|
||||||
|
LocalStore.expects(:remove_file)
|
||||||
|
Upload.remove_file(upload.url)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context ".has_been_uploaded?" do
|
||||||
|
|
||||||
it "identifies internal or relatives urls" do
|
it "identifies internal or relatives urls" do
|
||||||
Discourse.expects(:base_url_no_prefix).returns("http://discuss.site.com")
|
Discourse.expects(:base_url_no_prefix).returns("http://discuss.site.com")
|
||||||
|
@ -84,4 +174,14 @@ describe Upload do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context ".get_from_url" do
|
||||||
|
|
||||||
|
it "works only when the file has been uploaded" do
|
||||||
|
Upload.expects(:has_been_uploaded?).returns(false)
|
||||||
|
Upload.expects(:where).never
|
||||||
|
Upload.get_from_url("discourse.org")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue