From 549978d731ca1406e0f55a9d78ab6ee618486694 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 10 May 2016 15:06:51 +0200 Subject: [PATCH] Send inline images with cid (load images via http/https in src). --- app/controllers/getting_started_controller.rb | 10 +++---- app/controllers/settings_controller.rb | 2 +- app/controllers/tickets_controller.rb | 26 +++++++++++++++++-- app/models/channel/email_build.rb | 25 ++++++++++++++---- app/models/store.rb | 8 +++--- app/models/ticket/article.rb | 24 +++++++++++++++++ app/models/ticket/article/assets.rb | 14 ++++++++++ .../20160509000001_contenteditable_iamges.rb | 1 + lib/static_assets.rb | 2 +- 9 files changed, 94 insertions(+), 18 deletions(-) diff --git a/app/controllers/getting_started_controller.rb b/app/controllers/getting_started_controller.rb index 8b61226dd..0d5c0f751 100644 --- a/app/controllers/getting_started_controller.rb +++ b/app/controllers/getting_started_controller.rb @@ -129,7 +129,7 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password} # validate image if params[:logo] && params[:logo] =~ /^data:image/i - file = StaticAssets.data_url_attributes( params[:logo] ) + file = StaticAssets.data_url_attributes(params[:logo]) if !file[:content] || !file[:mime_type] messages[:logo] = 'Unable to process image upload.' @@ -163,19 +163,19 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password} if params[:logo] && params[:logo] =~ /^data:image/i # data:image/png;base64 - file = StaticAssets.data_url_attributes( params[:logo] ) + file = StaticAssets.data_url_attributes(params[:logo]) # store image 1:1 - StaticAssets.store_raw( file[:content], file[:mime_type] ) + StaticAssets.store_raw(file[:content], file[:mime_type]) end if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i # data:image/png;base64 - file = StaticAssets.data_url_attributes( params[:logo_resize] ) + file = StaticAssets.data_url_attributes(params[:logo_resize]) # store image 1:1 - settings[:product_logo] = StaticAssets.store( file[:content], file[:mime_type] ) + settings[:product_logo] = StaticAssets.store(file[:content], file[:mime_type]) end # set changed settings diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index a98b1faa0..4ea4557fc 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -67,7 +67,7 @@ class SettingsController < ApplicationController if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i # data:image/png;base64 - file = StaticAssets.data_url_attributes( params[:logo_resize] ) + file = StaticAssets.data_url_attributes(params[:logo_resize]) # store image 1:1 setting.state = StaticAssets.store( file[:content], file[:mime_type] ) diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb index 318bc0f4d..2a36a292d 100644 --- a/app/controllers/tickets_controller.rb +++ b/app/controllers/tickets_controller.rb @@ -250,7 +250,7 @@ class TicketsController < ApplicationController links.each { |item| link_list.push item if item['link_object'] == 'Ticket' - linked_ticket = Ticket.lookup( id: item['link_object_value'] ) + linked_ticket = Ticket.lookup(id: item['link_object_value']) assets = linked_ticket.assets(assets) end } @@ -534,9 +534,31 @@ class TicketsController < ApplicationController # create article if given form_id = params[:form_id] params.delete(:form_id) - article = Ticket::Article.new( Ticket::Article.param_validation( params ) ) + article = Ticket::Article.new(Ticket::Article.param_validation( params )) article.ticket_id = ticket.id + # store dataurl images to store + if form_id && article.body && article.content_type =~ %r{text/html}i + article.body.gsub!( %r{(}i ) { |_item| + file_attributes = StaticAssets.data_url_attributes($2) + cid = "#{ticket.id}.#{form_id}.#{rand(999_999)}@#{Setting.get('fqdn')}" + headers_store = { + 'Content-Type' => file_attributes[:mime_type], + 'Mime-Type' => file_attributes[:mime_type], + 'Content-ID' => cid, + 'Content-Disposition' => 'inline', + } + store = Store.add( + object: 'UploadCache', + o_id: form_id, + data: file_attributes[:content], + filename: cid, + preferences: headers_store + ) + "#{$1}cid:#{cid}\">" + } + end + # find attachments in upload cache if form_id article.attachments = Store.list( diff --git a/app/models/channel/email_build.rb b/app/models/channel/email_build.rb index 376e1d26c..e578bdf84 100644 --- a/app/models/channel/email_build.rb +++ b/app/models/channel/email_build.rb @@ -82,9 +82,23 @@ module Channel::EmailBuild if html_alternative html_container = Mail::Part.new { content_type 'multipart/related' } html_container.add_part html_alternative - alternative_bodies.add_part html_container # place to add inline attachments related to html alternative + if attr[:attachments] + attr[:attachments].each do |attachment| + next if attachment.class == Hash + next if attachment.preferences['Content-ID'].empty? + attachment = Mail::Part.new do + content_type attachment.preferences['Content-Type'] + content_id attachment.preferences['Content-ID'] + content_disposition attachment.preferences['Content-Disposition'] || 'inline' + content_transfer_encoding 'binary' + body attachment.content.force_encoding('BINARY') + end + html_container.add_part attachment + end + end + alternative_bodies.add_part html_container end mail.add_part alternative_bodies @@ -96,11 +110,12 @@ module Channel::EmailBuild attachment['content-id'] = nil mail.attachments[ attachment[:filename] ] = attachment else + next if !attachment.preferences['Content-ID'].empty? mail.attachments[attachment.filename] = { - :content_type => attachment.preferences['Content-Type'], - :mime_type => attachment.preferences['Mime-Type'], - :content => attachment.content, - 'content-id' => nil, + content_disposition: attachment.preferences['Content-Disposition'] || 'attachment', + content_type: attachment.preferences['Content-Type'], + mime_type: attachment.preferences['Mime-Type'], + content: attachment.content, } end end diff --git a/app/models/store.rb b/app/models/store.rb index 53418d336..4f3a6efcf 100644 --- a/app/models/store.rb +++ b/app/models/store.rb @@ -18,8 +18,8 @@ add an attachment to storage o_id: 4711, data: binary_string, preferences: { - :content_type => 'image/png', - :content_id => 234, + content_type: 'image/png', + content_id: 234, } ) @@ -69,8 +69,8 @@ returns size: 94123, filename: 'image.png', preferences: { - :content_type => 'image/png', - :content_id => 234, + content_type: 'image/png', + content_id: 234, } } store1.content # binary_string diff --git a/app/models/ticket/article.rb b/app/models/ticket/article.rb index b72848835..11ee02369 100644 --- a/app/models/ticket/article.rb +++ b/app/models/ticket/article.rb @@ -37,6 +37,30 @@ class Ticket::Article < ApplicationModel self.message_id_md5 = Digest::MD5.hexdigest(message_id.to_s) end + # insert inline image urls + def self.insert_urls(article, attachments) + inline_attachments = {} + article['body'].gsub!( /()/i ) { |item| + replace = item + + # look for attachment + attachments.each {|file| + next if !file.preferences['Content-ID'] || file.preferences['Content-ID'] != $3 + replace = "#{$1}/api/v1/ticket_attachment/#{article['ticket_id']}/#{article['id']}/#{file.id}#{$4}" + inline_attachments[file.id] = true + break + } + replace + } + new_attachments = [] + attachments.each {|file| + next if inline_attachments[file.id] + new_attachments.push file + } + article['attachments'] = new_attachments + article + end + private # strip not wanted chars diff --git a/app/models/ticket/article/assets.rb b/app/models/ticket/article/assets.rb index 8642d3d9c..9039bd066 100644 --- a/app/models/ticket/article/assets.rb +++ b/app/models/ticket/article/assets.rb @@ -39,6 +39,20 @@ returns # add attachment list to article data[ Ticket::Article.to_app_model ][ id ]['attachments'] = attachments + + if !data[ Ticket::Article.to_app_model ][ id ]['attachments'].empty? + if data[ Ticket::Article.to_app_model ][ id ]['content_type'] =~ %r{text/html}i + if data[ Ticket::Article.to_app_model ][ id ]['body'] =~ /