From 1dfd53164e66f9c4de427c821c27c953b65bec80 Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Sun, 30 Aug 2026 14:45:10 +0900 Subject: [PATCH 1/2] Preview Adobe Illustrator files saved in the PDF compatible format --- app/controllers/attachments_controller.rb | 6 +++- app/models/attachment.rb | 13 +++++++ .../functional/attachments_controller_test.rb | 35 +++++++++++++++++++ test/unit/attachment_test.rb | 18 ++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 283803d7b..92cf7b760 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -58,7 +58,7 @@ class AttachmentsController < ApplicationController render :action => 'diff' elsif @attachment.is_image? render :action => 'image' - elsif @attachment.is_pdf? + elsif @attachment.pdf_previewable? render :action => 'pdf' elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte @content = File.read(@attachment.diskfile, :mode => "rb") @@ -299,6 +299,10 @@ class AttachmentsController < ApplicationController content_type = Redmine::MimeType.of(attachment.filename).presence || "application/octet-stream" + elsif Marcel::Magic.child?(content_type, "application/pdf") + # Send PDF compatible files, such as Illustrator files, as PDF so that + # browsers display them inline + content_type = "application/pdf" end if is_thumb && !content_type.start_with?("image/") diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 6ac97daf3..2d349f0e9 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -326,6 +326,19 @@ class Attachment < ApplicationRecord Redmine::MimeType.of(filename) == "application/pdf" end + # Returns true for attachments that can be previewed as PDF files, + # including PDF compatible files such as Adobe Illustrator + # (application/illustrator) + def pdf_previewable? + if content_type.blank? || content_type == 'application/octet-stream' + # The type of attachments created before Redmine started detecting the + # content type from the file contents can only be guessed from the name + is_pdf? + else + !!Marcel::Magic.child?(content_type, 'application/pdf') + end + end + def is_video? Redmine::MimeType.is_type?('video', filename) end diff --git a/test/functional/attachments_controller_test.rb b/test/functional/attachments_controller_test.rb index f2eefcb4a..4050dcaa9 100644 --- a/test/functional/attachments_controller_test.rb +++ b/test/functional/attachments_controller_test.rb @@ -406,6 +406,41 @@ class AttachmentsControllerTest < Redmine::ControllerTest assert_match %r{\Aattachment}, @response.headers['Content-Disposition'] end + def test_show_pdf_compatible_illustrator_file_should_be_previewed + set_tmp_attachments_directory + attachment = Attachment.create!( + :file => mock_file_with_options( + :original_filename => 'logo.ai', + :content => File.binread("#{Rails.root}/test/fixtures/files/hello.pdf") + ), + :author_id => 2, + :container => Issue.find(1) + ) + assert_equal 'application/illustrator', attachment.content_type + + get(:show, :params => {:id => attachment.id}) + assert_response :success + assert_select 'div.filecontent.pdf object[type=?]', 'application/pdf' + end + + def test_download_pdf_compatible_illustrator_file_should_be_sent_inline_as_pdf + set_tmp_attachments_directory + attachment = Attachment.create!( + :file => mock_file_with_options( + :original_filename => 'logo.ai', + :content => File.binread("#{Rails.root}/test/fixtures/files/hello.pdf") + ), + :author_id => 2, + :container => Issue.find(1) + ) + + get(:download, :params => {:id => attachment.id}) + assert_response :success + # Sent as PDF so that browsers display it inline + assert_equal 'application/pdf', @response.media_type + assert_match %r{\Ainline}, @response.headers['Content-Disposition'] + end + def test_download_version_file_with_issue_tracking_disabled Project.find(1).disable_module! :issue_tracking get(:download, :params => {:id => 9}) diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index 820feafde..9b6301c09 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -838,4 +838,22 @@ class AttachmentTest < ActiveSupport::TestCase assert_equal expected, Attachment.new(:filename => filename).is_pdf?, filename end end + + def test_pdf_previewable + to_test = { + ['application/pdf', 'report.pdf'] => true, + # PDF compatible Illustrator files are detected as application/illustrator + ['application/illustrator', 'logo.ai'] => true, + # Illustrator files saved in the PostScript format are not PDF files + ['application/postscript', 'logo.ai'] => false, + # The type of attachments created before Redmine started detecting the + # content type from the file contents can only be guessed from the name + ['application/octet-stream', 'report.pdf'] => true, + ['application/octet-stream', 'logo.ai'] => false, + } + to_test.each do |(content_type, filename), expected| + attachment = Attachment.new(:content_type => content_type, :filename => filename) + assert_equal expected, attachment.pdf_previewable?, "#{content_type} (#{filename})" + end + end end -- 2.55.0