#1727 fix telegram channel issues
This commit is contained in:
parent
93c7ffbfdb
commit
b82dfc0d21
10 changed files with 344 additions and 15 deletions
|
@ -30,6 +30,7 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
|
|||
api = TelegramAPI.new(channel.options[:api_token])
|
||||
chat_id = ticket.preferences[:telegram][:chat_id]
|
||||
result = api.sendMessage(chat_id, article.body)
|
||||
me = api.getMe()
|
||||
article.attachments.each do |file|
|
||||
parts = file.filename.split(/^(.*)(\..+?)$/)
|
||||
t = Tempfile.new([parts[1], parts[2]])
|
||||
|
@ -43,6 +44,10 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
|
|||
return
|
||||
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
|
||||
article.from = "@#{result['from']['username']}"
|
||||
article.to = "@#{result['chat']['username']}"
|
||||
|
@ -53,6 +58,18 @@ class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
|
|||
chat_id: result['chat']['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
|
||||
article.preferences['delivery_status_message'] = nil
|
||||
|
|
|
@ -30,9 +30,9 @@ class Transaction::Trigger
|
|||
return if @item[:object] != 'Ticket'
|
||||
|
||||
triggers = if Rails.configuration.db_case_sensitive
|
||||
Trigger.where(active: true).order('LOWER(name)')
|
||||
::Trigger.where(active: true).order('LOWER(name)')
|
||||
else
|
||||
Trigger.where(active: true).order(:name)
|
||||
::Trigger.where(active: true).order(:name)
|
||||
end
|
||||
return if triggers.blank?
|
||||
|
||||
|
|
|
@ -470,7 +470,7 @@ returns
|
|||
object: 'Ticket::Article',
|
||||
o_id: article.id,
|
||||
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: {
|
||||
'Mime-Type' => params[:message][:voice][:mime_type],
|
||||
},
|
||||
|
@ -489,7 +489,7 @@ returns
|
|||
if !result.success? || !result.body
|
||||
raise "Unable for download image from telegram: #{result.code}"
|
||||
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'
|
||||
elsif emoji
|
||||
article.content_type = 'text/plain'
|
||||
|
@ -508,9 +508,9 @@ returns
|
|||
object: 'Ticket::Article',
|
||||
o_id: article.id,
|
||||
data: document_result.body,
|
||||
filename: params[:message][:sticker][:file_name] || 'sticker',
|
||||
filename: params[:message][:sticker][:file_name] || "#{params[:message][:sticker][:set_name]}.webp",
|
||||
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
|
||||
|
@ -528,8 +528,93 @@ returns
|
|||
end
|
||||
|
||||
def to_group(params, group_id, channel)
|
||||
# begin import
|
||||
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
|
||||
if !params[:edited_message]
|
||||
return if Ticket::Article.find_by(message_id: Telegram.message_id(params))
|
||||
|
|
22
test/fixtures/telegram/channel1_message_content1.json
vendored
Normal file
22
test/fixtures/telegram/channel1_message_content1.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
27
test/fixtures/telegram/channel1_message_content2.json
vendored
Normal file
27
test/fixtures/telegram/channel1_message_content2.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
34
test/fixtures/telegram/channel1_message_content3.json
vendored
Normal file
34
test/fixtures/telegram/channel1_message_content3.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
20
test/fixtures/telegram/channel1_message_content4.json
vendored
Normal file
20
test/fixtures/telegram/channel1_message_content4.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
30
test/fixtures/telegram/channel1_message_content5.json
vendored
Normal file
30
test/fixtures/telegram/channel1_message_content5.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
22
test/fixtures/telegram/channel2_message_content1.json
vendored
Normal file
22
test/fixtures/telegram/channel2_message_content1.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -105,6 +105,28 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_equal('Hello, I need your Help', ticket.articles.first.body)
|
||||
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
|
||||
post callback_url, params: read_messaage('personal1_message_content1'), headers: @headers
|
||||
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_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
|
||||
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
|
||||
.with(body: { 'file_id' => 'AAQCABO0I4INAATATQAB5HWPq4XgxQACAg' })
|
||||
|
@ -214,6 +247,18 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_equal('text/html', ticket.articles.last.content_type)
|
||||
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
|
||||
post callback_url, params: read_messaage('personal3_message_content4'), headers: @headers
|
||||
assert_response(200)
|
||||
|
@ -244,6 +289,17 @@ class TelegramControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_equal('text/html', ticket.articles.last.content_type)
|
||||
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
|
||||
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
|
||||
.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(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
|
||||
stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
|
||||
.with(body: { 'file_id' => 'AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC' })
|
||||
|
|
Loading…
Reference in a new issue