#1727 fix telegram channel issues

This commit is contained in:
Muhammad Nuzaihan 2018-01-05 16:02:51 +08:00
parent 93c7ffbfdb
commit b82dfc0d21
10 changed files with 344 additions and 15 deletions

View file

@ -30,6 +30,7 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
api = TelegramAPI.new(channel.options[:api_token]) api = TelegramAPI.new(channel.options[:api_token])
chat_id = ticket.preferences[:telegram][:chat_id] chat_id = ticket.preferences[:telegram][:chat_id]
result = api.sendMessage(chat_id, article.body) result = api.sendMessage(chat_id, article.body)
me = api.getMe()
article.attachments.each do |file| article.attachments.each do |file|
parts = file.filename.split(/^(.*)(\..+?)$/) parts = file.filename.split(/^(.*)(\..+?)$/)
t = Tempfile.new([parts[1], parts[2]]) t = Tempfile.new([parts[1], parts[2]])
@ -43,6 +44,10 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
return return
end end
Rails.logger.debug "result info: #{result}"
# only private, group messages. channel messages do not have from key
if result['from'] && result['chat']
# fill article with message info # fill article with message info
article.from = "@#{result['from']['username']}" article.from = "@#{result['from']['username']}"
article.to = "@#{result['chat']['username']}" article.to = "@#{result['chat']['username']}"
@ -53,6 +58,18 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
chat_id: result['chat']['id'], chat_id: result['chat']['id'],
message_id: result['message_id'] message_id: result['message_id']
} }
else
# fill article with message info (telegram channel)
article.from = "@#{me['username']}"
article.to = "#{result['chat']['title']} Channel"
article.preferences['telegram'] = {
date: result['date'],
from_id: me['id'],
chat_id: result['chat']['id'],
message_id: result['message_id']
}
end
# set delivery status # set delivery status
article.preferences['delivery_status_message'] = nil article.preferences['delivery_status_message'] = nil

View file

@ -30,9 +30,9 @@ class Transaction::Trigger
return if @item[:object] != 'Ticket' return if @item[:object] != 'Ticket'
triggers = if Rails.configuration.db_case_sensitive triggers = if Rails.configuration.db_case_sensitive
Trigger.where(active: true).order('LOWER(name)') ::Trigger.where(active: true).order('LOWER(name)')
else else
Trigger.where(active: true).order(:name) ::Trigger.where(active: true).order(:name)
end end
return if triggers.blank? return if triggers.blank?

View file

@ -470,7 +470,7 @@ returns
object: 'Ticket::Article', object: 'Ticket::Article',
o_id: article.id, o_id: article.id,
data: document_result.body, data: document_result.body,
filename: params[:message][:voice][:file_path] || 'audio', filename: params[:message][:voice][:file_path] || "audio-#{params[:message][:voice][:file_id]}.ogg",
preferences: { preferences: {
'Mime-Type' => params[:message][:voice][:mime_type], 'Mime-Type' => params[:message][:voice][:mime_type],
}, },
@ -489,7 +489,7 @@ returns
if !result.success? || !result.body if !result.success? || !result.body
raise "Unable for download image from telegram: #{result.code}" raise "Unable for download image from telegram: #{result.code}"
end end
body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(result.body)}\">" body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/webp;base64,#{Base64.strict_encode64(result.body)}\">"
article.content_type = 'text/html' article.content_type = 'text/html'
elsif emoji elsif emoji
article.content_type = 'text/plain' article.content_type = 'text/plain'
@ -508,9 +508,9 @@ returns
object: 'Ticket::Article', object: 'Ticket::Article',
o_id: article.id, o_id: article.id,
data: document_result.body, data: document_result.body,
filename: params[:message][:sticker][:file_name] || 'sticker', filename: params[:message][:sticker][:file_name] || "#{params[:message][:sticker][:set_name]}.webp",
preferences: { preferences: {
'Mime-Type' => params[:message][:sticker][:mime_type], 'Mime-Type' => 'image/webp', # mime type is not given from Telegram API but this is actually WebP
}, },
) )
end end
@ -528,8 +528,93 @@ returns
end end
def to_group(params, group_id, channel) def to_group(params, group_id, channel)
# begin import
Rails.logger.debug 'import message' Rails.logger.debug 'import message'
# map channel_post params to message
if params[:channel_post]
return if params[:channel_post][:new_chat_title] # happens when channel title is renamed, we use [:chat][:title] already, safely ignore this.
# note: used .blank? which is a rails method. empty? does not work on integers (values like date, width, height) to check.
# need delete_if to remove any empty hashes, .compact only removes keys with nil values.
params[:message] = {
document: {
file_name: params.dig(:channel_post, :document, :file_name),
mime_type: params.dig(:channel_post, :document, :mime_type),
file_id: params.dig(:channel_post, :document, :file_id),
file_size: params.dig(:channel_post, :document, :filesize),
thumb: {
file_id: params.dig(:channel_post, :document, :thumb, :file_id),
file_size: params.dig(:channel_post, :document, :thumb, :file_size),
width: params.dig(:channel_post, :document, :thumb, :width),
height: params.dig(:channel_post, :document, :thumb, :height)
}.compact
}.delete_if { |_, v| v.blank? },
voice: {
duration: params.dig(:channel_post, :voice, :duration),
mime_type: params.dig(:channel_post, :voice, :mime_type),
file_id: params.dig(:channel_post, :voice, :file_id),
file_size: params.dig(:channel_post, :voice, :file_size)
}.compact,
sticker: {
width: params.dig(:channel_post, :sticker, :width),
height: params.dig(:channel_post, :sticker, :height),
emoji: params.dig(:channel_post, :sticker, :emoji),
set_name: params.dig(:channel_post, :sticker, :set_name),
file_id: params.dig(:channel_post, :sticker, :file_id),
file_path: params.dig(:channel_post, :sticker, :file_path),
thumb: {
file_id: params.dig(:channel_post, :sticker, :thumb, :file_id),
file_size: params.dig(:channel_post, :sticker, :thumb, :file_size),
width: params.dig(:channel_post, :sticker, :thumb, :width),
height: params.dig(:channel_post, :sticker, :thumb, :file_id),
file_path: params.dig(:channel_post, :sticker, :thumb, :file_path)
}.compact
}.delete_if { |_, v| v.blank? },
chat: {
id: params.dig(:channel_post, :chat, :id),
first_name: params.dig(:channel_post, :chat, :title),
last_name: 'Channel',
username: "channel#{params.dig(:channel_post, :chat, :id)}"
},
from: {
id: params.dig(:channel_post, :chat, :id),
first_name: params.dig(:channel_post, :chat, :title),
last_name: 'Channel',
username: "channel#{params.dig(:channel_post, :chat, :id)}"
},
caption: (params.dig(:channel_post, :caption) ? params.dig(:channel_post, :caption) : {}),
date: params.dig(:channel_post, :date),
message_id: params.dig(:channel_post, :message_id),
text: params.dig(:channel_post, :text),
photo: (params[:channel_post][:photo].map { |photo| { file_id: photo[:file_id], file_size: photo[:file_size], width: photo[:width], height: photo[:height] } } if params.dig(:channel_post, :photo))
}.delete_if { |_, v| v.blank? }
params.delete(:channel_post) # discard unused :channel_post hash
end
# checks if the channel post is being edited, and map it when it is
if params[:edited_channel_post]
# updates on telegram can only be on messages, no attachments
params[:edited_message] = {
chat: {
id: params.dig(:edited_channel_post, :chat, :id),
first_name: params.dig(:edited_channel_post, :chat, :title),
last_name: 'Channel',
username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
},
from: {
id: params.dig(:edited_channel_post, :chat, :id),
first_name: params.dig(:edited_channel_post, :chat, :title),
last_name: 'Channel',
username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
},
date: params.dig(:edited_channel_post, :date),
edit_date: params.dig(:edited_channel_post, :edit_date),
message_id: params.dig(:edited_channel_post, :message_id),
text: params.dig(:edited_channel_post, :text)
}
params.delete(:edited_channel_post) # discard unused :edited_channel_post hash
end
# prevent multible update # prevent multible update
if !params[:edited_message] if !params[:edited_message]
return if Ticket::Article.find_by(message_id: Telegram.message_id(params)) return if Ticket::Article.find_by(message_id: Telegram.message_id(params))

View file

@ -0,0 +1,22 @@
{
"update_id":10001,
"channel_post":{
"date":1441645532,
"chat":{
"last_name":"Test Lastname",
"id":1111111,
"type":"channel",
"username":"Testusername"
},
"message_id":1365,
"text":"Hello, I need your Help",
"bid":"12345678",
"callback_token":"AbcDefG",
"entities": [
{"offset": 0,
"length": 6,
"type": "bot_command"
}
]
}
}

View file

@ -0,0 +1,27 @@
{
"update_id": 30003,
"channel_post": {
"message_id": 3367,
"chat": {
"title": "Zammad Bot",
"id":1111112,
"type": "channel"
},
"date": 1486036832,
"document": {
"file_name": "blockposter-162412.pdf",
"mime_type": "application/pdf",
"thumb": {
"file_id": "AAQCABO0I4INAATATQAB5HWPq4XgxQACAg",
"file_size": 8752,
"width": 200,
"height": 200
},
"caption": "test",
"file_id": "BQADAgADDgAD7x6ZSC_-1LMkOEmoAg",
"file_size": 3622849,
"bid": "435791794",
"callback_token": "z5N_uxY_Fut81g"
}
}
}

View file

@ -0,0 +1,34 @@
{
"update_id": 30002,
"channel_post": {
"message_id": 3366,
"chat": {
"title":"Zammad Bot",
"id":1111112,
"type": "channel"
},
"date": 1486036832,
"photo": [
{
"file_id": "ABC-123VabcOcv123w0ABBL_aoY-F849YYABC",
"file_size": 1016,
"width": 90,
"height": 82
},
{
"file_id": "ABC-123VabcOcv123w0ABPlhIiVSfO9TYoABC",
"file_size": 7378,
"width": 320,
"height": 291
},
{
"file_id": "ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC",
"file_size": 16433,
"width": 720,
"height": 654
}
],
"bid":"435791794",
"callback_token":"z5N_uxY_Fut81g"
}
}

View file

@ -0,0 +1,20 @@
{
"update_id":30005,
"channel_post":{
"message_id":3368,
"chat":{
"title": "Zammad Bot",
"id":1111112,
"type": "channel"
},
"date":1487119496,
"voice":{
"duration":1,
"mime_type":"audio/ogg",
"file_id":"AwADAgADVQADCEIYSZwyOmSZK9iZAg",
"file_size":6030
},
"bid": "435791794",
"callback_token":"z5N_uxY_Fut81g"
}
}

View file

@ -0,0 +1,30 @@
{
"update_id":40000,
"channel_post":{
"message_id":273,
"chat":{
"id":3310000,
"type":"channel",
"title":"Zammad Bot"
},
"date":1487161566,
"sticker":{
"width":512,
"height":512,
"emoji":"💻",
"set_name": "ChristmasGoose",
"thumb":{
"file_id":"AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC",
"file_size":4584,
"width":128,
"height":128,
"file_path": "thumbnails/file57.jpg"
},
"file_id":"BQADAwAD0QIAAqbJWAAB8OkQqgtDQe0C",
"file_size":25974,
"file_path": "stickers/file_58.webp"
},
"callback_token":"z5N_uxY_Fut81g",
"bid":"435791794"
}
}

View file

@ -0,0 +1,22 @@
{
"update_id":10001,
"edited_channel_post":{
"date":1441645532,
"chat":{
"last_name":"Test Lastname",
"id":1111111,
"type":"channel",
"username":"Testusername"
},
"message_id":1365,
"text":"Hello, I need your Help",
"bid":"12345678",
"callback_token":"AbcDefG",
"entities": [
{"offset": 0,
"length": 6,
"type": "bot_command"
}
]
}
}

View file

