Send inline images with cid (load images via http/https in src).
This commit is contained in:
parent
530c844f68
commit
549978d731
9 changed files with 94 additions and 18 deletions
|
@ -129,7 +129,7 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
|
||||||
# validate image
|
# validate image
|
||||||
if params[:logo] && params[:logo] =~ /^data:image/i
|
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]
|
if !file[:content] || !file[:mime_type]
|
||||||
messages[:logo] = 'Unable to process image upload.'
|
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
|
if params[:logo] && params[:logo] =~ /^data:image/i
|
||||||
|
|
||||||
# data:image/png;base64
|
# data:image/png;base64
|
||||||
file = StaticAssets.data_url_attributes( params[:logo] )
|
file = StaticAssets.data_url_attributes(params[:logo])
|
||||||
|
|
||||||
# store image 1:1
|
# store image 1:1
|
||||||
StaticAssets.store_raw( file[:content], file[:mime_type] )
|
StaticAssets.store_raw(file[:content], file[:mime_type])
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i
|
if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i
|
||||||
|
|
||||||
# data:image/png;base64
|
# data:image/png;base64
|
||||||
file = StaticAssets.data_url_attributes( params[:logo_resize] )
|
file = StaticAssets.data_url_attributes(params[:logo_resize])
|
||||||
|
|
||||||
# store image 1:1
|
# 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
|
end
|
||||||
|
|
||||||
# set changed settings
|
# set changed settings
|
||||||
|
|
|
@ -67,7 +67,7 @@ class SettingsController < ApplicationController
|
||||||
if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i
|
if params[:logo_resize] && params[:logo_resize] =~ /^data:image/i
|
||||||
|
|
||||||
# data:image/png;base64
|
# data:image/png;base64
|
||||||
file = StaticAssets.data_url_attributes( params[:logo_resize] )
|
file = StaticAssets.data_url_attributes(params[:logo_resize])
|
||||||
|
|
||||||
# store image 1:1
|
# store image 1:1
|
||||||
setting.state = StaticAssets.store( file[:content], file[:mime_type] )
|
setting.state = StaticAssets.store( file[:content], file[:mime_type] )
|
||||||
|
|
|
@ -250,7 +250,7 @@ class TicketsController < ApplicationController
|
||||||
links.each { |item|
|
links.each { |item|
|
||||||
link_list.push item
|
link_list.push item
|
||||||
if item['link_object'] == 'Ticket'
|
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)
|
assets = linked_ticket.assets(assets)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
@ -534,9 +534,31 @@ class TicketsController < ApplicationController
|
||||||
# create article if given
|
# create article if given
|
||||||
form_id = params[:form_id]
|
form_id = params[:form_id]
|
||||||
params.delete(: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
|
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{(<img\s.+?src=")(data:image/(jpeg|png);base64,.+?)">}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
|
# find attachments in upload cache
|
||||||
if form_id
|
if form_id
|
||||||
article.attachments = Store.list(
|
article.attachments = Store.list(
|
||||||
|
|
|
@ -82,9 +82,23 @@ module Channel::EmailBuild
|
||||||
if html_alternative
|
if html_alternative
|
||||||
html_container = Mail::Part.new { content_type 'multipart/related' }
|
html_container = Mail::Part.new { content_type 'multipart/related' }
|
||||||
html_container.add_part html_alternative
|
html_container.add_part html_alternative
|
||||||
alternative_bodies.add_part html_container
|
|
||||||
|
|
||||||
# place to add inline attachments related to html alternative
|
# 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
|
end
|
||||||
|
|
||||||
mail.add_part alternative_bodies
|
mail.add_part alternative_bodies
|
||||||
|
@ -96,11 +110,12 @@ module Channel::EmailBuild
|
||||||
attachment['content-id'] = nil
|
attachment['content-id'] = nil
|
||||||
mail.attachments[ attachment[:filename] ] = attachment
|
mail.attachments[ attachment[:filename] ] = attachment
|
||||||
else
|
else
|
||||||
|
next if !attachment.preferences['Content-ID'].empty?
|
||||||
mail.attachments[attachment.filename] = {
|
mail.attachments[attachment.filename] = {
|
||||||
:content_type => attachment.preferences['Content-Type'],
|
content_disposition: attachment.preferences['Content-Disposition'] || 'attachment',
|
||||||
:mime_type => attachment.preferences['Mime-Type'],
|
content_type: attachment.preferences['Content-Type'],
|
||||||
:content => attachment.content,
|
mime_type: attachment.preferences['Mime-Type'],
|
||||||
'content-id' => nil,
|
content: attachment.content,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,8 +18,8 @@ add an attachment to storage
|
||||||
o_id: 4711,
|
o_id: 4711,
|
||||||
data: binary_string,
|
data: binary_string,
|
||||||
preferences: {
|
preferences: {
|
||||||
:content_type => 'image/png',
|
content_type: 'image/png',
|
||||||
:content_id => 234,
|
content_id: 234,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ returns
|
||||||
size: 94123,
|
size: 94123,
|
||||||
filename: 'image.png',
|
filename: 'image.png',
|
||||||
preferences: {
|
preferences: {
|
||||||
:content_type => 'image/png',
|
content_type: 'image/png',
|
||||||
:content_id => 234,
|
content_id: 234,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store1.content # binary_string
|
store1.content # binary_string
|
||||||
|
|
|
@ -37,6 +37,30 @@ class Ticket::Article < ApplicationModel
|
||||||
self.message_id_md5 = Digest::MD5.hexdigest(message_id.to_s)
|
self.message_id_md5 = Digest::MD5.hexdigest(message_id.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# insert inline image urls
|
||||||
|
def self.insert_urls(article, attachments)
|
||||||
|
inline_attachments = {}
|
||||||
|
article['body'].gsub!( /(<img\s(style.+?|)src=")cid:(.+?)(">)/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
|
private
|
||||||
|
|
||||||
# strip not wanted chars
|
# strip not wanted chars
|
||||||
|
|
|
@ -39,6 +39,20 @@ returns
|
||||||
|
|
||||||
# add attachment list to article
|
# add attachment list to article
|
||||||
data[ Ticket::Article.to_app_model ][ id ]['attachments'] = attachments
|
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'] =~ /<img/i
|
||||||
|
|
||||||
|
# insert inline images with urls
|
||||||
|
attributes = Ticket::Article.insert_urls(
|
||||||
|
data[ Ticket::Article.to_app_model ][ id ],
|
||||||
|
data[ Ticket::Article.to_app_model ][ id ]['attachments']
|
||||||
|
)
|
||||||
|
data[ Ticket::Article.to_app_model ][ id ] = attributes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(created_by_id updated_by_id).each {|local_user_id|
|
%w(created_by_id updated_by_id).each {|local_user_id|
|
||||||
|
|
|
@ -7,5 +7,6 @@ class ContenteditableIamges < ActiveRecord::Migration
|
||||||
change_column :text_modules, :content, :text, limit: 10.megabytes + 1, null: false
|
change_column :text_modules, :content, :text, limit: 10.megabytes + 1, null: false
|
||||||
change_column :signatures, :body, :text, limit: 10.megabytes + 1, null: true
|
change_column :signatures, :body, :text, limit: 10.megabytes + 1, null: true
|
||||||
change_column :ticket_articles, :body, :text, limit: 20.megabytes + 1, null: false
|
change_column :ticket_articles, :body, :text, limit: 20.megabytes + 1, null: false
|
||||||
|
change_column :taskbars, :state, :text, limit: 20.megabytes + 1, null: true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ returns
|
||||||
|
|
||||||
store image 1:1 in backend and return filename
|
store image 1:1 in backend and return filename
|
||||||
|
|
||||||
filename = StaticAssets.store_raw( content, content_type )
|
filename = StaticAssets.store_raw(content, content_type)
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue