Improved article attachment api (implemented easier attaching attachments via rest).
This commit is contained in:
parent
5eb49443dd
commit
1b3d787c27
7 changed files with 723 additions and 69 deletions
|
@ -46,23 +46,22 @@ module CreatesTicketArticles
|
||||||
article.ticket_id = ticket.id
|
article.ticket_id = ticket.id
|
||||||
|
|
||||||
# store dataurl images to store
|
# store dataurl images to store
|
||||||
if form_id && article.body && article.content_type =~ %r{text/html}i
|
attachments_inline = []
|
||||||
article.body.gsub!( %r{(<img\s.+?src=")(data:image/(jpeg|png);base64,.+?)">}i ) { |_item|
|
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)
|
file_attributes = StaticAssets.data_url_attributes($2)
|
||||||
cid = "#{ticket.id}.#{form_id}.#{rand(999_999)}@#{Setting.get('fqdn')}"
|
cid = "#{ticket.id}.#{rand(999_999_999)}@#{Setting.get('fqdn')}"
|
||||||
headers_store = {
|
attachment = {
|
||||||
|
data: file_attributes[:content],
|
||||||
|
filename: cid,
|
||||||
|
preferences: {
|
||||||
'Content-Type' => file_attributes[:mime_type],
|
'Content-Type' => file_attributes[:mime_type],
|
||||||
'Mime-Type' => file_attributes[:mime_type],
|
'Mime-Type' => file_attributes[:mime_type],
|
||||||
'Content-ID' => cid,
|
'Content-ID' => cid,
|
||||||
'Content-Disposition' => 'inline',
|
'Content-Disposition' => 'inline',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
store = Store.add(
|
attachments_inline.push attachment
|
||||||
object: 'UploadCache',
|
|
||||||
o_id: form_id,
|
|
||||||
data: file_attributes[:content],
|
|
||||||
filename: cid,
|
|
||||||
preferences: headers_store
|
|
||||||
)
|
|
||||||
"#{$1}cid:#{cid}\">"
|
"#{$1}cid:#{cid}\">"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -76,6 +75,48 @@ module CreatesTicketArticles
|
||||||
end
|
end
|
||||||
article.save!
|
article.save!
|
||||||
|
|
||||||
|
# store inline attachments
|
||||||
|
attachments_inline.each { |attachment|
|
||||||
|
Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article.id,
|
||||||
|
data: attachment[:data],
|
||||||
|
filename: attachment[:filename],
|
||||||
|
preferences: attachment[:preferences],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# add attachments as param
|
||||||
|
if params[:attachments]
|
||||||
|
params[:attachments].each_with_index { |attachment, index|
|
||||||
|
|
||||||
|
# validation
|
||||||
|
['mime-type', 'filename', 'data'].each { |key|
|
||||||
|
next if attachment[key]
|
||||||
|
raise Exceptions::UnprocessableEntity, "Attachment needs '#{key}' param for attachment with index '#{index}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences = {}
|
||||||
|
['charset', 'mime-type'].each { |key|
|
||||||
|
next if !attachment[key]
|
||||||
|
store_key = key.tr('-', '_').camelize.gsub(/(.+)([A-Z])/, '\1_\2').tr('_', '-')
|
||||||
|
preferences[store_key] = attachment[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
if attachment[:data] !~ %r{^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$}
|
||||||
|
raise Exceptions::UnprocessableEntity, "Invalid base64 for attachment with index '#{index}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article.id,
|
||||||
|
data: Base64.decode64(attachment[:data]),
|
||||||
|
filename: attachment[:filename],
|
||||||
|
preferences: preferences,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# account time
|
# account time
|
||||||
if time_unit.present?
|
if time_unit.present?
|
||||||
Ticket::TimeAccounting.create!(
|
Ticket::TimeAccounting.create!(
|
||||||
|
@ -85,9 +126,9 @@ module CreatesTicketArticles
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# remove attachments from upload cache
|
|
||||||
return article if !form_id
|
return article if !form_id
|
||||||
|
|
||||||
|
# remove attachments from upload cache
|
||||||
Store.remove(
|
Store.remove(
|
||||||
object: 'UploadCache',
|
object: 'UploadCache',
|
||||||
o_id: form_id,
|
o_id: form_id,
|
||||||
|
@ -95,4 +136,5 @@ module CreatesTicketArticles
|
||||||
|
|
||||||
article
|
article
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,14 +14,11 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# GET /articles/1
|
# GET /articles/1
|
||||||
def show
|
def show
|
||||||
|
|
||||||
# permission check
|
|
||||||
article = Ticket::Article.find(params[:id])
|
article = Ticket::Article.find(params[:id])
|
||||||
article_permission(article)
|
article_permission(article)
|
||||||
|
|
||||||
if params[:expand]
|
if params[:expand]
|
||||||
result = article.attributes_with_association_names
|
result = article.attributes_with_association_names
|
||||||
result[:attachments] = article.attachments
|
|
||||||
render json: result, status: :ok
|
render json: result, status: :ok
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -37,8 +34,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# GET /ticket_articles/by_ticket/1
|
# GET /ticket_articles/by_ticket/1
|
||||||
def index_by_ticket
|
def index_by_ticket
|
||||||
|
|
||||||
# permission check
|
|
||||||
ticket = Ticket.find(params[:id])
|
ticket = Ticket.find(params[:id])
|
||||||
ticket_permission(ticket)
|
ticket_permission(ticket)
|
||||||
|
|
||||||
|
@ -50,9 +45,6 @@ class TicketArticlesController < ApplicationController
|
||||||
# ignore internal article if customer is requesting
|
# ignore internal article if customer is requesting
|
||||||
next if article.internal == true && current_user.permissions?('ticket.customer')
|
next if article.internal == true && current_user.permissions?('ticket.customer')
|
||||||
result = article.attributes_with_association_names
|
result = article.attributes_with_association_names
|
||||||
|
|
||||||
# add attachments
|
|
||||||
result[:attachments] = article.attachments
|
|
||||||
articles.push result
|
articles.push result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +87,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
if params[:expand]
|
if params[:expand]
|
||||||
result = article.attributes_with_association_names
|
result = article.attributes_with_association_names
|
||||||
result[:attachments] = article.attachments
|
|
||||||
render json: result, status: :created
|
render json: result, status: :created
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -111,8 +102,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# PUT /articles/1
|
# PUT /articles/1
|
||||||
def update
|
def update
|
||||||
|
|
||||||
# permission check
|
|
||||||
article = Ticket::Article.find(params[:id])
|
article = Ticket::Article.find(params[:id])
|
||||||
article_permission(article)
|
article_permission(article)
|
||||||
|
|
||||||
|
@ -127,7 +116,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
if params[:expand]
|
if params[:expand]
|
||||||
result = article.attributes_with_association_names
|
result = article.attributes_with_association_names
|
||||||
result[:attachments] = article.attachments
|
|
||||||
render json: result, status: :ok
|
render json: result, status: :ok
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -220,8 +208,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# GET /ticket_attachment/:ticket_id/:article_id/:id
|
# GET /ticket_attachment/:ticket_id/:article_id/:id
|
||||||
def attachment
|
def attachment
|
||||||
|
|
||||||
# permission check
|
|
||||||
ticket = Ticket.lookup(id: params[:ticket_id])
|
ticket = Ticket.lookup(id: params[:ticket_id])
|
||||||
if !ticket_permission(ticket)
|
if !ticket_permission(ticket)
|
||||||
raise Exceptions::NotAuthorized, 'No such ticket.'
|
raise Exceptions::NotAuthorized, 'No such ticket.'
|
||||||
|
@ -255,8 +241,6 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# GET /ticket_article_plain/1
|
# GET /ticket_article_plain/1
|
||||||
def article_plain
|
def article_plain
|
||||||
|
|
||||||
# permission check
|
|
||||||
article = Ticket::Article.find(params[:id])
|
article = Ticket::Article.find(params[:id])
|
||||||
article_permission(article)
|
article_permission(article)
|
||||||
|
|
||||||
|
@ -276,6 +260,9 @@ class TicketArticlesController < ApplicationController
|
||||||
private
|
private
|
||||||
|
|
||||||
def article_permission(article)
|
def article_permission(article)
|
||||||
|
if current_user.permissions?('ticket.customer')
|
||||||
|
raise Exceptions::NotAuthorized if article.internal == true
|
||||||
|
end
|
||||||
ticket = Ticket.lookup(id: article.ticket_id)
|
ticket = Ticket.lookup(id: article.ticket_id)
|
||||||
return true if ticket.permission(current_user: current_user)
|
return true if ticket.permission(current_user: current_user)
|
||||||
raise Exceptions::NotAuthorized
|
raise Exceptions::NotAuthorized
|
||||||
|
|
|
@ -44,10 +44,7 @@ class Ticket::Article < ApplicationModel
|
||||||
|
|
||||||
insert inline image urls to body
|
insert inline image urls to body
|
||||||
|
|
||||||
article_attributes = Ticket::Article.insert_urls(
|
article_attributes = Ticket::Article.insert_urls(article_attributes)
|
||||||
article_attributes,
|
|
||||||
attachments,
|
|
||||||
)
|
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
|
||||||
|
@ -55,23 +52,30 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.insert_urls(article, attachments)
|
def self.insert_urls(article)
|
||||||
|
return article if article['attachments'].empty?
|
||||||
|
return article if article['content_type'] !~ %r{text/html}i
|
||||||
|
return article if article['body'] !~ /<img/i
|
||||||
|
|
||||||
inline_attachments = {}
|
inline_attachments = {}
|
||||||
article['body'].gsub!( /(<img[[:space:]](.+?|)src=")cid:(.+?)(">)/i ) { |item|
|
article['body'].gsub!( /(<img[[:space:]](|.+?)src=")cid:(.+?)"(|.+?)>/im ) { |item|
|
||||||
|
tag_start = $1
|
||||||
|
cid = $3
|
||||||
|
tag_end = $4
|
||||||
replace = item
|
replace = item
|
||||||
|
|
||||||
# look for attachment
|
# look for attachment
|
||||||
attachments.each { |file|
|
article['attachments'].each { |file|
|
||||||
next if !file.preferences['Content-ID'] || file.preferences['Content-ID'] != $3
|
next if !file[:preferences] || !file[:preferences]['Content-ID'] || (file[:preferences]['Content-ID'] != cid && file[:preferences]['Content-ID'] != "<#{cid}>" )
|
||||||
replace = "#{$1}/api/v1/ticket_attachment/#{article['ticket_id']}/#{article['id']}/#{file.id}#{$4}"
|
replace = "#{tag_start}/api/v1/ticket_attachment/#{article['ticket_id']}/#{article['id']}/#{file[:id]}\"#{tag_end}>"
|
||||||
inline_attachments[file.id] = true
|
inline_attachments[file[:id]] = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
replace
|
replace
|
||||||
}
|
}
|
||||||
new_attachments = []
|
new_attachments = []
|
||||||
attachments.each { |file|
|
article['attachments'].each { |file|
|
||||||
next if inline_attachments[file.id]
|
next if inline_attachments[file[:id]]
|
||||||
new_attachments.push file
|
new_attachments.push file
|
||||||
}
|
}
|
||||||
article['attachments'] = new_attachments
|
article['attachments'] = new_attachments
|
||||||
|
@ -93,11 +97,12 @@ returns
|
||||||
|
|
||||||
def attachments_inline
|
def attachments_inline
|
||||||
inline_attachments = {}
|
inline_attachments = {}
|
||||||
body.gsub( /<img[[:space:]](.+?|)src="cid:(.+?)">/i ) { |_item|
|
body.gsub( /<img[[:space:]](|.+?)src="cid:(.+?)"(|.+?)>/im ) { |_item|
|
||||||
|
cid = $2
|
||||||
|
|
||||||
# look for attachment
|
# look for attachment
|
||||||
attachments.each { |file|
|
attachments.each { |file|
|
||||||
next if !file.preferences['Content-ID'] || file.preferences['Content-ID'] != $2
|
next if !file.preferences['Content-ID'] || (file.preferences['Content-ID'] != cid && file.preferences['Content-ID'] != "<#{cid}>" )
|
||||||
inline_attachments[file.id] = true
|
inline_attachments[file.id] = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -212,6 +217,62 @@ returns:
|
||||||
content_type =~ /html/i
|
content_type =~ /html/i
|
||||||
end
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
get relation name of model based on params
|
||||||
|
|
||||||
|
model = Model.find(1)
|
||||||
|
attributes = model.attributes_with_association_names
|
||||||
|
|
||||||
|
returns
|
||||||
|
|
||||||
|
hash with attributes, association ids, association names and relation name
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def attributes_with_association_names
|
||||||
|
attributes = super
|
||||||
|
attributes['attachments'] = []
|
||||||
|
attachments.each { |attachment|
|
||||||
|
item = {
|
||||||
|
id: attachment['id'],
|
||||||
|
filename: attachment['filename'],
|
||||||
|
size: attachment['size'],
|
||||||
|
preferences: attachment['preferences'],
|
||||||
|
}
|
||||||
|
attributes['attachments'].push item
|
||||||
|
}
|
||||||
|
Ticket::Article.insert_urls(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
get relations of model based on params
|
||||||
|
|
||||||
|
model = Model.find(1)
|
||||||
|
attributes = model.attributes_with_association_ids
|
||||||
|
|
||||||
|
returns
|
||||||
|
|
||||||
|
hash with attributes and association ids
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def attributes_with_association_ids
|
||||||
|
attributes = super
|
||||||
|
attributes['attachments'] = []
|
||||||
|
attachments.each { |attachment|
|
||||||
|
item = {
|
||||||
|
id: attachment['id'],
|
||||||
|
filename: attachment['filename'],
|
||||||
|
size: attachment['size'],
|
||||||
|
preferences: attachment['preferences'],
|
||||||
|
}
|
||||||
|
attributes['attachments'].push item
|
||||||
|
}
|
||||||
|
Ticket::Article.insert_urls(attributes)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# strip not wanted chars
|
# strip not wanted chars
|
||||||
|
|
|
@ -39,24 +39,7 @@ returns
|
||||||
data[ app_model_article ] = {}
|
data[ app_model_article ] = {}
|
||||||
end
|
end
|
||||||
if !data[ app_model_article ][ id ]
|
if !data[ app_model_article ][ id ]
|
||||||
data[ app_model_article ][ id ] = attributes
|
data[ app_model_article ][ id ] = attributes_with_association_ids
|
||||||
|
|
||||||
# add attachment list to article
|
|
||||||
data[ app_model_article ][ id ]['attachments'] = attachments
|
|
||||||
|
|
||||||
if !data[ app_model_article ][ id ]['attachments'].empty?
|
|
||||||
if data[ app_model_article ][ id ]['content_type'] =~ %r{text/html}i
|
|
||||||
if data[ app_model_article ][ id ]['body'] =~ /<img/i
|
|
||||||
|
|
||||||
# insert inline images with urls
|
|
||||||
attributes = Ticket::Article.insert_urls(
|
|
||||||
data[ app_model_article ][ id ],
|
|
||||||
data[ app_model_article ][ id ]['attachments']
|
|
||||||
)
|
|
||||||
data[ app_model_article ][ 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|
|
||||||
|
|
273
test/controllers/ticket_articles_controller_test.rb
Normal file
273
test/controllers/ticket_articles_controller_test.rb
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TicketArticlesControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
|
||||||
|
# set accept header
|
||||||
|
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: %w(Admin Agent))
|
||||||
|
groups = Group.all
|
||||||
|
|
||||||
|
UserInfo.current_user_id = 1
|
||||||
|
@admin = User.create_or_update(
|
||||||
|
login: 'tickets-admin',
|
||||||
|
firstname: 'Tickets',
|
||||||
|
lastname: 'Admin',
|
||||||
|
email: 'tickets-admin@example.com',
|
||||||
|
password: 'adminpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: 'Agent')
|
||||||
|
@agent = User.create_or_update(
|
||||||
|
login: 'tickets-agent@example.com',
|
||||||
|
firstname: 'Tickets',
|
||||||
|
lastname: 'Agent',
|
||||||
|
email: 'tickets-agent@example.com',
|
||||||
|
password: 'agentpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create customer without org
|
||||||
|
roles = Role.where(name: 'Customer')
|
||||||
|
@customer_without_org = User.create_or_update(
|
||||||
|
login: 'tickets-customer1@example.com',
|
||||||
|
firstname: 'Tickets',
|
||||||
|
lastname: 'Customer1',
|
||||||
|
email: 'tickets-customer1@example.com',
|
||||||
|
password: 'customer1pw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.01 ticket create with agent and articles' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #1',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
body: 'some body',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['id'],
|
||||||
|
content_type: 'text/plain', # or text/html
|
||||||
|
body: 'some body',
|
||||||
|
type: 'note',
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(nil, result['subject'])
|
||||||
|
assert_equal('some body', result['body'])
|
||||||
|
assert_equal('text/plain', result['content_type'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['ticket_id'])
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['ticket_id'],
|
||||||
|
content_type: 'text/html', # or text/html
|
||||||
|
body: 'some body <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
|
||||||
|
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
|
||||||
|
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />',
|
||||||
|
type: 'note',
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
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_equal('text/html', result['content_type'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
assert_equal(3, ticket.articles.count)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
assert_equal(1, ticket.articles[2].attachments.count)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['ticket_id'],
|
||||||
|
content_type: 'text/html', # or text/html
|
||||||
|
body: 'some body',
|
||||||
|
type: 'note',
|
||||||
|
attachments: [
|
||||||
|
'filename' => 'some_file.txt',
|
||||||
|
'data' => 'dGVzdCAxMjM=',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(nil, result['subject'])
|
||||||
|
assert_equal('some body', 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'])
|
||||||
|
|
||||||
|
assert_equal(4, ticket.articles.count)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
assert_equal(1, ticket.articles[2].attachments.count)
|
||||||
|
assert_equal(1, ticket.articles[3].attachments.count)
|
||||||
|
|
||||||
|
get "/api/v1/ticket_articles/#{result['id']}?expand=true", {}.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(1, result['attachments'].count)
|
||||||
|
end
|
||||||
|
|
||||||
|
test '02.01 ticket create with customer and articles' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-customer1@example.com', 'customer1pw')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #2',
|
||||||
|
group: 'Users',
|
||||||
|
article: {
|
||||||
|
body: 'some body',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['id'],
|
||||||
|
content_type: 'text/plain', # or text/html
|
||||||
|
body: 'some body',
|
||||||
|
type: 'note',
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(nil, result['subject'])
|
||||||
|
assert_equal('some body', result['body'])
|
||||||
|
assert_equal('text/plain', result['content_type'])
|
||||||
|
assert_equal(@customer_without_org.id, result['updated_by_id'])
|
||||||
|
assert_equal(@customer_without_org.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['ticket_id'])
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_equal('Customer', ticket.articles[1].sender.name)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['ticket_id'],
|
||||||
|
content_type: 'text/plain', # or text/html
|
||||||
|
body: 'some body',
|
||||||
|
sender: 'Agent',
|
||||||
|
type: 'note',
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(nil, result['subject'])
|
||||||
|
assert_equal('some body', result['body'])
|
||||||
|
assert_equal('text/plain', result['content_type'])
|
||||||
|
assert_equal(@customer_without_org.id, result['updated_by_id'])
|
||||||
|
assert_equal(@customer_without_org.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['ticket_id'])
|
||||||
|
assert_equal(3, ticket.articles.count)
|
||||||
|
assert_equal('Customer', ticket.articles[2].sender.name)
|
||||||
|
assert_equal(false, ticket.articles[2].internal)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[2].attachments.count)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
ticket_id: result['ticket_id'],
|
||||||
|
content_type: 'text/plain', # or text/html
|
||||||
|
body: 'some body 2',
|
||||||
|
sender: 'Agent',
|
||||||
|
type: 'note',
|
||||||
|
internal: true,
|
||||||
|
}
|
||||||
|
post '/api/v1/ticket_articles', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(nil, result['subject'])
|
||||||
|
assert_equal('some body 2', result['body'])
|
||||||
|
assert_equal('text/plain', result['content_type'])
|
||||||
|
assert_equal(@customer_without_org.id, result['updated_by_id'])
|
||||||
|
assert_equal(@customer_without_org.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['ticket_id'])
|
||||||
|
assert_equal(4, ticket.articles.count)
|
||||||
|
assert_equal('Customer', ticket.articles[3].sender.name)
|
||||||
|
assert_equal(false, ticket.articles[3].internal)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[2].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[3].attachments.count)
|
||||||
|
|
||||||
|
# add internal article
|
||||||
|
article = Ticket::Article.create(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
to: 'some_recipient@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
body: 'some message 123',
|
||||||
|
internal: true,
|
||||||
|
sender: Ticket::Article::Sender.find_by(name: 'Agent'),
|
||||||
|
type: Ticket::Article::Type.find_by(name: 'note'),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
assert_equal(5, ticket.articles.count)
|
||||||
|
assert_equal('Agent', ticket.articles[4].sender.name)
|
||||||
|
assert_equal(1, ticket.articles[4].updated_by_id)
|
||||||
|
assert_equal(1, ticket.articles[4].created_by_id)
|
||||||
|
assert_equal(0, ticket.articles[0].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[1].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[2].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[3].attachments.count)
|
||||||
|
assert_equal(0, ticket.articles[4].attachments.count)
|
||||||
|
|
||||||
|
get "/api/v1/ticket_articles/#{article.id}", {}.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(401)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Not authorized', result['error'])
|
||||||
|
|
||||||
|
put "/api/v1/ticket_articles/#{article.id}", { internal: false }.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(401)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Not authorized', result['error'])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -263,6 +263,231 @@ class TicketsControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal(@agent.id, result['created_by_id'])
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test '01.10 ticket create with agent - minimal article with missing body - with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #10',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
subject: 'some test 123',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Need at least article: { body: "some text" }', result['error'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.11 ticket create with agent - minimal article and attachment with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #11',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123',
|
||||||
|
attachments: [
|
||||||
|
'filename' => 'some_file.txt',
|
||||||
|
'data' => 'dGVzdCAxMjM=',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(Ticket::State.lookup(name: 'new').id, result['state_id'])
|
||||||
|
assert_equal('a new ticket #11', result['title'])
|
||||||
|
assert_equal(@customer_without_org.id, result['customer_id'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['id'])
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal(1, ticket.articles.first.attachments.count)
|
||||||
|
file = ticket.articles.first.attachments.first
|
||||||
|
assert_equal('test 123', file.content)
|
||||||
|
assert_equal('some_file.txt', file.filename)
|
||||||
|
assert_equal('text/plain', file.preferences['Mime-Type'])
|
||||||
|
assert_not(file.preferences['Content-ID'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.12 ticket create with agent - minimal article and attachment with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #12',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123',
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
'filename' => 'some_file1.txt',
|
||||||
|
'data' => 'dGVzdCAxMjM=',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'filename' => 'some_file2.txt',
|
||||||
|
'data' => 'w6TDtsO8w58=',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(Ticket::State.lookup(name: 'new').id, result['state_id'])
|
||||||
|
assert_equal('a new ticket #12', result['title'])
|
||||||
|
assert_equal(@customer_without_org.id, result['customer_id'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['id'])
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal(2, ticket.articles.first.attachments.count)
|
||||||
|
file = ticket.articles.first.attachments.first
|
||||||
|
assert_equal('test 123', file.content)
|
||||||
|
assert_equal('some_file1.txt', file.filename)
|
||||||
|
assert_equal('text/plain', file.preferences['Mime-Type'])
|
||||||
|
assert_not(file.preferences['Content-ID'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.13 ticket create with agent - minimal article and attachment missing mine-type with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #13',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123',
|
||||||
|
attachments: [
|
||||||
|
'filename' => 'some_file.txt',
|
||||||
|
'data' => 'ABC_INVALID_BASE64',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Invalid base64 for attachment with index \'0\'', result['error'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.14 ticket create with agent - minimal article and attachment invalid base64 with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #14',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123',
|
||||||
|
attachments: [
|
||||||
|
'filename' => 'some_file.txt',
|
||||||
|
'data' => 'dGVzdCAxMjM=',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Attachment needs \'mime-type\' param for attachment with index \'0\'', result['error'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.15 ticket create with agent - minimal article and inline attachments with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #15',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
content_type: 'text/html',
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
|
||||||
|
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
|
||||||
|
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" /> <img src="data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAJAAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzJCOTE2NzlGQUEwMTFFNjg0M0NGQjU0OUU4MTFEOEIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzJCOTE2N0FGQUEwMTFFNjg0M0NGQjU0OUU4MTFEOEIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDMkI5MTY3N0ZBQTAxMUU2ODQzQ0ZCNTQ5RTgxMUQ4QiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDMkI5MTY3OEZBQTAxMUU2ODQzQ0ZCNTQ5RTgxMUQ4QiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/uAA5BZG9iZQBkwAAAAAH/2wCEABQRERoTGioZGSo1KCEoNTEpKCgpMUE4ODg4OEFEREREREREREREREREREREREREREREREREREREREREREREREQBFhoaIh0iKRoaKTkpIik5RDktLTlEREREOERERERERERERERERERERERERERERERERERERERERERERERERERERP/AABEIABAADAMBIgACEQEDEQH/xABbAAEBAAAAAAAAAAAAAAAAAAAEBQEBAQAAAAAAAAAAAAAAAAAABAUQAAEEAgMAAAAAAAAAAAAAAAABAhIDESIxBAURAAICAwAAAAAAAAAAAAAAAAESABNRoQP/2gAMAwEAAhEDEQA/AJDq1rfF3Imeg/1+lFy2oR564DKWWWbweV+Buf/Z">',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(Ticket::State.lookup(name: 'new').id, result['state_id'])
|
||||||
|
assert_equal('a new ticket #15', result['title'])
|
||||||
|
assert_equal(@customer_without_org.id, result['customer_id'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['id'])
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal(2, ticket.articles.first.attachments.count)
|
||||||
|
file = ticket.articles.first.attachments[0]
|
||||||
|
assert_equal('d3c1e09bdefb92b6a06b791a24ca9599', Digest::MD5.hexdigest(file.content))
|
||||||
|
assert_match(/#{ticket.id}\..+?@zammad.example.com/, file.filename)
|
||||||
|
assert_equal('image/png', file.preferences['Mime-Type'])
|
||||||
|
assert(file.preferences['Content-ID'])
|
||||||
|
file = ticket.articles.first.attachments[1]
|
||||||
|
assert_equal('006a2ca3793b550c8fe444acdeb39252', Digest::MD5.hexdigest(file.content))
|
||||||
|
assert_match(/#{ticket.id}\..+?@zammad.example.com/, file.filename)
|
||||||
|
assert_equal('image/jpeg', file.preferences['Mime-Type'])
|
||||||
|
assert(file.preferences['Content-ID'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01.16 ticket create with agent - minimal article and inline attachments with customer' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
|
params = {
|
||||||
|
title: 'a new ticket #16',
|
||||||
|
group: 'Users',
|
||||||
|
customer_id: @customer_without_org.id,
|
||||||
|
article: {
|
||||||
|
content_type: 'text/html',
|
||||||
|
subject: 'some test 123',
|
||||||
|
body: 'some test 123 <img src="data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAJAAD/4QMtaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzJCOTE2NzlGQUEwMTFFNjg0M0NGQjU0OUU4MTFEOEIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzJCOTE2N0FGQUEwMTFFNjg0M0NGQjU0OUU4MTFEOEIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDMkI5MTY3N0ZBQTAxMUU2ODQzQ0ZCNTQ5RTgxMUQ4QiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDMkI5MTY3OEZBQTAxMUU2ODQzQ0ZCNTQ5RTgxMUQ4QiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/uAA5BZG9iZQBkwAAAAAH/2wCEABQRERoTGioZGSo1KCEoNTEpKCgpMUE4ODg4OEFEREREREREREREREREREREREREREREREREREREREREREREREQBFhoaIh0iKRoaKTkpIik5RDktLTlEREREOERERERERERERERERERERERERERERERERERERERERERERERERERERP/AABEIABAADAMBIgACEQEDEQH/xABbAAEBAAAAAAAAAAAAAAAAAAAEBQEBAQAAAAAAAAAAAAAAAAAABAUQAAEEAgMAAAAAAAAAAAAAAAABAhIDESIxBAURAAICAwAAAAAAAAAAAAAAAAESABNRoQP/2gAMAwEAAhEDEQA/AJDq1rfF3Imeg/1+lFy2oR564DKWWWbweV+Buf/Z"
|
||||||
|
>',
|
||||||
|
attachments: [
|
||||||
|
'filename' => 'some_file.txt',
|
||||||
|
'data' => 'dGVzdCAxMjM=',
|
||||||
|
'mime-type' => 'text/plain',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
post '/api/v1/tickets', params.to_json, @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(201)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal(Ticket::State.lookup(name: 'new').id, result['state_id'])
|
||||||
|
assert_equal('a new ticket #16', result['title'])
|
||||||
|
assert_equal(@customer_without_org.id, result['customer_id'])
|
||||||
|
assert_equal(@agent.id, result['updated_by_id'])
|
||||||
|
assert_equal(@agent.id, result['created_by_id'])
|
||||||
|
|
||||||
|
ticket = Ticket.find(result['id'])
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal(2, ticket.articles.first.attachments.count)
|
||||||
|
file = ticket.articles.first.attachments[0]
|
||||||
|
assert_equal('006a2ca3793b550c8fe444acdeb39252', Digest::MD5.hexdigest(file.content))
|
||||||
|
assert_match(/#{ticket.id}\..+?@zammad.example.com/, file.filename)
|
||||||
|
assert_equal('image/jpeg', file.preferences['Mime-Type'])
|
||||||
|
assert(file.preferences['Content-ID'])
|
||||||
|
file = ticket.articles.first.attachments[1]
|
||||||
|
assert_equal('39d0d586a701e199389d954f2d592720', Digest::MD5.hexdigest(file.content))
|
||||||
|
assert_equal('some_file.txt', file.filename)
|
||||||
|
assert_equal('text/plain', file.preferences['Mime-Type'])
|
||||||
|
assert_not(file.preferences['Content-ID'])
|
||||||
|
end
|
||||||
|
|
||||||
test '02.02 ticket create with agent' do
|
test '02.02 ticket create with agent' do
|
||||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw')
|
||||||
params = {
|
params = {
|
||||||
|
|
|
@ -307,7 +307,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'article attachment helper' do
|
test 'article attachment helper 1' do
|
||||||
|
|
||||||
ticket1 = Ticket.create(
|
ticket1 = Ticket.create(
|
||||||
title: 'some article helper test1',
|
title: 'some article helper test1',
|
||||||
|
@ -376,10 +376,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||||
created_by_id: 1,
|
created_by_id: 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
article_attributes = Ticket::Article.insert_urls(
|
article_attributes = Ticket::Article.insert_urls(article1.attributes_with_association_ids)
|
||||||
article1.attributes,
|
|
||||||
article1.attachments,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_no_match('15.274327094.140938@zammad.example.com', article_attributes['body'])
|
assert_no_match('15.274327094.140938@zammad.example.com', article_attributes['body'])
|
||||||
assert_no_match('15.274327094.140939@zammad.example.com', article_attributes['body'])
|
assert_no_match('15.274327094.140939@zammad.example.com', article_attributes['body'])
|
||||||
|
@ -394,6 +391,92 @@ class TicketTest < ActiveSupport::TestCase
|
||||||
assert_equal(store1.id, attachments.first.id)
|
assert_equal(store1.id, attachments.first.id)
|
||||||
|
|
||||||
ticket1.destroy
|
ticket1.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'article attachment helper 2' do
|
||||||
|
|
||||||
|
ticket1 = Ticket.create(
|
||||||
|
title: 'some article helper test2',
|
||||||
|
group: Group.lookup(name: 'Users'),
|
||||||
|
customer_id: 2,
|
||||||
|
state: Ticket::State.lookup(name: 'new'),
|
||||||
|
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
assert(ticket1, 'ticket created')
|
||||||
|
|
||||||
|
# create inbound article #1
|
||||||
|
article1 = Ticket::Article.create(
|
||||||
|
ticket_id: ticket1.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
to: 'some_recipient@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
content_type: 'text/html',
|
||||||
|
body: 'some message article helper test2 <div><img src="cid:15.274327094.140938@zammad.example.com">asdasd<img border="0" width="60" height="19" src="cid:15.274327094.140939@zammad.example.com" alt="Beschreibung: Beschreibung: efqmLogo"><br>',
|
||||||
|
internal: false,
|
||||||
|
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||||
|
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
store1 = Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article1.id,
|
||||||
|
data: 'content_file1_normally_should_be_an_image',
|
||||||
|
filename: 'some_file1.jpg',
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => 'image/jpeg',
|
||||||
|
'Mime-Type' => 'image/jpeg',
|
||||||
|
'Content-ID' => '15.274327094.140938@zammad.example.com',
|
||||||
|
'Content-Disposition' => 'inline'
|
||||||
|
},
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
store2 = Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article1.id,
|
||||||
|
data: 'content_file2_normally_should_be_an_image',
|
||||||
|
filename: 'some_file2.jpg',
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => 'image/jpeg',
|
||||||
|
'Mime-Type' => 'image/jpeg',
|
||||||
|
'Content-ID' => '15.274327094.140939@zammad.example.com',
|
||||||
|
'Content-Disposition' => 'inline'
|
||||||
|
},
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
store3 = Store.add(
|
||||||
|
object: 'Ticket::Article',
|
||||||
|
o_id: article1.id,
|
||||||
|
data: 'content_file3',
|
||||||
|
filename: 'some_file3.txt',
|
||||||
|
preferences: {
|
||||||
|
'Content-Type' => 'text/stream',
|
||||||
|
'Mime-Type' => 'text/stream',
|
||||||
|
'Content-ID' => '15.274327094.99999@zammad.example.com',
|
||||||
|
'Content-Disposition' => 'inline'
|
||||||
|
},
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
article_attributes = Ticket::Article.insert_urls(article1.attributes_with_association_ids)
|
||||||
|
|
||||||
|
assert_no_match('15.274327094.140938@zammad.example.com', article_attributes['body'])
|
||||||
|
assert_no_match('15.274327094.140939@zammad.example.com', article_attributes['body'])
|
||||||
|
assert_no_match('15.274327094.99999@zammad.example.com', article_attributes['body'])
|
||||||
|
assert_match("api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store1.id}", article_attributes['body'])
|
||||||
|
assert_match("api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store2.id}", article_attributes['body'])
|
||||||
|
assert_no_match("api/v1/ticket_attachment/#{ticket1.id}/#{article1.id}/#{store3.id}", article_attributes['body'])
|
||||||
|
|
||||||
|
article1 = Ticket::Article.find(article1.id)
|
||||||
|
attachments = article1.attachments_inline
|
||||||
|
assert_equal(2, attachments.length)
|
||||||
|
assert_equal(store1.id, attachments.first.id)
|
||||||
|
|
||||||
|
ticket1.destroy
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
Loading…
Reference in a new issue