#1502 Text and Markdown files' preview

This commit is contained in:
Karel Pičman 2024-05-22 14:57:42 +02:00
parent 79bc188c75
commit a88d65cd5b
8 changed files with 136 additions and 9 deletions

View File

@ -74,11 +74,18 @@ class DmsfFilesController < ApplicationController
member = Member.find_by(user_id: User.current.id, project_id: @file.project.id)
# IE has got a tendency to cache files
expires_in 0.years, 'must-revalidate' => true
# PDF preview
pdf_preview = (params[:disposition] != 'attachment') && params[:filename].blank? && @file.pdf_preview
filename = filename_for_content_disposition(@revision.formatted_name(member))
if pdf_preview.present? && (Setting.plugin_redmine_dmsf['office_bin'].present? || params[:preview].present?)
basename = File.basename(filename, '.*')
send_file pdf_preview, filename: "#{basename}.pdf", type: 'application/pdf', disposition: 'inline'
# Text preview
elsif params[:download].blank? && (@file.size <= Setting.file_max_size_displayed.to_i.kilobyte) &&
(@file.text? || @file.markdown? || @file.textile?)
@content = File.read(@revision.disk_file, mode: 'rb')
render action: 'document'
# Offer the file for download
else
params[:disposition] = 'attachment' if params[:filename].present?
send_file @revision.disk_file,

View File

@ -27,4 +27,14 @@ module DmsfFilesHelper
.gsub("\n\n", '<br>')
.gsub("\n\t", '<br>')
end
def render_document_content(dmsf_file, content)
if dmsf_file.markdown?
render partial: 'common/markup', locals: { markup_text_formatting: markdown_formatter, markup_text: content }
elsif dmsf_file.textile?
render partial: 'common/markup', locals: { markup_text_formatting: 'textile', markup_text: content }
else
render partial: 'common/file', locals: { content: content, filename: dmsf_file.name }
end
end
end

View File

@ -186,14 +186,15 @@ module DmsfQueriesHelper
file_view_url = url_for(
{ controller: :dmsf_files, action: 'view', id: item.type == 'file' ? item.id : item.revision_id }
)
content_type = Redmine::MimeType.of(value)
content_type = Redmine::MimeType.of(item.filename)
content_type = 'application/octet-stream' if content_type.blank?
tag = link_to(h(value),
file_view_url,
target: '_blank',
rel: 'noopener',
class: "icon icon-file #{DmsfHelper.filetype_css(item.filename)}",
'data-downloadurl': "#{content_type}:#{h(value)}:#{file_view_url}")
options = { class: "icon icon-file #{DmsfHelper.filetype_css(item.filename)}",
'data-downloadurl': "#{content_type}:#{h(value)}:#{file_view_url}" }
unless previewable?(item.filename, content_type)
options[:target] = '_blank'
options[:rel] = 'noopener'
end
tag = link_to h(value), file_view_url, options
tag = content_tag('span', '', class: 'dmsf-expander') + tag unless filter_any?
end
member = Member.find_by(user_id: User.current.id, project_id: item.project_id)
@ -279,4 +280,13 @@ module DmsfQueriesHelper
end
false
end
def previewable?(filename, content_type)
case content_type
when 'text/markdown', 'text/x-textile'
true
else
Redmine::MimeType.is_type?('text', filename) || Redmine::SyntaxHighlighting.filename_supported?(filename)
end
end
end

View File

@ -465,7 +465,9 @@ class DmsfFile < ApplicationRecord
end
def text?
Redmine::MimeType.is_type?('text', last_revision&.disk_filename)
filename = last_revision&.disk_filename
Redmine::MimeType.is_type?('text', filename) ||
Redmine::SyntaxHighlighting.filename_supported?(filename)
end
def image?
@ -495,6 +497,14 @@ class DmsfFile < ApplicationRecord
end
end
def markdown?
Redmine::MimeType.of(last_revision&.disk_filename) == 'text/markdown'
end
def textile?
Redmine::MimeType.of(last_revision&.disk_filename) == 'text/x-textile'
end
def disposition
image? || pdf? || video? || html? ? 'inline' : 'attachment'
end
@ -504,7 +514,7 @@ class DmsfFile < ApplicationRecord
end
def previewable?
office_doc? && RedmineDmsf::Preview.office_available?
office_doc? && RedmineDmsf::Preview.office_available? && size <= Setting.file_max_size_displayed.to_i.kilobyte
end
# Deletes all previews

View File

@ -0,0 +1,23 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render layout: 'layouts/document' do %>&nbsp;
<%= render_document_content @file, @content %>
<% end %>

View File

@ -0,0 +1,47 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<div class="contextual">
<%= link_to "#{l(:button_download)} (#{number_to_human_size(@file.size)})",
static_dmsf_file_path(@file, download: @file.last_revision, filename: @file.last_revision.disk_filename),
class: 'icon icon-download', disabled: false %>
</div>
<h2>
<%= render partial: '/dmsf/path', locals: { folder: @file.dmsf_folder, filename: @file.title, title: nil } %>
</h2>
<div class="attachments">
<p>
<%= @file.description %>
<span class="author">
<%= link_to_user @file.last_revision.user %>, <%= format_time @file.last_revision.updated_at %>
</span>
</p>
</div>
<div class="filecontent-container">
<%= yield %>
</div>
<% html_title @file.name %>
<% content_for :header_tags do %>
<%= stylesheet_link_tag 'scm' %>
<% end %>

View File

@ -42,4 +42,10 @@ class DmsfQueriesHelperTest < RedmineDmsf::Test::HelperTest
c_size = QueryColumn.new(:size)
assert_equal '1 KB', csv_value(c_size, @folder1, 1024)
end
def test_previewable
assert previewable?('file.txt', 'text/plain')
assert previewable?('main.c', 'text/x-csrc')
assert_not previewable?('document.odt', 'application/vnd.oasis.opendocument.text')
end
end

View File

@ -213,6 +213,8 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
assert @file1.text?
assert_not @file7.text?
assert_not @file8.text?
@file1.last_revision.disk_filename = 'test.c'
assert @file1.text?
end
def test_pdf
@ -233,6 +235,18 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
assert @file1.html?
end
def test_markdown
assert_not @file1.markdown?
@file1.last_revision.disk_filename = 'test.md'
assert @file1.markdown?
end
def test_textile
assert_not @file1.textile?
@file1.last_revision.disk_filename = 'test.textile'
assert @file1.textile?
end
def test_findn_file_by_name
assert DmsfFile.find_file_by_name(@project1, nil, 'test.txt')
assert_nil DmsfFile.find_file_by_name(@project1, nil, 'test.ods')