forked from zammad/zammad
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Maintenance: Enhance attachment preview capabilities
- Loading branch information
1 parent
7dbd1c1
commit acc93a2
Showing
8 changed files
with
340 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/ | ||
|
||
module ApplicationController::HasDownload | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
around_action do |_controller, block| | ||
|
||
subscriber = proc do | ||
policy = ActionDispatch::ContentSecurityPolicy.new | ||
policy.default_src :none | ||
|
||
# The 'plugin_types' rule is deprecated and should be changed in the future. | ||
policy.plugin_types 'application/pdf' | ||
|
||
request.content_security_policy = policy | ||
end | ||
|
||
ActiveSupport::Notifications.subscribed(subscriber, 'send_file.action_controller') do | ||
ActiveSupport::Notifications.subscribed(subscriber, 'send_data.action_controller') do | ||
block.call | ||
end | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def file_id | ||
@file_id ||= params[:id] | ||
end | ||
|
||
def download_file | ||
@download_file ||= ::ApplicationController::HasDownload::DownloadFile.new(file_id, disposition: sanitized_disposition) | ||
end | ||
|
||
def sanitized_disposition | ||
disposition = params.fetch(:disposition, 'inline') | ||
valid_disposition = %w[inline attachment] | ||
return disposition if valid_disposition.include?(disposition) | ||
|
||
raise Exceptions::Forbidden, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid." | ||
end | ||
end |
54 changes: 54 additions & 0 deletions
54
app/controllers/application_controller/has_download/download_file.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/ | ||
|
||
class ApplicationController::HasDownload::DownloadFile < SimpleDelegator | ||
attr_reader :requested_disposition | ||
|
||
def initialize(id, disposition: 'inline') | ||
@requested_disposition = disposition | ||
|
||
super(Store.find(id)) | ||
end | ||
|
||
def disposition | ||
return 'attachment' if forcibly_download_as_binary? || !allowed_inline? | ||
|
||
requested_disposition | ||
end | ||
|
||
def content_type | ||
return ActiveStorage.binary_content_type if forcibly_download_as_binary? | ||
|
||
file_content_type | ||
end | ||
|
||
def content(view_type) | ||
return __getobj__.content if view_type.blank? || !preferences[:resizable] | ||
|
||
return content_inline if content_inline? && view_type == 'inline' | ||
return content_preview if content_preview? && view_type == 'preview' | ||
|
||
__getobj__.content | ||
end | ||
|
||
private | ||
|
||
def allowed_inline? | ||
ActiveStorage.content_types_allowed_inline.include?(content_type) | ||
end | ||
|
||
def forcibly_download_as_binary? | ||
ActiveStorage.content_types_to_serve_as_binary.include?(file_content_type) | ||
end | ||
|
||
def file_content_type | ||
@file_content_type ||= preferences['Content-Type'] || preferences['Mime-Type'] || ActiveStorage.binary_content_type | ||
end | ||
|
||
def content_inline? | ||
preferences[:content_inline] == true | ||
end | ||
|
||
def content_preview? | ||
preferences[:content_preview] == true | ||
end | ||
end |
25 changes: 0 additions & 25 deletions
25
app/controllers/application_controller/has_secure_content_security_policy_for_downloads.rb
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
spec/controllers/application_controller/has_download/download_file_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/ | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe ApplicationController::HasDownload::DownloadFile do | ||
subject(:download_file) { described_class.new(stored_file.id, disposition: 'inline') } | ||
|
||
let(:file_content_type) { 'application/pdf' } | ||
let(:file_data) { 'A example file.' } | ||
let(:file_name) { 'example.pdf' } | ||
|
||
let(:stored_file) do | ||
Store.add( | ||
object: 'Ticket', | ||
o_id: 1, | ||
data: file_data, | ||
filename: file_name, | ||
preferences: { | ||
'Content-Type' => file_content_type, | ||
}, | ||
created_by_id: 1, | ||
) | ||
end | ||
|
||
describe '#disposition' do | ||
context "with given object dispostion 'inline'" do | ||
context 'with allowed inline content type (from ActiveStorage.content_types_allowed_inline)' do | ||
it 'disposition is inline' do | ||
expect(download_file.disposition).to eq('inline') | ||
end | ||
end | ||
|
||
context 'with binary content type (ActiveStorage.content_types_to_serve_as_binary)' do | ||
let(:file_content_type) { 'image/svg+xml' } | ||
|
||
it 'disposition forced to attachment' do | ||
expect(download_file.disposition).to eq('attachment') | ||
end | ||
end | ||
end | ||
|
||
context "with given object dispostion 'attachment'" do | ||
subject(:download_file) { described_class.new(stored_file.id, disposition: 'attachment') } | ||
|
||
it 'disposition is attachment' do | ||
expect(download_file.disposition).to eq('attachment') | ||
end | ||
end | ||
end | ||
|
||
describe '#content_type' do | ||
context 'with none binary content type' do | ||
it 'check content type' do | ||
expect(download_file.content_type).to eq('application/pdf') | ||
end | ||
end | ||
|
||
context 'with forced active storage binary content type' do | ||
let(:file_content_type) { 'image/svg+xml' } | ||
|
||
it 'check content type' do | ||
expect(download_file.content_type).to eq('application/octet-stream') | ||
end | ||
end | ||
end | ||
|
||
describe '#content' do | ||
context 'with not resizable file' do | ||
it 'check that normal content will be returned' do | ||
expect(download_file.content('preview')).to eq('A example file.') | ||
end | ||
end | ||
|
||
context 'with image content type' do | ||
let(:file_content_type) { 'image/jpg' } | ||
let(:file_data) { File.binread(Rails.root.join('test/data/upload/upload2.jpg')) } | ||
let(:file_name) { 'image.jpg' } | ||
|
||
it 'check that inline content will be returned' do | ||
expect(download_file.content('inline')).to not_eq(file_data) | ||
end | ||
|
||
it 'check that preview content will be returned' do | ||
expect(download_file.content('preview')).to not_eq(file_data) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.