diff --git a/Gemfile b/Gemfile index 90735174..19c81d1e 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ source 'https://rubygems.org' do gem 'active_record_union' gem 'activestorage' + gem 'image_processing', '~> 1.2' gem 'ox' # Dav4Rack gem 'rake' unless Dir.exist?(File.expand_path('../../redmine_dashboard', __FILE__)) gem 'simple_enum' diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index d75689ac..2d72c16d 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -322,20 +322,6 @@ class DmsfFilesController < ApplicationController redirect_to trash_dmsf_path(@project) end - def thumbnail - tbnail = @file.thumbnail(size: params[:size]) - if tbnail - if stale?(etag: tbnail) - send_file tbnail, - filename: filename_for_content_disposition(@file.name), - type: @file.last_revision.content_type, - disposition: 'inline' - end - else - head :not_found - end - end - private def find_file diff --git a/app/helpers/dmsf_helper.rb b/app/helpers/dmsf_helper.rb index bd306c62..ce5d0070 100644 --- a/app/helpers/dmsf_helper.rb +++ b/app/helpers/dmsf_helper.rb @@ -34,7 +34,7 @@ module DmsfHelper def self.sanitize_filename(filename) # Get only the filename, not the whole path just_filename = File.basename(filename.gsub('\\\\', '/')) - # Replace all non alphanumeric, hyphens or periods with underscore + # Replace all non-alphanumeric, hyphens or periods with underscore just_filename.gsub!(/[^\w.\-]/, '_') # Keep the extension if any if !/^[a-zA-Z0-9_.\-]*$/.match?(just_filename) && just_filename =~ /(.[a-zA-Z0-9]+)$/ diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index 28fedc85..e5ccd629 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -546,7 +546,7 @@ class DmsfFile < ApplicationRecord end def thumbnailable? - Redmine::Thumbnail.convert_available? && (image? || (pdf? && Redmine::Thumbnail.gs_available?)) + last_revision.file&.variable? end def previewable? @@ -632,29 +632,6 @@ class DmsfFile < ApplicationRecord nil end - def thumbnail(options = {}) - size = options[:size].to_i - if size.positive? - # 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.positive? - target = File.join(Attachment.thumbnails_storage_path, "#{id}_#{last_revision.digest}_#{size}.thumb") - begin - Redmine::Thumbnail.generate last_revision.file.download, target, size, pdf? - rescue StandardError => e - Rails.logger.error do - %(An error occured while generating thumbnail for #{last_revision.file&.blob&.filename} to #{target}\n - Exception was: #{e.message}) - end - nil - end - end - def locked_title if locked_for_user? return l(:title_locked_by_user, user: lock.reverse[0].user) if lock.reverse[0].user diff --git a/app/views/dmsf_files/_thumbnails.html.erb b/app/views/dmsf_files/_thumbnails.html.erb index 3ffb90c9..d8aa7a58 100644 --- a/app/views/dmsf_files/_thumbnails.html.erb +++ b/app/views/dmsf_files/_thumbnails.html.erb @@ -25,12 +25,20 @@
#{image_tag(url, alt: @file7.name, title: @file7.title, width: size, height: size)}
", text + # TODO: Swaped parameters src and size # size = '300' # text = textilizable("{{dmsf_image(#{@file7.id}, size=#{size})}}") - # assert text.include?(image_tag(url, alt: @file7.name, title: @file7.title, width: size, height: size)), text - # TODO: arguments src and with and height are swapped + # assert_equal "#{image_tag(url, alt: @file7.name, title: @file7.title, width: size, height: size)}
", text # size = '640x480' # text = textilizable("{{dmsf_image(#{@file7.id}, size=#{size})}}") - # assert text.include?(image_tag(url, alt: @file7.name, title: @file7.title, width: '640', height: '480')), text + # assert_equal "#{image_tag(url, alt: @file7.name, title: @file7.title, width: '640', height: '480')}
", + # text height = '480' text = textilizable("{{dmsf_image(#{@file7.id}, height=#{height})}}") - assert text.include?(image_tag(url, alt: @file7.name, title: @file7.title, width: 'auto', height: height)), text + assert_equal "#{image_tag(url, alt: @file7.name, title: @file7.title, width: 'auto', height: height)}
", + text width = '480' text = textilizable("{{dmsf_image(#{@file7.id}, width=#{height})}}") - assert text.include?(image_tag(url, alt: @file7.name, title: @file7.title, width: width, height: 'auto')), text + assert_equal "#{image_tag(url, alt: @file7.name, title: @file7.title, width: width, height: 'auto')}
", + text end def test_macro_dmsf_image_no_permissions @@ -344,74 +346,86 @@ class DmsfMacrosTest < RedmineDmsf::Test::HelperTest def test_macro_dmsftn text = textilizable("{{dmsftn(#{@file7.id})}}") url = static_dmsf_file_url(@file7, @file7.last_revision.name) - img = image_tag(url, alt: @file7.name, title: @file7.title, width: 'auto', height: 200) + size = Setting.thumbnails_size.to_i + img = image_tag(@file7.last_revision&.file&.variant(resize_to_limit: [size, size]), + alt: @file7.name, + style: "max-width: #{size}px; max-height: #{size}px;", + loading: 'lazy') link = link_to(img, url, target: '_blank', rel: 'noopener', title: h(@file7.last_revision.try(:tooltip)), 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}") - assert text.include?(link), text + assert_equal "#{link}
", text end # {{dmsftn(file_id file_id)}} def test_macro_dmsftn_multiple text = textilizable("{{dmsftn(#{@file7.id} #{@file7.id})}}") url = static_dmsf_file_url(@file7, @file7.last_revision.name) - img = image_tag(url, alt: @file7.name, title: @file7.title, width: 'auto', height: 200) + img = image_tag(@file7.last_revision&.file&.variant(resize_to_limit: [100, 100]), + alt: @file7.name, + style: 'max-width: 100px; max-height: 100px;', + loading: 'lazy') link = link_to(img, url, target: '_blank', rel: 'noopener', title: h(@file7.last_revision.try(:tooltip)), 'data-downloadurl': 'image/gif:test.gif:http://www.example.com/dmsf/files/7/test.gif') - assert text.include?(link + link), text + assert_equal "#{link}#{link}
", text end # {{dmsftn(file_id size=300)}} def test_macro_dmsftn_size url = static_dmsf_file_url(@file7, @file7.last_revision.name) - size = '300' - text = textilizable("{{dmsftn(#{@file7.id}, size=#{size})}}") - img = image_tag(url, alt: @file7.name, title: @file7.title, size: size) + size = Setting.thumbnails_size.to_i + + # Size + text = textilizable("{{dmsftn(#{@file7.id}, size=300)}}") + img = image_tag(@file7.last_revision&.file&.variant(resize_to_limit: [300, 300]), + alt: @file7.name, + style: 'max-width: 300px; max-height: 300px;', + loading: 'lazy') link = link_to(img, url, target: '_blank', rel: 'noopener', title: h(@file7.last_revision.try(:tooltip)), 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}") - assert text.include?(link), text - # TODO: arguments src and with and height are swapped - # size = '640x480' - # text = textilizable("{{dmsftn(#{@file7.id}, size=#{size})}}") - # img = image_tag(url, alt: @file7.name, title: @file7.title, width: 640, height: 480) - # link = link_to(img, - # url, - # target: '_blank', - # rel: 'noopener', - # title: h(@file7.last_revision.try(:tooltip)), - # 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}") - # assert text.include?(link), text - height = '480' - text = textilizable("{{dmsftn(#{@file7.id}, height=#{height})}}") - img = image_tag(url, alt: @file7.name, title: @file7.title, width: 'auto', height: 480) - link = link_to(img, - url, - target: '_blank', - rel: 'noopener', - title: h(@file7.last_revision.try(:tooltip)), - 'data-downloadurl': 'image/gif:test.gif:http://www.example.com/dmsf/files/7/test.gif') - assert text.include?(link), text - width = '640' - text = textilizable("{{dmsftn(#{@file7.id}, width=#{width})}}") - img = image_tag(url, alt: @file7.name, title: @file7.title, width: 640, height: 'auto') + assert_equal "#{link.gsub(/redirect\/.*\/#{@file7.name}/, '...')}
", + text.gsub(/redirect\/.*\/#{@file7.name}/, '...') + + # Height + text = textilizable("{{dmsftn(#{@file7.id}, height=480)}}") + img = image_tag(@file7.last_revision&.file&.variant(resize_to_limit: [size, 480]), + alt: @file7.name, + style: "max-width: #{size}px; max-height: 480px;", + loading: 'lazy') link = link_to(img, url, target: '_blank', rel: 'noopener', title: h(@file7.last_revision.try(:tooltip)), 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}") - assert text.include?(link), text + assert_equal "#{link.gsub(/redirect\/.*\/#{@file7.name}/, '...')}
", + text.gsub(/redirect\/.*\/#{@file7.name}/, '...') + + # Width + text = textilizable("{{dmsftn(#{@file7.id}, width=640)}}") + img = image_tag(@file7.last_revision&.file&.variant(resize_to_limit: [640, size]), + alt: @file7.name, + style: "max-width: 640px; max-height: #{size}px;", + loading: 'lazy') + link = link_to(img, + url, + target: '_blank', + rel: 'noopener', + title: h(@file7.last_revision.try(:tooltip)), + 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}") + assert_equal "#{link.gsub(/redirect\/.*\/#{@file7.name}/, '...')}
", + text.gsub(/redirect\/.*\/#{@file7.name}/, '...') end def test_macro_dmsftn_no_permissions