Merge pull request #1798 from biosistemika/jg_sci_3145_thumbnail_preview

File preview on new attachments layout [SCI-3145]
This commit is contained in:
Jure Grabnar 2019-06-10 17:59:12 +02:00 committed by GitHub
commit bbfe2b9c89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 130 additions and 53 deletions

View file

@ -1,8 +1,16 @@
FROM ruby:2.5.5
MAINTAINER BioSistemika <info@biosistemika.com>
# Get version of Debian (lsb_release substitute) and save it to /tmp/lsb_release for further commands
RUN cat /etc/os-release | grep -Po "VERSION=.*\(\K\w+" | tee /tmp/lsb_release
# Add Debian stretch backports repository
RUN echo "deb http://http.debian.net/debian $(cat /tmp/lsb_release)-backports main" \
| tee /etc/apt/sources.list.d/$(cat /tmp/lsb_release)-backports.list
# additional dependecies
# libSSL-1.0 is required by wkhtmltopdf binary
# libreoffice for file preview generation
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
@ -14,6 +22,7 @@ RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
unison \
sudo graphviz --no-install-recommends \
libfile-mimeinfo-perl && \
apt-get install -y --no-install-recommends -t $(cat /tmp/lsb_release)-backports libreoffice && \
npm install -g yarn && \
rm -rf /var/lib/apt/lists/*

View file

@ -1,8 +1,11 @@
FROM ruby:2.5.5
MAINTAINER BioSistemika <info@biosistemika.com>
RUN echo deb "http://http.debian.net/debian stretch-backports main" >> /etc/apt/sources.list
# additional dependecies
# libSSL-1.0 is required by wkhtmltopdf binary
# libreoffice for file preview generation
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
@ -16,6 +19,7 @@ RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
default-jre-headless \
sudo graphviz --no-install-recommends \
libfile-mimeinfo-perl && \
apt-get install -y --no-install-recommends -t stretch-backports libreoffice && \
npm install -g yarn && \
rm -rf /var/lib/apt/lists/*

View file

@ -79,8 +79,8 @@ gem 'underscore-rails'
gem 'wicked_pdf', '~> 1.1.0'
gem 'wkhtmltopdf-heroku'
gem 'aws-sdk', '~> 2'
gem 'paperclip', '~> 5.3' # File attachment, image attachment library
gem 'aws-sdk-s3'
gem 'paperclip', '~> 6.1' # File attachment, image attachment library
gem 'delayed_job_active_record'
gem 'devise-async',
git: 'https://github.com/mhfs/devise-async.git',

View file

@ -102,13 +102,19 @@ GEM
rails (>= 3.1)
awesome_print (1.8.0)
aws-eventstream (1.0.3)
aws-sdk (2.11.264)
aws-sdk-resources (= 2.11.264)
aws-sdk-core (2.11.264)
aws-sigv4 (~> 1.0)
aws-partitions (1.172.0)
aws-sdk-core (3.54.2)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-resources (2.11.264)
aws-sdk-core (= 2.11.264)
aws-sdk-kms (1.21.0)
aws-sdk-core (~> 3, >= 3.53.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.42.0)
aws-sdk-core (~> 3, >= 3.53.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.0)
aws-eventstream (~> 1.0, >= 1.0.2)
backports (3.14.0)
@ -334,7 +340,7 @@ GEM
overcommit (0.47.0)
childprocess (~> 0.6, >= 0.6.3)
iniparse (~> 1.4)
paperclip (5.3.0)
paperclip (6.1.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
mime-types
@ -552,7 +558,7 @@ DEPENDENCIES
auto_strip_attributes (~> 2.1)
autosize-rails
awesome_print
aws-sdk (~> 2)
aws-sdk-s3
base62
bcrypt (~> 3.1.10)
better_errors
@ -601,7 +607,7 @@ DEPENDENCIES
omniauth
omniauth-linkedin-oauth2
overcommit
paperclip (~> 5.3)
paperclip (~> 6.1)
pg (~> 0.18)
pg_search
phantomjs

View file

@ -10,16 +10,34 @@ class Asset < ApplicationRecord
# Paperclip validation
has_attached_file :file,
styles: {
large: [Constants::LARGE_PIC_FORMAT, :jpg],
medium: [Constants::MEDIUM_PIC_FORMAT, :jpg],
original: { processors: [:image_quality_calculate] }
styles: lambda { |a|
if a.previewable_document?
{
large: { processors: [:custom_file_preview],
geometry: Constants::LARGE_PIC_FORMAT,
format: :jpg },
medium: { processors: [:custom_file_preview],
geometry: Constants::MEDIUM_PIC_FORMAT,
format: :jpg }
}
else
{
large: [Constants::LARGE_PIC_FORMAT, :jpg],
medium: [Constants::MEDIUM_PIC_FORMAT, :jpg]
}
end
},
convert_options: {
medium: '-quality 70 -strip',
all: '-background "#d2d2d2" -flatten +matte'
}
before_post_process :previewable?
before_post_process :extract_image_quality
# adds image processing in background job
process_in_background :file, processing_image_url: '/images/:style/processing.gif'
validates_attachment :file,
presence: true,
size: {
@ -31,20 +49,6 @@ class Asset < ApplicationRecord
# Should be checked for any security leaks
do_not_validate_attachment_file_type :file
# adds image processing in background job
process_in_background :file,
only_process: lambda { |a|
if a.content_type ==
%r{^image/#{ Regexp.union(
Constants::WHITELISTED_IMAGE_TYPES
) }}
%i(large medium original)
else
{}
end
},
processing_image_url: '/images/:style/processing.gif'
# Asset validation
# This could cause some problems if you create empty asset and want to
# assign it to result
@ -196,6 +200,22 @@ class Asset < ApplicationRecord
end
end
def extract_image_quality
return unless ['image/jpeg', 'image/pjpeg'].include? file_content_type
tempfile = file.queued_for_write[:original]
unless tempfile.nil?
quality = Paperclip::Processor.new(tempfile).identify(" -format '%Q' #{tempfile.path}")
self.file_image_quality = quality.to_i
end
rescue StandardError => e
Rails.logger.info "There was an error extracting image quality - #{e}"
end
def previewable?
file.previewable_image? || file.previewable_document?
end
def is_image?
%r{^image/#{Regexp.union(Constants::WHITELISTED_IMAGE_TYPES)}} ===
file.content_type

View file

@ -1,4 +1,8 @@
<div>
<i class="fas fa-10x <%= file_fa_icon_class(asset) %>"></i>
<% if asset.file.previewable_document? %>
<%= image_tag(asset.url(:large)) %>
<% else %>
<i class="fas fa-10x <%= file_fa_icon_class(asset) %>"></i>
<% end %>
<h3 class="file-name"></h3>
</div>

View file

@ -1,4 +1,4 @@
<% if asset.file.processing? && asset.is_image? %>
<% if asset.file.processing? && (asset.is_image? || asset.file.previewable_document?) %>
<% asset_status = 'asset-loading' %>
<% present_url = step_file_present_asset_path(asset.id) %>
<% else %>

View file

@ -1,4 +1,4 @@
<% image_preview = asset.is_image? ? asset.url(:medium) : nil %>
<% image_preview = (asset.is_image? || asset.file.previewable_document?) ? asset.url(:medium) : nil %>
<div class="attachment-placeholder pull-left">
<div class="attachment-thumbnail <%= image_preview ? '' : 'no-shadow' %>">

View file

@ -218,6 +218,8 @@ class Constants
'text/plain'
].freeze
PREVIEWABLE_FILE_TYPES = TEXT_EXTRACT_FILE_TYPES
WHITELISTED_IMAGE_TYPES = [
'gif', 'jpeg', 'pjpeg', 'png', 'x-png', 'svg+xml', 'bmp', 'tiff'
].freeze

View file

@ -61,6 +61,27 @@ Paperclip::Attachment.class_eval do
def fetch
Paperclip.io_adapters.for self
end
def previewable_document?
previewable = Constants::PREVIEWABLE_FILE_TYPES.include?(content_type)
extensions = %w(.xlsx .docx .pptx .xls .doc .ppt)
# Mimetype sometimes recognizes Office files as zip files
# In this case we also check the extension of the given file
# Otherwise the conversion should fail if the file is being something else
previewable ||= (content_type == 'application/zip' && extensions.include?(File.extname(original_filename)))
# Mimetype also sometimes recognizes '.xls' and '.ppt' files as
# application/x-ole-storage (https://github.com/minad/mimemagic/issues/50)
previewable ||=
(content_type == 'application/x-ole-storage' && %w(.xls .ppt).include?(File.extname(original_filename)))
previewable
end
def previewable_image?
content_type =~ %r{^image/#{Regexp.union(Constants::WHITELISTED_IMAGE_TYPES)}}
end
end
module Paperclip

View file

@ -1,21 +0,0 @@
# frozen_string_literal: true
module Paperclip
class ImageQualityCalculate < Processor
def initialize(file, options = {}, attachment = nil)
super
end
def make
if @file && (['image/jpeg', 'image/pjpeg'].include? @file.content_type)
quality = Paperclip::Processor.new(@file).identify(" -format '%Q' #{@file.path}")
@attachment.instance.file_image_quality = quality.to_i
# Asset will be save after all processors finished
end
# We need again open file after read quality
File.new(File.expand_path(@file.path))
rescue StandardError => e
raise Paperclip::Error, "There was an error processing the image - #{e}"
end
end
end

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Paperclip
class CustomFilePreview < Processor
def make
libreoffice_path = ENV['LIBREOFFICE_PATH'] || 'libreoffice'
directory = File.dirname(@file.path)
basename = File.basename(@file.path, '.*')
original_preview_file = File.join(directory, "#{basename}.png")
dst = TempfileFactory.new.generate("#{basename}.#{options[:format]}")
begin
Paperclip.run(
libreoffice_path,
"--headless --invisible --convert-to png --outdir #{directory} #{@file.path}"
)
convert(
":source -resize '#{options[:geometry]}' -format #{options[:format]} #{options[:convert_options]} :dest",
source: File.expand_path(original_preview_file),
dest: File.expand_path(dst.path)
)
ensure
File.delete(original_preview_file) if File.file?(original_preview_file)
end
dst
rescue StandardError => e
raise Paperclip::Error, "There was an error generating document preview - #{e}"
end
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB