diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 25c1bf1bc87..6720cd18514 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -69,13 +69,17 @@ class Attachment < ApplicationRecord # Returns an URL if the attachment is stored in an external (fog) attachment storage # or nil otherwise. def external_url(expires_in: nil) - url = URI.parse file.download_url(content_disposition: content_disposition, expires_in: expires_in) # returns a path if local + url = URI.parse file.download_url(external_url_options) # returns a path if local url if url.host rescue URI::InvalidURIError nil end + def external_url_options(expires_in: nil) + { content_disposition: content_disposition(include_filename: false), expires_in: expires_in } + end + def external_storage? !external_url.nil? end @@ -89,10 +93,14 @@ class Attachment < ApplicationRecord container.respond_to?(:project) ? container.project : nil end - def content_disposition - # Do not use filename with attachment as this may break for Unicode files - # specifically when using S3 for attachments. - inlineable? ? "inline" : "attachment" + def content_disposition(include_filename: true) + return "inline" if inlineable? + + if include_filename + "attachment; filename=#{attachment.filename}" + else + "attachment" + end end def visible?(user = User.current) diff --git a/lib/api/helpers/attachment_renderer.rb b/lib/api/helpers/attachment_renderer.rb index 08735cfe2a6..40d1d6ff08e 100644 --- a/lib/api/helpers/attachment_renderer.rb +++ b/lib/api/helpers/attachment_renderer.rb @@ -76,7 +76,7 @@ module API def send_attachment(attachment) content_type attachment.content_type - header['Content-Disposition'] = "#{attachment.content_disposition}; filename=#{attachment.filename}" + header['Content-Disposition'] = attachment.content_disposition env['api.format'] = :binary sendfile attachment.diskfile.path end diff --git a/modules/bim/lib/open_project/bim/engine.rb b/modules/bim/lib/open_project/bim/engine.rb index 1c1a6f8adcc..e94a680208a 100644 --- a/modules/bim/lib/open_project/bim/engine.rb +++ b/modules/bim/lib/open_project/bim/engine.rb @@ -97,7 +97,7 @@ module OpenProject::Bim assets %w(bim/logo_openproject_bim_big.png) - patches %i[WorkPackage Type Journal RootSeeder Project FogFileUploader] + patches %i[Attachment WorkPackage Type Journal RootSeeder Project FogFileUploader] patch_with_namespace :OpenProject, :CustomStyles, :ColorThemes patch_with_namespace :API, :V3, :Activities, :ActivityRepresenter diff --git a/modules/bim/lib/open_project/bim/patches/attachment_patch.rb b/modules/bim/lib/open_project/bim/patches/attachment_patch.rb new file mode 100644 index 00000000000..80e7c0c486e --- /dev/null +++ b/modules/bim/lib/open_project/bim/patches/attachment_patch.rb @@ -0,0 +1,61 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2021 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# 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. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module OpenProject::Bim::Patches::AttachmentPatch + def self.included(base) # :nodoc: + base.prepend InstanceMethods + end + + module InstanceMethods + def external_url_options(expires_in: nil) + return super unless ifc_model? + + super.merge content_disposition: ifc_content_disposition + end + + def content_disposition(include_filename: true) + return super unless ifc_model? && include_filename + + ifc_content_disposition + end + + def ifc_model? + container_type == Bim::IfcModels::IfcModel.name && container.present? + end + + def ifc_content_disposition + "attachment; filename=#{ifc_file_name}" + end + + def ifc_file_name + title = container.title.sub /\.ifc\Z/, '' + + title.to_localized_slug(:en) + ".ifc" + end + end +end