mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
refactor CookedPostProcessor & specs
This commit is contained in:
parent
c6c8246399
commit
ac7253a938
6 changed files with 313 additions and 277 deletions
|
@ -3,7 +3,9 @@ require "digest/sha1"
|
|||
class OptimizedImage < ActiveRecord::Base
|
||||
belongs_to :upload
|
||||
|
||||
def self.create_for(upload, width=nil, height=nil)
|
||||
def self.create_for(upload, width, height)
|
||||
return unless width && height
|
||||
|
||||
@image_sorcery_loaded ||= require "image_sorcery"
|
||||
|
||||
original_path = "#{Rails.root}/public#{upload.url}"
|
||||
|
@ -11,15 +13,13 @@ class OptimizedImage < ActiveRecord::Base
|
|||
temp_file = Tempfile.new(["discourse", File.extname(original_path)])
|
||||
temp_path = temp_file.path
|
||||
|
||||
# do the resize when there is both dimensions
|
||||
if width && height && ImageSorcery.new(original_path).convert(temp_path, resize: "#{width}x#{height}")
|
||||
image_info = FastImage.new(temp_path)
|
||||
if ImageSorcery.new(original_path).convert(temp_path, resize: "#{width}x#{height}")
|
||||
thumbnail = OptimizedImage.new({
|
||||
upload_id: upload.id,
|
||||
sha1: Digest::SHA1.file(temp_path).hexdigest,
|
||||
extension: File.extname(temp_path),
|
||||
width: image_info.size[0],
|
||||
height: image_info.size[1]
|
||||
width: width,
|
||||
height: height
|
||||
})
|
||||
# make sure the directory exists
|
||||
FileUtils.mkdir_p Pathname.new(thumbnail.path).dirname
|
||||
|
|
|
@ -31,7 +31,6 @@ class Upload < ActiveRecord::Base
|
|||
def create_thumbnail!
|
||||
return unless SiteSetting.create_thumbnails?
|
||||
return if SiteSetting.enable_s3_uploads?
|
||||
return if width < SiteSetting.max_image_width
|
||||
return if has_thumbnail?
|
||||
thumbnail = OptimizedImage.create_for(self, width, height)
|
||||
optimized_images << thumbnail if thumbnail
|
||||
|
@ -48,10 +47,7 @@ class Upload < ActiveRecord::Base
|
|||
# compute the sha
|
||||
sha1 = Digest::SHA1.file(file.tempfile).hexdigest
|
||||
# check if the file has already been uploaded
|
||||
upload = Upload.where(sha1: sha1).first
|
||||
|
||||
# otherwise, create it
|
||||
if upload.blank?
|
||||
unless upload = Upload.where(sha1: sha1).first
|
||||
# retrieve image info
|
||||
image_info = FastImage.new(file.tempfile, raise_on_failure: true)
|
||||
# compute image aspect ratio
|
||||
|
@ -111,6 +107,16 @@ class Upload < ActiveRecord::Base
|
|||
ActionController::Base.asset_host
|
||||
end
|
||||
|
||||
def self.get_from_url(url)
|
||||
if has_been_uploaded?(url)
|
||||
if m = LocalStore.uploaded_regex.match(url)
|
||||
Upload.where(id: m[:upload_id]).first
|
||||
elsif is_on_s3?(url)
|
||||
Upload.where(url: url).first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Post processing that we can do after a post has already been cooked.
|
||||
# For example, inserting the onebox content, or image sizes.
|
||||
# For example, inserting the onebox content, or image sizes/thumbnails.
|
||||
|
||||
require_dependency 'oneboxer'
|
||||
|
||||
|
@ -21,43 +21,31 @@ class CookedPostProcessor
|
|||
end
|
||||
|
||||
def post_process_images
|
||||
images = @doc.css("img") - @doc.css(".onebox-result img") - @doc.css(".quote img")
|
||||
images = extract_images
|
||||
return if images.blank?
|
||||
|
||||
images.each do |img|
|
||||
# keep track of the original src
|
||||
src = img['src']
|
||||
# make sure the src is absolute (when working with locally uploaded files)
|
||||
img['src'] = Discourse.base_url_no_prefix + img['src'] if img['src'] =~ /^\/[^\/]/
|
||||
|
||||
if src.present?
|
||||
# make sure the img has both width and height attributes
|
||||
if img['src'].present?
|
||||
# keep track of the original src
|
||||
src = img['src']
|
||||
# make sure the src is absolute (when working with locally uploaded files)
|
||||
img['src'] = relative_to_absolute(src)
|
||||
# make sure the img has proper width and height attributes
|
||||
update_dimensions!(img)
|
||||
# retrieve the associated upload, if any
|
||||
upload = get_upload_from_url(img['src'])
|
||||
if upload.present?
|
||||
if upload = Upload.get_from_url(img['src'])
|
||||
# update reverse index
|
||||
associate_to_post upload
|
||||
# create a thumbnail
|
||||
upload.create_thumbnail!
|
||||
# optimize image
|
||||
img['src'] = optimize_image(img)
|
||||
# lightbox treatment
|
||||
convert_to_link!(img, upload)
|
||||
else
|
||||
convert_to_link!(img)
|
||||
associate_to_post(upload)
|
||||
end
|
||||
# lightbox treatment
|
||||
convert_to_link!(img, upload)
|
||||
# mark the post as dirty whenever the src has changed
|
||||
@dirty |= src != img['src']
|
||||
end
|
||||
end
|
||||
|
||||
# Extract the first image from the first post and use it as the 'topic image'
|
||||
if @post.post_number == 1
|
||||
img = images.first
|
||||
@post.topic.update_column :image_url, img['src'] if img['src'].present?
|
||||
end
|
||||
|
||||
extract_topic_image(images)
|
||||
end
|
||||
|
||||
def post_process_oneboxes
|
||||
|
@ -71,28 +59,31 @@ class CookedPostProcessor
|
|||
@dirty |= result.changed?
|
||||
end
|
||||
|
||||
def extract_images
|
||||
# do not extract images inside a onebox or a quote
|
||||
@doc.css("img") - @doc.css(".onebox-result img") - @doc.css(".quote img")
|
||||
end
|
||||
|
||||
def relative_to_absolute(src)
|
||||
if src =~ /\A\/[^\/]/
|
||||
Discourse.base_url_no_prefix + src
|
||||
else
|
||||
src
|
||||
end
|
||||
end
|
||||
|
||||
def update_dimensions!(img)
|
||||
return if img['width'].present? && img['height'].present?
|
||||
|
||||
w, h = get_size_from_image_sizes(img['src'], @opts[:image_sizes]) || image_dimensions(img['src'])
|
||||
|
||||
if w && h
|
||||
img['width'] = w.to_s
|
||||
img['height'] = h.to_s
|
||||
img['width'] = w
|
||||
img['height'] = h
|
||||
@dirty = true
|
||||
end
|
||||
end
|
||||
|
||||
def get_upload_from_url(url)
|
||||
if Upload.has_been_uploaded?(url)
|
||||
if m = LocalStore.uploaded_regex.match(url)
|
||||
Upload.where(id: m[:upload_id]).first
|
||||
elsif Upload.is_on_s3?(url)
|
||||
Upload.where(url: url).first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def associate_to_post(upload)
|
||||
return if PostUpload.where(post_id: @post.id, upload_id: upload.id).count > 0
|
||||
PostUpload.create({ post_id: @post.id, upload_id: upload.id })
|
||||
|
@ -100,10 +91,10 @@ class CookedPostProcessor
|
|||
# do not care if it's already associated
|
||||
end
|
||||
|
||||
def optimize_image(img)
|
||||
return img["src"]
|
||||
def optimize_image!(img)
|
||||
# TODO
|
||||
# 1) optimize using image_optim
|
||||
# 2) .png vs. .jpg
|
||||
# 2) .png vs. .jpg (> 1.5x)
|
||||
end
|
||||
|
||||
def convert_to_link!(img, upload=nil)
|
||||
|
@ -113,42 +104,59 @@ class CookedPostProcessor
|
|||
width, height = img["width"].to_i, img["height"].to_i
|
||||
original_width, original_height = get_size(src)
|
||||
|
||||
return unless original_width.to_i > width && original_height.to_i > height
|
||||
return if original_width < SiteSetting.max_image_width
|
||||
return if original_width.to_i <= width && original_height.to_i <= height
|
||||
return if original_width.to_i <= SiteSetting.max_image_width
|
||||
return if is_a_hyperlink(img)
|
||||
|
||||
if upload
|
||||
# create a thumbnail
|
||||
upload.create_thumbnail!
|
||||
# optimize image
|
||||
# TODO: optimize_image!(img)
|
||||
end
|
||||
|
||||
add_lightbox!(img, original_width, original_height, upload)
|
||||
|
||||
@dirty = true
|
||||
end
|
||||
|
||||
def is_a_hyperlink(img)
|
||||
parent = img.parent
|
||||
while parent
|
||||
return if parent.name == "a"
|
||||
break unless parent.respond_to? :parent
|
||||
parent = parent.parent
|
||||
end
|
||||
end
|
||||
|
||||
# not a hyperlink so we can apply
|
||||
img['src'] = upload.thumbnail_url if (upload && upload.thumbnail_url.present?)
|
||||
def add_lightbox!(img, original_width, original_height, upload=nil)
|
||||
# first, create a div to hold our lightbox
|
||||
lightbox = Nokogiri::XML::Node.new "div", @doc
|
||||
img.add_next_sibling lightbox
|
||||
lightbox.add_child img
|
||||
lightbox = Nokogiri::XML::Node.new("div", @doc)
|
||||
img.add_next_sibling(lightbox)
|
||||
lightbox.add_child(img)
|
||||
|
||||
# then, the link to our larger image
|
||||
a = Nokogiri::XML::Node.new "a", @doc
|
||||
a = Nokogiri::XML::Node.new("a", @doc)
|
||||
img.add_next_sibling(a)
|
||||
a["href"] = src
|
||||
a["href"] = img['src']
|
||||
a["class"] = "lightbox"
|
||||
a.add_child(img)
|
||||
# then, some overlay informations
|
||||
meta = Nokogiri::XML::Node.new "div", @doc
|
||||
meta["class"] = "meta"
|
||||
img.add_next_sibling meta
|
||||
|
||||
filename = get_filename(upload, src)
|
||||
# replace the image by its thumbnail
|
||||
img['src'] = upload.thumbnail_url if upload && upload.has_thumbnail?
|
||||
|
||||
# then, some overlay informations
|
||||
meta = Nokogiri::XML::Node.new("div", @doc)
|
||||
meta["class"] = "meta"
|
||||
img.add_next_sibling(meta)
|
||||
|
||||
filename = get_filename(upload, img['src'])
|
||||
informations = "#{original_width}x#{original_height}"
|
||||
informations << " | #{number_to_human_size(upload.filesize)}" if upload
|
||||
|
||||
meta.add_child create_span_node("filename", filename)
|
||||
meta.add_child create_span_node("informations", informations)
|
||||
meta.add_child create_span_node("expand")
|
||||
|
||||
@dirty = true
|
||||
end
|
||||
|
||||
def get_filename(upload, src)
|
||||
|
@ -158,12 +166,19 @@ class CookedPostProcessor
|
|||
end
|
||||
|
||||
def create_span_node(klass, content=nil)
|
||||
span = Nokogiri::XML::Node.new "span", @doc
|
||||
span = Nokogiri::XML::Node.new("span", @doc)
|
||||
span.content = content if content
|
||||
span['class'] = klass
|
||||
span
|
||||
end
|
||||
|
||||
def extract_topic_image(images)
|
||||
if @post.post_number == 1
|
||||
img = images.first
|
||||
@post.topic.update_column :image_url, img['src'] if img['src'].present?
|
||||
end
|
||||
end
|
||||
|
||||
def get_size_from_image_sizes(src, image_sizes)
|
||||
if image_sizes.present?
|
||||
if dim = image_sizes[src]
|
||||
|
@ -180,8 +195,8 @@ class CookedPostProcessor
|
|||
|
||||
def get_size(url)
|
||||
# make sure s3 urls have a scheme (otherwise, FastImage will fail)
|
||||
url = "http:" + url if Upload.is_on_s3? (url)
|
||||
return unless is_valid_image_uri? url
|
||||
url = "http:" + url if Upload.is_on_s3?(url)
|
||||
return unless is_valid_image_uri?(url)
|
||||
# we can *always* crawl our own images
|
||||
return unless SiteSetting.crawl_images? || Upload.has_been_uploaded?(url)
|
||||
@size_cache[url] ||= FastImage.size(url)
|
||||
|
|
|
@ -3,218 +3,164 @@ require 'cooked_post_processor'
|
|||
|
||||
describe CookedPostProcessor do
|
||||
|
||||
def cpp(cooked = nil, options = {})
|
||||
post = Fabricate.build(:post_with_youtube)
|
||||
post.cooked = cooked if cooked
|
||||
post.id = 123
|
||||
CookedPostProcessor.new(post, options)
|
||||
end
|
||||
context "post_process" do
|
||||
|
||||
context 'process_onebox' do
|
||||
let(:post) { build(:post) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
let(:post_process) { sequence("post_process") }
|
||||
|
||||
before do
|
||||
@cpp = cpp(nil, invalidate_oneboxes: true)
|
||||
Oneboxer.expects(:onebox).with("http://www.youtube.com/watch?v=9bZkp7q19f0", post_id: 123, invalidate_oneboxes: true).returns('<div>GANGNAM STYLE</div>')
|
||||
@cpp.post_process_oneboxes
|
||||
end
|
||||
|
||||
it 'should be dirty' do
|
||||
@cpp.should be_dirty
|
||||
end
|
||||
|
||||
it 'inserts the onebox without wrapping p' do
|
||||
@cpp.html.should match_html "<div>GANGNAM STYLE</div>"
|
||||
it "works on images before oneboxes" do
|
||||
cpp.expects(:post_process_images).in_sequence(post_process)
|
||||
cpp.expects(:post_process_oneboxes).in_sequence(post_process)
|
||||
cpp.post_process
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "post_process_images" do
|
||||
|
||||
context 'process_images' do
|
||||
context "with images in quotes and oneboxes" do
|
||||
|
||||
it "has no topic image if there isn't one in the post" do
|
||||
@post = Fabricate(:post)
|
||||
@post.topic.image_url.should be_blank
|
||||
end
|
||||
let(:post) { build(:post_with_images_in_quote_and_onebox) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
before { cpp.post_process_images }
|
||||
|
||||
context 'with sized images in the post' do
|
||||
before do
|
||||
@topic = Fabricate(:topic)
|
||||
@post = Fabricate.build(:post_with_image_url, topic: @topic, user: @topic.user)
|
||||
@cpp = CookedPostProcessor.new(@post, image_sizes: {'http://www.forumwarz.com/images/header/logo.png' => {'width' => 111, 'height' => 222}})
|
||||
it "does not process them" do
|
||||
cpp.html.should match_html post.cooked
|
||||
cpp.should_not be_dirty
|
||||
end
|
||||
|
||||
it "has no topic image if there isn't one in the post" do
|
||||
post.topic.image_url.should be_blank
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "with uploaded images" do
|
||||
|
||||
let(:upload) { Fabricate(:upload) }
|
||||
let(:post) { Fabricate(:post_with_uploaded_images) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
before { FastImage.stubs(:size) }
|
||||
|
||||
# all in one test to speed things up
|
||||
it "works" do
|
||||
Upload.expects(:get_from_url).returns(upload).twice
|
||||
cpp.post_process_images
|
||||
# ensures absolute urls on uploaded images
|
||||
cpp.html.should =~ /#{Discourse.base_url_no_prefix}/
|
||||
# dirty
|
||||
cpp.should be_dirty
|
||||
# keeps the reverse index up to date
|
||||
post.uploads.reload
|
||||
post.uploads.count.should == 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "width sized images" do
|
||||
|
||||
let(:post) { build(:post_with_image_url) }
|
||||
let(:cpp) { CookedPostProcessor.new(post, image_sizes: {'http://foo.bar/image.png' => {'width' => 111, 'height' => 222}}) }
|
||||
|
||||
before { FastImage.stubs(:size).returns([150, 250]) }
|
||||
|
||||
it "doesn't call image_dimensions because it knows the size" do
|
||||
@cpp.expects(:image_dimensions).never
|
||||
@cpp.post_process_images
|
||||
cpp.expects(:image_dimensions).never
|
||||
cpp.post_process_images
|
||||
end
|
||||
|
||||
it "adds the width from the image sizes provided" do
|
||||
@cpp.post_process_images
|
||||
@cpp.html.should =~ /width=\"111\"/
|
||||
cpp.post_process_images
|
||||
cpp.html.should =~ /width=\"111\"/
|
||||
cpp.should be_dirty
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with uploaded images in the post' do
|
||||
before do
|
||||
@topic = Fabricate(:topic)
|
||||
@post = Fabricate(:post_with_uploads, topic: @topic, user: @topic.user)
|
||||
@cpp = CookedPostProcessor.new(@post)
|
||||
@cpp.expects(:get_upload_from_url).returns(Fabricate(:upload))
|
||||
@cpp.expects(:get_size).returns([100,200])
|
||||
end
|
||||
context "with unsized images" do
|
||||
|
||||
it "keeps reverse index up to date" do
|
||||
@cpp.post_process_images
|
||||
@post.uploads.reload
|
||||
@post.uploads.count.should == 1
|
||||
let(:post) { build(:post_with_unsized_images) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "adds the width and height to images that don't have them" do
|
||||
FastImage.expects(:size).returns([123, 456])
|
||||
cpp.post_process_images
|
||||
cpp.html.should =~ /width="123" height="456"/
|
||||
cpp.should be_dirty
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with unsized images in the post' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:topic) { Fabricate(:topic, user: user) }
|
||||
context "with large images" do
|
||||
|
||||
let(:upload) { Fabricate(:upload) }
|
||||
let(:post) { build(:post_with_large_image) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
before do
|
||||
FastImage.stubs(:size).returns([123, 456])
|
||||
creator = PostCreator.new(user, raw: Fabricate.build(:post_with_images).raw, topic_id: topic.id)
|
||||
@post = creator.create
|
||||
end
|
||||
|
||||
it "adds a topic image if there's one in the post" do
|
||||
@post.topic.reload
|
||||
@post.topic.image_url.should == "http://test.localhost/path/to/img.jpg"
|
||||
end
|
||||
|
||||
it "adds the height and width to images that don't have them" do
|
||||
@post.reload
|
||||
@post.cooked.should =~ /width=\"123\" height=\"456\"/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with an absolute image path without protocol' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:topic) { Fabricate(:topic, user: user) }
|
||||
let(:post) { Fabricate.build(:post_with_s3_image_url, topic: topic, user: user) }
|
||||
let(:processor) { CookedPostProcessor.new(post) }
|
||||
|
||||
before do
|
||||
processor.post_process_images
|
||||
end
|
||||
|
||||
it "doesn't change the protocol" do
|
||||
processor.html.should =~ /src="\/\/bucket\.s3\.amazonaws\.com\/uploads\/6\/4\/123\.png"/
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a oneboxed image' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:topic) { Fabricate(:topic, user: user) }
|
||||
let(:post) { Fabricate.build(:post_with_oneboxed_image, topic: topic, user: user) }
|
||||
let(:processor) { CookedPostProcessor.new(post) }
|
||||
|
||||
before do
|
||||
processor.post_process_images
|
||||
end
|
||||
|
||||
it "doesn't lightbox" do
|
||||
processor.html.should_not =~ /class="lightbox"/
|
||||
end
|
||||
end
|
||||
|
||||
context "with a large image" do
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:topic) { Fabricate(:topic, user: user) }
|
||||
let(:post) { Fabricate.build(:post_with_uploads, topic: topic, user: user) }
|
||||
let(:processor) { CookedPostProcessor.new(post) }
|
||||
|
||||
before do
|
||||
SiteSetting.stubs(:max_image_width).returns(10)
|
||||
FastImage.stubs(:size).returns([1000, 1000])
|
||||
processor.post_process_images
|
||||
SiteSetting.stubs(:create_thumbnails?).returns(true)
|
||||
Upload.expects(:get_from_url).returns(upload)
|
||||
cpp.stubs(:associate_to_post)
|
||||
FastImage.stubs(:size).returns([1000, 2000])
|
||||
# optimized_image
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
File.stubs(:open)
|
||||
ImageSorcery.any_instance.expects(:convert).returns(true)
|
||||
end
|
||||
|
||||
it "generates overlay information" do
|
||||
processor.html.should =~ /class="lightbox"/
|
||||
processor.html.should =~ /class="meta"/
|
||||
processor.html.should =~ /class="filename"/
|
||||
processor.html.should =~ /class="informations"/
|
||||
processor.html.should =~ /class="expand"/
|
||||
cpp.post_process_images
|
||||
cpp.html.should match_html '<div><a href="http://test.localhost/uploads/default/1/1234567890123456.jpg" class="lightbox"><img src="http://test.localhost/uploads/default/_optimized/da3/9a3/ee5e6b4b0d3_100x200.jpg" width="690" height="1380"><div class="meta">
|
||||
<span class="filename">uploaded.jpg</span><span class="informations">1000x2000 | 1.21 KB</span><span class="expand"></span>
|
||||
</div></a></div>'
|
||||
cpp.should be_dirty
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "topic image" do
|
||||
|
||||
let(:topic) { build(:topic, id: 1) }
|
||||
let(:post) { Fabricate(:post_with_uploaded_images, topic: topic) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "adds a topic image if there's one in the post" do
|
||||
FastImage.stubs(:size).returns([100, 100])
|
||||
cpp.post_process_images
|
||||
post.topic.reload
|
||||
post.topic.image_url.should == "http://test.localhost/uploads/default/2/3456789012345678.png"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'link convertor' do
|
||||
context "post_process_oneboxes" do
|
||||
|
||||
let(:post) { build(:post_with_youtube, id: 123) }
|
||||
let(:cpp) { CookedPostProcessor.new(post, invalidate_oneboxes: true) }
|
||||
|
||||
before do
|
||||
SiteSetting.stubs(:crawl_images?).returns(true)
|
||||
Oneboxer.expects(:onebox).with("http://www.youtube.com/watch?v=9bZkp7q19f0", post_id: 123, invalidate_oneboxes: true).returns('<div>GANGNAM STYLE</div>')
|
||||
cpp.post_process_oneboxes
|
||||
end
|
||||
|
||||
let(:post_with_img) { Fabricate.build(:post, cooked: '<p><img src="http://hello.com/image.png"></p>') }
|
||||
let(:cpp_for_post) { CookedPostProcessor.new(post_with_img) }
|
||||
|
||||
it 'convert img tags to links if they are sized down' do
|
||||
cpp_for_post.expects(:get_size).returns([2000,2000]).twice
|
||||
cpp_for_post.post_process
|
||||
cpp_for_post.html.should =~ /a href/
|
||||
it "should be dirty" do
|
||||
cpp.should be_dirty
|
||||
end
|
||||
|
||||
it 'does not convert img tags to links if they are small' do
|
||||
cpp_for_post.expects(:get_size).returns([200,200]).twice
|
||||
cpp_for_post.post_process
|
||||
(cpp_for_post.html !~ /a href/).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "image_dimensions" do
|
||||
|
||||
it "returns unless called with a http or https url" do
|
||||
cpp.image_dimensions("/tmp/image.jpg").should be_blank
|
||||
end
|
||||
|
||||
context "with valid url" do
|
||||
|
||||
let(:url) { "http://www.forumwarz.com/images/header/logo.png" }
|
||||
|
||||
it "doesn't call FastImage if image crawling is disabled" do
|
||||
SiteSetting.expects(:crawl_images?).returns(false)
|
||||
FastImage.expects(:size).never
|
||||
cpp.image_dimensions(url)
|
||||
end
|
||||
|
||||
it "calls FastImage if image crawling is enabled" do
|
||||
SiteSetting.expects(:crawl_images?).returns(true)
|
||||
FastImage.expects(:size).with(url)
|
||||
cpp.image_dimensions(url)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "is_valid_image_uri?" do
|
||||
|
||||
it "needs the scheme to be either http or https" do
|
||||
cpp.is_valid_image_uri?("http://domain.com").should == true
|
||||
cpp.is_valid_image_uri?("https://domain.com").should == true
|
||||
cpp.is_valid_image_uri?("ftp://domain.com").should == false
|
||||
cpp.is_valid_image_uri?("ftps://domain.com").should == false
|
||||
cpp.is_valid_image_uri?("//domain.com").should == false
|
||||
cpp.is_valid_image_uri?("/tmp/image.png").should == false
|
||||
end
|
||||
|
||||
it "doesn't throw an exception with a bad URI" do
|
||||
cpp.is_valid_image_uri?("http://do<main.com").should == nil
|
||||
it "inserts the onebox without wrapping p" do
|
||||
cpp.html.should match_html "<div>GANGNAM STYLE</div>"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "get_filename" do
|
||||
|
||||
let(:post) { build(:post) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "returns the filename of the src when there is no upload" do
|
||||
cpp.get_filename(nil, "http://domain.com/image.png").should == "image.png"
|
||||
end
|
||||
|
@ -231,4 +177,80 @@ describe CookedPostProcessor do
|
|||
|
||||
end
|
||||
|
||||
context "image_dimensions" do
|
||||
|
||||
let(:post) { build(:post) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "calls the resizer" do
|
||||
SiteSetting.stubs(:max_image_width).returns(200)
|
||||
cpp.expects(:get_size).returns([1000, 2000])
|
||||
cpp.image_dimensions("http://foo.bar/image.png").should == [200, 400]
|
||||
end
|
||||
|
||||
it "doesn't call the resizer when there is no size" do
|
||||
cpp.expects(:get_size).returns(nil)
|
||||
cpp.image_dimensions("http://foo.bar/image.png").should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "get_size" do
|
||||
|
||||
let(:post) { build(:post) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "ensures s3 urls have a default scheme" do
|
||||
Upload.stubs(:is_on_s3?).returns(true)
|
||||
FastImage.stubs(:size)
|
||||
cpp.expects(:is_valid_image_uri?).with("http://bucket.s3.aws.amazon.com/image.jpg")
|
||||
cpp.get_size("//bucket.s3.aws.amazon.com/image.jpg")
|
||||
end
|
||||
|
||||
context "crawl_images is disabled" do
|
||||
|
||||
before { SiteSetting.stubs(:crawl_images?).returns(false) }
|
||||
|
||||
it "doesn't call FastImage" do
|
||||
FastImage.expects(:size).never
|
||||
cpp.get_size("http://foo.bar/image.png").should == nil
|
||||
end
|
||||
|
||||
it "is always allowed to crawled our own images" do
|
||||
Upload.expects(:has_been_uploaded?).returns(true)
|
||||
FastImage.expects(:size).returns([100, 200])
|
||||
cpp.get_size("http://foo.bar/image.png").should == [100, 200]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it "caches the results" do
|
||||
SiteSetting.stubs(:crawl_images?).returns(true)
|
||||
FastImage.expects(:size).returns([200, 400])
|
||||
cpp.get_size("http://foo.bar/image.png")
|
||||
cpp.get_size("http://foo.bar/image.png").should == [200, 400]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "is_valid_image_uri?" do
|
||||
|
||||
let(:post) { build(:post) }
|
||||
let(:cpp) { CookedPostProcessor.new(post) }
|
||||
|
||||
it "needs the scheme to be either http or https" do
|
||||
cpp.is_valid_image_uri?("http://domain.com").should == true
|
||||
cpp.is_valid_image_uri?("https://domain.com").should == true
|
||||
cpp.is_valid_image_uri?("ftp://domain.com").should == false
|
||||
cpp.is_valid_image_uri?("ftps://domain.com").should == false
|
||||
cpp.is_valid_image_uri?("//domain.com").should == false
|
||||
cpp.is_valid_image_uri?("/tmp/image.png").should == false
|
||||
end
|
||||
|
||||
it "doesn't throw an exception with a bad URI" do
|
||||
cpp.is_valid_image_uri?("http://do<main.com").should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -20,41 +20,6 @@ Fabricator(:moderator_post, from: :post) do
|
|||
raw "Hello world"
|
||||
end
|
||||
|
||||
|
||||
Fabricator(:post_with_images, from: :post) do
|
||||
raw "
|
||||
<img src='/path/to/img.jpg' height='50' width='50'>
|
||||
![Alt text](/second_image.jpg)
|
||||
"
|
||||
end
|
||||
|
||||
Fabricator(:post_with_image_url, from: :post) do
|
||||
cooked "
|
||||
<img src=\"http://www.forumwarz.com/images/header/logo.png\">
|
||||
"
|
||||
end
|
||||
|
||||
Fabricator(:post_with_s3_image_url, from: :post) do
|
||||
cooked "
|
||||
<img src=\"//bucket.s3.amazonaws.com/uploads/6/4/123.png\">
|
||||
"
|
||||
end
|
||||
|
||||
Fabricator(:post_with_uploads, from: :post) do
|
||||
cooked "
|
||||
<img src='/uploads/default/1/1234567890123456.jpg' height='100' width='100'>
|
||||
"
|
||||
end
|
||||
|
||||
Fabricator(:post_with_oneboxed_image, from: :post) do
|
||||
cooked "
|
||||
<div class='onebox-result'>
|
||||
<img src='/uploads/default/1/1234567890123456.jpg' height='100' width='100'>
|
||||
</div>
|
||||
"
|
||||
end
|
||||
|
||||
|
||||
Fabricator(:basic_reply, from: :post) do
|
||||
user(:coding_horror)
|
||||
reply_to_post_number 1
|
||||
|
@ -71,6 +36,35 @@ Fabricator(:reply, from: :post) do
|
|||
'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_images_in_quote_and_onebox, from: :post) do
|
||||
cooked '
|
||||
<aside class="quote"><img src="/uploads/default/1/1234567890123456.jpg"></aside>
|
||||
<div class="onebox-result"><img src="/uploads/default/1/1234567890123456.jpg"></div>
|
||||
'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_uploaded_images, from: :post) do
|
||||
cooked '
|
||||
<img src="/uploads/default/2/3456789012345678.png" width="1500" height="2000">
|
||||
<img src="/uploads/default/1/1234567890123456.jpg">
|
||||
'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_unsized_images, from: :post) do
|
||||
cooked '
|
||||
<img src="http://foo.bar/image.png">
|
||||
<img src="/uploads/default/1/1234567890123456.jpg">
|
||||
'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_image_url, from: :post) do
|
||||
cooked '<img src="http://foo.bar/image.png">'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_large_image, from: :post) do
|
||||
cooked '<img src="/uploads/default/1/1234567890123456.jpg">'
|
||||
end
|
||||
|
||||
Fabricator(:post_with_external_links, from: :post) do
|
||||
user
|
||||
topic
|
||||
|
|
|
@ -10,20 +10,19 @@ describe OptimizedImage do
|
|||
describe ".create_for" do
|
||||
|
||||
before(:each) do
|
||||
ImageSorcery.any_instance.stubs(:convert).returns(true)
|
||||
FastImage.any_instance.stubs(:size).returns([244, 66])
|
||||
ImageSorcery.any_instance.expects(:convert).returns(true)
|
||||
# make sure we don't hit the filesystem
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
File.stubs(:open)
|
||||
end
|
||||
|
||||
it "works" do
|
||||
Tempfile.any_instance.expects(:close).once
|
||||
Tempfile.any_instance.expects(:unlink).once
|
||||
Tempfile.any_instance.expects(:close)
|
||||
Tempfile.any_instance.expects(:unlink)
|
||||
oi.sha1.should == "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
oi.extension.should == ".jpg"
|
||||
oi.width.should == 244
|
||||
oi.height.should == 66
|
||||
oi.width.should == 100
|
||||
oi.height.should == 100
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue