Improved external attachment support.
This commit is contained in:
parent
b09ecbe23e
commit
14507180a3
9 changed files with 170 additions and 26 deletions
|
@ -0,0 +1,19 @@
|
|||
class App.TicketZoomArticleImageView extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: 'Download'
|
||||
buttonClass: 'btn--success'
|
||||
head: ''
|
||||
large: true
|
||||
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
'click .js-cancel': 'cancel'
|
||||
'click .js-close': 'cancel'
|
||||
|
||||
content: ->
|
||||
"<div class=\"centered\">#{@image}</div>"
|
||||
|
||||
onSubmit: =>
|
||||
url = "#{$(@image).attr('src')}?disposition=attachment"
|
||||
window.open(url, '_blank')
|
|
@ -50,9 +50,10 @@ class ArticleViewItem extends App.ObserverController
|
|||
'.textBubble-overflowContainer': 'textBubbleOverflowContainer'
|
||||
|
||||
events:
|
||||
'click .textBubble': 'toggleMetaWithDelay'
|
||||
'click .textBubble a': 'stopPropagation'
|
||||
'click .js-toggleFold': 'toggleFold'
|
||||
'click .textBubble': 'toggleMetaWithDelay'
|
||||
'click .textBubble a': 'stopPropagation'
|
||||
'click .js-toggleFold': 'toggleFold'
|
||||
'click .richtext-content img': 'imageView'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
@ -367,3 +368,8 @@ class ArticleViewItem extends App.ObserverController
|
|||
|
||||
remove: =>
|
||||
@el.remove()
|
||||
|
||||
imageView: (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
new App.TicketZoomArticleImageView(image: $(e.target).get(0).outerHTML)
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<%- @Icon('diagonal-cross') %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if @head: %>
|
||||
<h1 class="modal-title"><% if @headPrefix: %><%- @T(@headPrefix) %>: <% end %><%- @T(@head) %></h1>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<%- @content %>
|
||||
|
|
|
@ -48,22 +48,7 @@ module CreatesTicketArticles
|
|||
# store dataurl images to store
|
||||
attachments_inline = []
|
||||
if article.body && article.content_type =~ %r{text/html}i
|
||||
article.body.gsub!( %r{(<img\s.?src=")(data:image/(jpeg|png);base64,.+?)"(|.+?)>}im ) { |_item|
|
||||
file_attributes = StaticAssets.data_url_attributes($2)
|
||||
cid = "#{ticket.id}.#{rand(999_999_999)}@#{Setting.get('fqdn')}"
|
||||
attachment = {
|
||||
data: file_attributes[:content],
|
||||
filename: cid,
|
||||
preferences: {
|
||||
'Content-Type' => file_attributes[:mime_type],
|
||||
'Mime-Type' => file_attributes[:mime_type],
|
||||
'Content-ID' => cid,
|
||||
'Content-Disposition' => 'inline',
|
||||
},
|
||||
}
|
||||
attachments_inline.push attachment
|
||||
"#{$1}cid:#{cid}\">"
|
||||
}
|
||||
(article.body, attachments_inline) = HtmlSanitizer.replace_inline_images(article.body, ticket.id)
|
||||
end
|
||||
|
||||
# find attachments in upload cache
|
||||
|
|
|
@ -270,6 +270,9 @@ returns
|
|||
}
|
||||
attributes['attachments'].push item
|
||||
}
|
||||
if articles['body'] && articles['content_type'] =~ %r{text/html}i
|
||||
articles['body'] = HtmlSanitizer.dynamic_image_size(articles['body'])
|
||||
end
|
||||
Ticket::Article.insert_urls(attributes)
|
||||
end
|
||||
|
||||
|
|
|
@ -352,6 +352,73 @@ cleanup html string:
|
|||
false
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
reolace inline images with cid images
|
||||
|
||||
string = HtmlSanitizer.replace_inline_images(article.body)
|
||||
|
||||
=end
|
||||
|
||||
def self.replace_inline_images(string, prefix = rand(999_999_999))
|
||||
attachments_inline = []
|
||||
scrubber = Loofah::Scrubber.new do |node|
|
||||
if node.name == 'img'
|
||||
if node['src'] && node['src'] =~ %r{^(data:image/(jpeg|png);base64,.+?)$}i
|
||||
file_attributes = StaticAssets.data_url_attributes($1)
|
||||
cid = "#{prefix}.#{rand(999_999_999)}@#{Setting.get('fqdn')}"
|
||||
attachment = {
|
||||
data: file_attributes[:content],
|
||||
filename: cid,
|
||||
preferences: {
|
||||
'Content-Type' => file_attributes[:mime_type],
|
||||
'Mime-Type' => file_attributes[:mime_type],
|
||||
'Content-ID' => cid,
|
||||
'Content-Disposition' => 'inline',
|
||||
},
|
||||
}
|
||||
attachments_inline.push attachment
|
||||
node['src'] = "cid:#{cid}"
|
||||
end
|
||||
Loofah::Scrubber::STOP
|
||||
end
|
||||
end
|
||||
[Loofah.fragment(string).scrub!(scrubber).to_s, attachments_inline]
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
satinize style of img tags
|
||||
|
||||
string = HtmlSanitizer.dynamic_image_size(article.body)
|
||||
|
||||
=end
|
||||
|
||||
def self.dynamic_image_size(string)
|
||||
scrubber = Loofah::Scrubber.new do |node|
|
||||
if node.name == 'img'
|
||||
if node['src']
|
||||
style = 'max-width:100%;'
|
||||
if node['style']
|
||||
pears = node['style'].downcase.gsub(/\t|\n|\r/, '').split(';')
|
||||
pears.each { |local_pear|
|
||||
prop = local_pear.split(':')
|
||||
next if !prop[0]
|
||||
key = prop[0].strip
|
||||
if key == 'height'
|
||||
key = 'max-height'
|
||||
end
|
||||
style += "#{key}:#{prop[1]};"
|
||||
}
|
||||
end
|
||||
node['style'] = style
|
||||
end
|
||||
Loofah::Scrubber::STOP
|
||||
end
|
||||
end
|
||||
Loofah.fragment(string).scrub!(scrubber).to_s
|
||||
end
|
||||
|
||||
private_class_method :cleanup_target
|
||||
private_class_method :add_link
|
||||
private_class_method :url_same?
|
||||
|
|
|
@ -156,6 +156,11 @@ returns
|
|||
result[:subject] = data[:main_object].subject_build(result[:subject])
|
||||
end
|
||||
|
||||
# prepare scaling of images
|
||||
if result[:body]
|
||||
result[:body] = HtmlSanitizer.dynamic_image_size(result[:body])
|
||||
end
|
||||
|
||||
NotificationFactory::Mailer.send(
|
||||
recipient: data[:user],
|
||||
subject: result[:subject],
|
||||
|
|
|
@ -99,8 +99,8 @@ AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
|
|||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal(nil, result['subject'])
|
||||
assert_no_match(/some body <img src="cid:/, result['body'])
|
||||
assert_match(%r{some body <img src="/api/v1/ticket_attachment/.}, result['body'])
|
||||
assert_no_match(/some body <img src="cid:.+?/, result['body'])
|
||||
assert_match(%r{some body <img src="/api/v1/ticket_attachment/.+?" alt="Red dot"}, result['body'])
|
||||
assert_equal('text/html', result['content_type'])
|
||||
assert_equal(@agent.id, result['updated_by_id'])
|
||||
assert_equal(@agent.id, result['created_by_id'])
|
||||
|
|
|
@ -215,12 +215,12 @@ you<br/>
|
|||
should = 'line 1
|
||||
you
|
||||
-----&'
|
||||
assert_equal( should, html.html2text)
|
||||
assert_equal(should, html.html2text)
|
||||
|
||||
html = ' <ul><li>#1</li><li>#2</li></ul>'
|
||||
should = '* #1
|
||||
* #2'
|
||||
assert_equal( should, html.html2text)
|
||||
assert_equal(should, html.html2text)
|
||||
|
||||
html = '<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -235,7 +235,7 @@ you
|
|||
>
|
||||
> Thank you for installing Zammad.
|
||||
>'
|
||||
assert_equal( should, html.html2text)
|
||||
assert_equal(should, html.html2text)
|
||||
|
||||
html = ' <style type="text/css">
|
||||
body {
|
||||
|
@ -270,7 +270,7 @@ ont-size: 12px;;
|
|||
|
||||
</style><p>some other content</p>'
|
||||
should = 'some other content'
|
||||
assert_equal( should, html.html2text)
|
||||
assert_equal(should, html.html2text)
|
||||
|
||||
html = ' IT-Infrastruktur</span><br>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
|
@ -337,7 +337,7 @@ div.wordsection1
|
|||
<o:idmap v:ext="edit" data="1" />
|
||||
</o:shapelayout></xml><![endif]-->'
|
||||
should = 'IT-Infrastruktur'
|
||||
assert_equal( should, html.html2text)
|
||||
assert_equal(should, html.html2text)
|
||||
|
||||
html = "<h1>some head</h1>
|
||||
some content
|
||||
|
@ -848,6 +848,18 @@ christian.schaefer@example.com'
|
|||
result = 'john.smith2@example.com'
|
||||
assert_equal(result, html.html2html_strict)
|
||||
|
||||
html = '<img src="/some.png" style="color: blue; width: 30px; height: 50px">'
|
||||
result = '<img src="/some.png" style=" width: 30px; height: 50px;">'
|
||||
assert_equal(result, html.html2html_strict)
|
||||
|
||||
html = '<img src="/some.png" width="30px" height="50px">'
|
||||
result = '<img src="/some.png" style="width:30px;height:50px;">'
|
||||
assert_equal(result, html.html2html_strict)
|
||||
|
||||
html = '<img style="width: 181px; height: 125px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/...">'
|
||||
result = '<img style="width: 181px; height: 125px;" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/...">'
|
||||
assert_equal(result, html.html2html_strict)
|
||||
|
||||
html = '<p class="MsoNormal"><a href="http://www.example.de/"><span style="color:blue;text-decoration:none"><img border="0" width="30" height="30" id="_x0000_i1030" src="cid:image001.png@01D172FC.F323CDB0"></span></a><o:p></o:p></p>'
|
||||
#result = '<p>http://www.example.de/ <a href="http://www.example.de/" rel="nofollow" target="_blank"><img border="0" src="cid:image001.png@01D172FC.F323CDB0" style="width:30px;height:30px;"></a></p>'
|
||||
result = '<p><a href="http://www.example.de/" rel="nofollow" target="_blank">http://www.example.de/</a></p>'
|
||||
|
@ -864,6 +876,51 @@ christian.schaefer@example.com'
|
|||
assert_equal(result, html.html2html_strict)
|
||||
end
|
||||
|
||||
test 'inline attachment replace' do
|
||||
html = '<img style="width: 181px; height: 125px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/...">'
|
||||
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(html)
|
||||
assert_match(/<img style="width: 181px; height: 125px" src="cid:.+?">/, body)
|
||||
assert(1, attachments_inline.count)
|
||||
|
||||
html = '<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..." style="width: 181px; height: 125px" alt="abc">'
|
||||
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(html)
|
||||
assert_match(/<img src="cid:.+?" style="width: 181px; height: 125px" alt="abc">/, body)
|
||||
assert(1, attachments_inline.count)
|
||||
|
||||
html = '<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..." style="width: 181px; height: 125px" alt="abc"><invalid what ever'
|
||||
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(html)
|
||||
assert_match(/<img src="cid:.+?" style="width: 181px; height: 125px" alt="abc">/, body)
|
||||
assert(1, attachments_inline.count)
|
||||
|
||||
html = '<img src="/some_one.png" style="width: 181px; height: 125px" alt="abc">'
|
||||
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(html)
|
||||
assert_match(/<img src="\/some_one.png" style="width: 181px; height: 125px" alt="abc">/, body)
|
||||
assert(0, attachments_inline.count)
|
||||
|
||||
html = '<div><img style="width: 181px; height: 125px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..."><p>123</p><img style="width: 181px; height: 125px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..."></div>'
|
||||
(body, attachments_inline) = HtmlSanitizer.replace_inline_images(html)
|
||||
assert_match(/<div>\s+<img style="width: 181px; height: 125px" src="cid:.+?"><p>123<\/p>\s+<img style="width: 181px; height: 125px" src="cid:.+?">\s+<\/div>/, body)
|
||||
assert(2, attachments_inline.count)
|
||||
end
|
||||
|
||||
test 'set dynamic image size' do
|
||||
html = '<img style="width: 181px; height: 125px" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/...">'
|
||||
body = HtmlSanitizer.dynamic_image_size(html)
|
||||
assert_match(/<img style="max-width:100%;width: 181px;max-height: 125px;" src="data:image.+?">/, body)
|
||||
|
||||
html = '<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..." style="width: 181px; height: 125px" alt="abc">'
|
||||
body = HtmlSanitizer.dynamic_image_size(html)
|
||||
assert_match(/<img src="data:image.+?" style="max-width:100%;width: 181px;max-height: 125px;" alt="abc">/, body)
|
||||
|
||||
html = '<img src="/some_one.png" style="width: 181px; height: 125px" alt="abc">'
|
||||
body = HtmlSanitizer.dynamic_image_size(html)
|
||||
assert_match(/<img src="\/some_one.png" style="max-width:100%;width: 181px;max-height: 125px;" alt="abc">/, body)
|
||||
|
||||
html = '<img src="/some_one.png" alt="abc">'
|
||||
body = HtmlSanitizer.dynamic_image_size(html)
|
||||
assert_match(/<img src="\/some_one.png" alt="abc" style="max-width:100%;">/, body)
|
||||
end
|
||||
|
||||
test 'signature_identify function' do
|
||||
marker_template = '######SIGNATURE_MARKER######'
|
||||
|
||||
|
|
Loading…
Reference in a new issue