@ -105,6 +105,28 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
assert_equal('Hello, I need your Help', ticket.articles.first.body) assert_equal('Hello, I need your Help', ticket.articles.first.body)
assert_equal('text/plain', ticket.articles.first.content_type) assert_equal('text/plain', ticket.articles.first.content_type)
# send channel message1
post callback_url, params: read_messaage('channel1_message_content1'), headers: @headers
assert_response(200)
assert_equal(1, Ticket.count)
ticket = Ticket.last
assert_equal('Hello, I need your Help', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal(1, ticket.articles.count)
assert_equal('Hello, I need your Help', ticket.articles.first.body)
assert_equal('text/plain', ticket.articles.first.content_type)
# edit channel message1
post callback_url, params: read_messaage('channel2_message_content1'), headers: @headers
assert_response(200)
assert_equal(1, Ticket.count)
ticket = Ticket.last
assert_equal('Hello, I need your Help', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal(1, ticket.articles.count)
assert_equal('Hello, I need your Help', ticket.articles.first.body)
assert_equal('text/plain', ticket.articles.first.content_type)
# send same message again, ignore it # send same message again, ignore it
post callback_url, params: read_messaage('personal1_message_content1'), headers: @headers post callback_url, params: read_messaage('personal1_message_content1'), headers: @headers
assert_response(200) assert_response(200)
@ -193,6 +215,17 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
assert_match(/<img style="width:360px;height:327px;"/i, ticket.articles.last.body) assert_match(/<img style="width:360px;height:327px;"/i, ticket.articles.last.body)
assert_equal('text/html', ticket.articles.last.content_type) assert_equal('text/html', ticket.articles.last.content_type)
# send channel message 3
post callback_url, params: read_messaage('channel1_message_content3'), headers: @headers
assert_response(200)
assert_equal(3, Ticket.count)
ticket = Ticket.last
assert_equal('Can you help me with my feature?', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal(2, ticket.articles.count)
assert_match(/<img style="width:360px;height:327px;"/i, ticket.articles.last.body)
assert_equal('text/html', ticket.articles.last.content_type)
# send message3 # send message3
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
.with(body: { 'file_id' => 'AAQCABO0I4INAATATQAB5HWPq4XgxQACAg' }) .with(body: { 'file_id' => 'AAQCABO0I4INAATATQAB5HWPq4XgxQACAg' })
@ -214,6 +247,18 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
assert_equal('text/html', ticket.articles.last.content_type) assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count) assert_equal(1, ticket.articles.last.attachments.count)
# isend channel message 2
post callback_url, params: read_messaage('channel1_message_content2'), headers: @headers
assert_response(200)
assert_equal(3, Ticket.count)
ticket = Ticket.last
assert_equal('Can you help me with my feature?', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal(3, ticket.articles.count)
assert_match(/<img style="width:200px;height:200px;"/i, ticket.articles.last.body)
assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count)
# update message1 # update message1
post callback_url, params: read_messaage('personal3_message_content4'), headers: @headers post callback_url, params: read_messaage('personal3_message_content4'), headers: @headers
assert_response(200) assert_response(200)
@ -244,6 +289,17 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
assert_equal('text/html', ticket.articles.last.content_type) assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count) assert_equal(1, ticket.articles.last.attachments.count)
# send channel message 4 with voice
post callback_url, params: read_messaage('channel1_message_content4'), headers: @headers
assert_response(200)
assert_equal(3, Ticket.count)
ticket = Ticket.last
assert_equal('Can you help me with my feature?', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal(4, ticket.articles.count)
assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count)
# start communication #4 - with sticker # start communication #4 - with sticker
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
.with(body: { 'file_id' => 'AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC' }) .with(body: { 'file_id' => 'AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC' })
@ -267,6 +323,22 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
assert_equal('text/html', ticket.articles.last.content_type) assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count) assert_equal(1, ticket.articles.last.attachments.count)
# send channel message #5 with sticker
post callback_url, params: read_messaage('channel1_message_content5'), headers: @headers
assert_response(200)
assert_equal(4, Ticket.count)
ticket = Ticket.last
if Rails.application.config.db_4bytes_utf8
assert_equal('💻', ticket.title)
else
assert_equal('', ticket.title)
end
assert_equal('new', ticket.state.name)
assert_equal(1, ticket.articles.count)
assert_match(/<img style="/i, ticket.articles.last.body)
assert_equal('text/html', ticket.articles.last.content_type)
assert_equal(1, ticket.articles.last.attachments.count)
# start communication #5 - with photo # start communication #5 - with photo
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
.with(body: { 'file_id' => 'AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC' }) .with(body: { 'file_id' => 'AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC' })