Adds a macro for inserting thumbnails in formatted text (#3510).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10013 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
5c2de4dfc9
commit
537be80be2
|
@ -61,7 +61,7 @@ class AttachmentsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def thumbnail
|
def thumbnail
|
||||||
if @attachment.thumbnailable? && Setting.thumbnails_enabled? && thumbnail = @attachment.thumbnail
|
if @attachment.thumbnailable? && thumbnail = @attachment.thumbnail(:size => params[:size])
|
||||||
if stale?(:etag => thumbnail)
|
if stale?(:etag => thumbnail)
|
||||||
send_file thumbnail,
|
send_file thumbnail,
|
||||||
:filename => filename_for_content_disposition(@attachment.filename),
|
:filename => filename_for_content_disposition(@attachment.filename),
|
||||||
|
|
|
@ -171,9 +171,17 @@ class Attachment < ActiveRecord::Base
|
||||||
|
|
||||||
# Returns the full path the attachment thumbnail, or nil
|
# Returns the full path the attachment thumbnail, or nil
|
||||||
# if the thumbnail cannot be generated.
|
# if the thumbnail cannot be generated.
|
||||||
def thumbnail
|
def thumbnail(options={})
|
||||||
if thumbnailable? && readable?
|
if thumbnailable? && readable?
|
||||||
size = Setting.thumbnails_size.to_i
|
size = options[:size].to_i
|
||||||
|
if size > 0
|
||||||
|
# Limit the number of thumbnails per image
|
||||||
|
size = (size / 50) * 50
|
||||||
|
# Maximum thumbnail size
|
||||||
|
size = 800 if size > 800
|
||||||
|
else
|
||||||
|
size = Setting.thumbnails_size.to_i
|
||||||
|
end
|
||||||
size = 100 unless size > 0
|
size = 100 unless size > 0
|
||||||
target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb")
|
target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb")
|
||||||
|
|
||||||
|
|
|
@ -264,7 +264,7 @@ RedmineApp::Application.routes.draw do
|
||||||
match 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/, :via => :get
|
match 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/, :via => :get
|
||||||
match 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/, :via => :get
|
match 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/, :via => :get
|
||||||
match 'attachments/download/:id', :controller => 'attachments', :action => 'download', :id => /\d+/, :via => :get
|
match 'attachments/download/:id', :controller => 'attachments', :action => 'download', :id => /\d+/, :via => :get
|
||||||
match 'attachments/thumbnail/:id', :controller => 'attachments', :action => 'thumbnail', :id => /\d+/, :via => :get
|
match 'attachments/thumbnail/:id(/:size)', :controller => 'attachments', :action => 'thumbnail', :id => /\d+/, :via => :get, :size => /\d+/
|
||||||
resources :attachments, :only => [:show, :destroy]
|
resources :attachments, :only => [:show, :destroy]
|
||||||
|
|
||||||
resources :groups do
|
resources :groups do
|
||||||
|
|
|
@ -116,6 +116,24 @@ module Redmine
|
||||||
@included_wiki_pages.pop
|
@included_wiki_pages.pop
|
||||||
out
|
out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Displays a clickable thumbnail of an attached image. Examples:\n\n<pre>{{thumbnail(image.png)}}\n{{thumbnail(image.png, size=300, title=Thumbnail)}}</pre>"
|
||||||
|
macro :thumbnail do |obj, args|
|
||||||
|
args, options = extract_macro_options(args, :size, :title)
|
||||||
|
filename = args.first
|
||||||
|
raise 'Filename required' unless filename.present?
|
||||||
|
size = options[:size]
|
||||||
|
raise 'Invalid size parameter' unless size.nil? || size.match(/^\d+$/)
|
||||||
|
size = size.to_i
|
||||||
|
size = nil unless size > 0
|
||||||
|
if obj && obj.respond_to?(:attachments) && attachment = Attachment.latest_attach(obj.attachments, filename)
|
||||||
|
title = options[:title] || attachment.title
|
||||||
|
img = image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment, :size => size), :alt => attachment.filename)
|
||||||
|
link_to(img, url_for(:controller => 'attachments', :action => 'show', :id => attachment), :class => 'thumbnail', :title => title)
|
||||||
|
else
|
||||||
|
raise "Attachment #{filename} not found"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -262,43 +262,44 @@ class AttachmentsControllerTest < ActionController::TestCase
|
||||||
def test_thumbnail
|
def test_thumbnail
|
||||||
Attachment.clear_thumbnails
|
Attachment.clear_thumbnails
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
with_settings :thumbnails_enabled => '1' do
|
|
||||||
get :thumbnail, :id => 16
|
get :thumbnail, :id => 16
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_equal 'image/png', response.content_type
|
assert_equal 'image/png', response.content_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_thumbnail_should_not_exceed_maximum_size
|
||||||
|
Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 800}
|
||||||
|
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get :thumbnail, :id => 16, :size => 2000
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_thumbnail_should_round_size
|
||||||
|
Redmine::Thumbnail.expects(:generate).with {|source, target, size| size == 250}
|
||||||
|
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get :thumbnail, :id => 16, :size => 260
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_thumbnail_should_return_404_for_non_image_attachment
|
def test_thumbnail_should_return_404_for_non_image_attachment
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
with_settings :thumbnails_enabled => '1' do
|
|
||||||
get :thumbnail, :id => 15
|
|
||||||
assert_response 404
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_thumbnail_should_return_404_if_thumbnails_not_enabled
|
get :thumbnail, :id => 15
|
||||||
@request.session[:user_id] = 2
|
assert_response 404
|
||||||
with_settings :thumbnails_enabled => '0' do
|
|
||||||
get :thumbnail, :id => 16
|
|
||||||
assert_response 404
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_thumbnail_should_return_404_if_thumbnail_generation_failed
|
def test_thumbnail_should_return_404_if_thumbnail_generation_failed
|
||||||
Attachment.any_instance.stubs(:thumbnail).returns(nil)
|
Attachment.any_instance.stubs(:thumbnail).returns(nil)
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
with_settings :thumbnails_enabled => '1' do
|
|
||||||
get :thumbnail, :id => 16
|
get :thumbnail, :id => 16
|
||||||
assert_response 404
|
assert_response 404
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_thumbnail_should_be_denied_without_permission
|
def test_thumbnail_should_be_denied_without_permission
|
||||||
with_settings :thumbnails_enabled => '1' do
|
get :thumbnail, :id => 16
|
||||||
get :thumbnail, :id => 16
|
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
|
||||||
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fthumbnail%2F16'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
puts '(ImageMagick convert not available)'
|
puts '(ImageMagick convert not available)'
|
||||||
|
|
|
@ -49,6 +49,10 @@ class RoutingAttachmentsTest < ActionController::IntegrationTest
|
||||||
{ :method => 'get', :path => "/attachments/thumbnail/1" },
|
{ :method => 'get', :path => "/attachments/thumbnail/1" },
|
||||||
{ :controller => 'attachments', :action => 'thumbnail', :id => '1' }
|
{ :controller => 'attachments', :action => 'thumbnail', :id => '1' }
|
||||||
)
|
)
|
||||||
|
assert_routing(
|
||||||
|
{ :method => 'get', :path => "/attachments/thumbnail/1/200" },
|
||||||
|
{ :controller => 'attachments', :action => 'thumbnail', :id => '1', :size => '200' }
|
||||||
|
)
|
||||||
assert_routing(
|
assert_routing(
|
||||||
{ :method => 'delete', :path => "/attachments/1" },
|
{ :method => 'delete', :path => "/attachments/1" },
|
||||||
{ :controller => 'attachments', :action => 'destroy', :id => '1' }
|
{ :controller => 'attachments', :action => 'destroy', :id => '1' }
|
||||||
|
|
|
@ -119,4 +119,24 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase
|
||||||
def test_macro_child_pages_without_wiki_page_should_fail
|
def test_macro_child_pages_without_wiki_page_should_fail
|
||||||
assert_match /can be called from wiki pages only/, textilizable("{{child_pages}}")
|
assert_match /can be called from wiki pages only/, textilizable("{{child_pages}}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_macro_thumbnail
|
||||||
|
assert_equal '<p><a href="/attachments/17" class="thumbnail" title="testfile.PNG"><img alt="testfile.PNG" src="/attachments/thumbnail/17" /></a></p>',
|
||||||
|
textilizable("{{thumbnail(testfile.png)}}", :object => Issue.find(14))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_macro_thumbnail_with_size
|
||||||
|
assert_equal '<p><a href="/attachments/17" class="thumbnail" title="testfile.PNG"><img alt="testfile.PNG" src="/attachments/thumbnail/17/200" /></a></p>',
|
||||||
|
textilizable("{{thumbnail(testfile.png, size=200)}}", :object => Issue.find(14))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_macro_thumbnail_with_title
|
||||||
|
assert_equal '<p><a href="/attachments/17" class="thumbnail" title="Cool image"><img alt="testfile.PNG" src="/attachments/thumbnail/17" /></a></p>',
|
||||||
|
textilizable("{{thumbnail(testfile.png, title=Cool image)}}", :object => Issue.find(14))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_macro_thumbnail_with_invalid_filename_should_fail
|
||||||
|
assert_include 'test.png not found',
|
||||||
|
textilizable("{{thumbnail(test.png)}}", :object => Issue.find(14))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue