telegram_helper.rb 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'telegram/bot'
  3. class TelegramHelper
  4. attr_accessor :client
  5. =begin
  6. check token and return bot attributes of token
  7. bot = TelegramHelper.check_token('token')
  8. =end
  9. def self.check_token(token)
  10. result = nil
  11. begin
  12. Telegram::Bot::Client.run(token) do |bot|
  13. result = bot.api.getMe
  14. end
  15. rescue
  16. raise Exceptions::UnprocessableEntity, 'invalid api token'
  17. end
  18. result
  19. end
  20. =begin
  21. set webhook for bot
  22. success = TelegramHelper.set_webhook('token', callback_url)
  23. returns
  24. true|false
  25. =end
  26. def self.set_webhook(token, callback_url)
  27. if callback_url.match?(%r{^http://}i)
  28. raise Exceptions::UnprocessableEntity, __('The Telegram integration can only be configured on systems using the HTTPS protocol.')
  29. end
  30. begin
  31. Telegram::Bot::Client.run(token) do |bot|
  32. bot.api.setWebhook(url: callback_url)
  33. end
  34. rescue
  35. raise Exceptions::UnprocessableEntity, __('The webhook could not be saved by Telegram, seems to be an invalid URL.')
  36. end
  37. true
  38. end
  39. =begin
  40. create or update channel, store bot attributes and verify token
  41. channel = TelegramHelper.create_or_update_channel('token', params)
  42. returns
  43. channel # instance of Channel
  44. =end
  45. def self.create_or_update_channel(token, params, channel = nil)
  46. # verify token
  47. bot = check_token(token)
  48. if !channel && bot_duplicate?(bot.id)
  49. raise Exceptions::UnprocessableEntity, __('This bot already exists.')
  50. end
  51. if params[:group_id].blank?
  52. raise Exceptions::UnprocessableEntity, __("The required parameter 'group_id' is missing.")
  53. end
  54. group = Group.find_by(id: params[:group_id])
  55. if !group
  56. raise Exceptions::UnprocessableEntity, __("The required parameter 'group_id' is invalid.")
  57. end
  58. # generate random callback token
  59. callback_token = if Rails.env.test?
  60. 'callback_token'
  61. else
  62. SecureRandom.urlsafe_base64(10)
  63. end
  64. # set webhook / callback url for this bot @ telegram
  65. callback_url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/channels_telegram_webhook/#{callback_token}?bid=#{bot.id}"
  66. set_webhook(token, callback_url)
  67. if !channel
  68. channel = bot_by_bot_id(bot.id)
  69. if !channel
  70. channel = Channel.new
  71. end
  72. end
  73. channel.area = 'Telegram::Bot'
  74. channel.options = {
  75. bot: {
  76. id: bot.id,
  77. username: bot.username,
  78. first_name: bot.first_name,
  79. last_name: bot.last_name,
  80. },
  81. callback_token: callback_token,
  82. callback_url: callback_url,
  83. api_token: token,
  84. welcome: params[:welcome],
  85. goodbye: params[:goodbye],
  86. }
  87. channel.group_id = group.id
  88. channel.active = true
  89. channel.save!
  90. channel
  91. end
  92. =begin
  93. check if bot already exists as channel
  94. success = TelegramHelper.bot_duplicate?(bot_id)
  95. returns
  96. channel # instance of Channel
  97. =end
  98. def self.bot_duplicate?(bot_id, channel_id = nil)
  99. Channel.where(area: 'Telegram::Bot').each do |channel|
  100. next if !channel.options
  101. next if !channel.options[:bot]
  102. next if !channel.options[:bot][:id]
  103. next if channel.options[:bot][:id] != bot_id
  104. next if channel.id.to_s == channel_id.to_s
  105. return true
  106. end
  107. false
  108. end
  109. =begin
  110. get channel by bot_id
  111. channel = TelegramHelper.bot_by_bot_id(bot_id)
  112. returns
  113. true|false
  114. =end
  115. def self.bot_by_bot_id(bot_id)
  116. Channel.where(area: 'Telegram::Bot').each do |channel|
  117. next if !channel.options
  118. next if !channel.options[:bot]
  119. next if !channel.options[:bot][:id]
  120. return channel if channel.options[:bot][:id].to_s == bot_id.to_s
  121. end
  122. nil
  123. end
  124. =begin
  125. generate message_id for message
  126. message_id = TelegramHelper.message_id(message)
  127. returns
  128. message_id # 123456@telegram
  129. =end
  130. def self.message_id(params)
  131. message_id = nil
  132. %i[message edited_message].each do |key|
  133. next if !params[key]
  134. next if !params[key][:message_id]
  135. message_id = params[key][:message_id]
  136. break
  137. end
  138. if message_id
  139. %i[message edited_message].each do |key|
  140. next if !params[key]
  141. next if !params[key][:chat]
  142. next if !params[key][:chat][:id]
  143. message_id = "#{message_id}.#{params[key][:chat][:id]}"
  144. end
  145. end
  146. if !message_id
  147. message_id = params[:update_id]
  148. end
  149. "#{message_id}@telegram"
  150. end
  151. =begin
  152. client = TelegramHelper.new('token')
  153. =end
  154. def initialize(token)
  155. @token = token
  156. end
  157. =begin
  158. client.message(chat_id, 'some message', language_code)
  159. =end
  160. def message(chat_id, message, language_code = 'en')
  161. return if Rails.env.test?
  162. locale = Locale.find_by(alias: language_code)
  163. if !locale
  164. locale = Locale.where('locale LIKE :prefix', prefix: "#{SqlHelper.quote_like(language_code)}%").first
  165. end
  166. if locale
  167. message = Translation.translate(locale[:locale], message)
  168. end
  169. Telegram::Bot::Client.run(@token) do |bot|
  170. bot.api.sendMessage(chat_id: chat_id, text: message)
  171. end
  172. end
  173. def user(params)
  174. {
  175. id: params[:message][:from][:id],
  176. username: params[:message][:from][:username],
  177. first_name: params[:message][:from][:first_name],
  178. last_name: params[:message][:from][:last_name]
  179. }
  180. end
  181. def to_user(params)
  182. Rails.logger.debug { 'Create user from message...' }
  183. Rails.logger.debug { params.inspect }
  184. # do message_user lookup
  185. message_user = user(params)
  186. auth = Authorization.find_by(uid: message_user[:id], provider: 'telegram')
  187. # create or update user
  188. login = message_user[:username] || message_user[:id]
  189. user_data = {
  190. login: login,
  191. firstname: message_user[:first_name],
  192. lastname: message_user[:last_name],
  193. }
  194. if auth
  195. user = User.find(auth.user_id)
  196. user.update!(user_data)
  197. else
  198. if message_user[:username]
  199. user_data[:note] = "Telegram @#{message_user[:username]}"
  200. end
  201. user_data[:active] = true
  202. user_data[:role_ids] = Role.signup_role_ids
  203. user = User.create(user_data)
  204. end
  205. # create or update authorization
  206. auth_data = {
  207. uid: message_user[:id],
  208. username: login,
  209. user_id: user.id,
  210. provider: 'telegram'
  211. }
  212. if auth
  213. auth.update!(auth_data)
  214. else
  215. Authorization.create(auth_data)
  216. end
  217. user
  218. end
  219. def to_ticket(params, user, group_id, channel)
  220. UserInfo.current_user_id = user.id
  221. Rails.logger.debug { 'Create ticket from message...' }
  222. Rails.logger.debug { params.inspect }
  223. Rails.logger.debug { user.inspect }
  224. Rails.logger.debug { group_id.inspect }
  225. # prepare title
  226. title = '-'
  227. %i[text caption].each do |area|
  228. next if !params[:message]
  229. next if !params[:message][area]
  230. title = params[:message][area]
  231. break
  232. end
  233. if title == '-'
  234. %i[sticker photo document voice].each do |area|
  235. next if !params[:message]
  236. next if !params[:message][area]
  237. next if !params[:message][area][:emoji]
  238. title = params[:message][area][:emoji]
  239. break
  240. rescue
  241. # just go ahead
  242. title
  243. end
  244. end
  245. if title.length > 60
  246. title = "#{title[0, 60]}..."
  247. end
  248. # find ticket or create one
  249. state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
  250. possible_tickets = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).reorder(:updated_at)
  251. ticket = possible_tickets.find_each.find { |possible_ticket| possible_ticket.preferences[:channel_id] == channel.id }
  252. if ticket
  253. # check if title needs to be updated
  254. if ticket.title == '-'
  255. ticket.title = title
  256. end
  257. new_state = Ticket::State.find_by(default_create: true)
  258. if ticket.state_id != new_state.id
  259. ticket.state = Ticket::State.find_by(default_follow_up: true)
  260. end
  261. ticket.save!
  262. return ticket
  263. end
  264. ticket = Ticket.new(
  265. group_id: group_id,
  266. title: title,
  267. state_id: Ticket::State.find_by(default_create: true).id,
  268. priority_id: Ticket::Priority.find_by(default_create: true).id,
  269. customer_id: user.id,
  270. preferences: {
  271. channel_id: channel.id,
  272. telegram: {
  273. bid: params['bid'],
  274. chat_id: params[:message][:chat][:id]
  275. }
  276. },
  277. )
  278. ticket.save!
  279. ticket
  280. end
  281. def to_article(params, user, ticket, channel, article = nil)
  282. if article
  283. Rails.logger.debug { 'Update article from message...' }
  284. else
  285. Rails.logger.debug { 'Create article from message...' }
  286. end
  287. Rails.logger.debug { params.inspect }
  288. Rails.logger.debug { user.inspect }
  289. Rails.logger.debug { ticket.inspect }
  290. UserInfo.current_user_id = user.id
  291. if article
  292. article.preferences[:edited_message] = {
  293. message: {
  294. created_at: params[:message][:date],
  295. message_id: params[:message][:message_id],
  296. from: params[:message][:from],
  297. },
  298. update_id: params[:update_id],
  299. }
  300. else
  301. article = Ticket::Article.new(
  302. ticket_id: ticket.id,
  303. type_id: Ticket::Article::Type.find_by(name: 'telegram personal-message').id,
  304. sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
  305. from: user(params)[:username],
  306. to: "@#{channel[:options][:bot][:username]}",
  307. message_id: TelegramHelper.message_id(params),
  308. internal: false,
  309. preferences: {
  310. message: {
  311. created_at: params[:message][:date],
  312. message_id: params[:message][:message_id],
  313. from: params[:message][:from],
  314. },
  315. update_id: params[:update_id],
  316. }
  317. )
  318. end
  319. # add photo
  320. if params[:message][:photo]
  321. # find photo with best resolution for us
  322. photo = nil
  323. max_width = 650 * 2
  324. last_width = 0
  325. last_height = 0
  326. params[:message][:photo].each do |file|
  327. if !photo
  328. photo = file
  329. last_width = file['width'].to_i
  330. last_height = file['height'].to_i
  331. end
  332. next if file['width'].to_i >= max_width || file['width'].to_i <= last_width
  333. photo = file
  334. last_width = file['width'].to_i
  335. last_height = file['height'].to_i
  336. end
  337. if last_width > 650
  338. last_width = (last_width / 2).to_i
  339. last_height = (last_height / 2).to_i
  340. end
  341. # download photo
  342. photo_result = get_file(params, photo)
  343. body = "<img style=\"width:#{last_width}px;height:#{last_height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(photo_result.body)}\">"
  344. if params[:message][:caption]
  345. body += "<br>#{params[:message][:caption].text2html}"
  346. end
  347. article.content_type = 'text/html'
  348. article.body = body
  349. article.save!
  350. return article
  351. end
  352. # add document
  353. if params[:message][:document]
  354. document = params[:message][:document]
  355. thumb = params[:message][:document][:thumb]
  356. body = '&nbsp;'
  357. if thumb
  358. width = thumb[:width]
  359. height = thumb[:height]
  360. thumb_result = get_file(params, thumb)
  361. body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
  362. end
  363. if params[:message][:caption]
  364. body += "<br>#{params[:message][:caption].text2html}"
  365. end
  366. document_result = get_file(params, document)
  367. article.content_type = 'text/html'
  368. article.body = body
  369. article.save!
  370. Store.remove(
  371. object: 'Ticket::Article',
  372. o_id: article.id,
  373. )
  374. Store.create!(
  375. object: 'Ticket::Article',
  376. o_id: article.id,
  377. data: document_result.body,
  378. filename: document[:file_name],
  379. preferences: {
  380. 'Mime-Type' => document[:mime_type],
  381. },
  382. )
  383. return article
  384. end
  385. # add video
  386. if params[:message][:video]
  387. video = params[:message][:video]
  388. thumb = params[:message][:video][:thumb]
  389. body = '&nbsp;'
  390. if thumb
  391. width = thumb[:width]
  392. height = thumb[:height]
  393. thumb_result = get_file(params, thumb)
  394. body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
  395. end
  396. if params[:message][:caption]
  397. body += "<br>#{params[:message][:caption].text2html}"
  398. end
  399. video_result = get_file(params, video)
  400. article.content_type = 'text/html'
  401. article.body = body
  402. article.save!
  403. Store.remove(
  404. object: 'Ticket::Article',
  405. o_id: article.id,
  406. )
  407. # get video type
  408. type = video[:mime_type].gsub(%r{(.+/)}, '')
  409. Store.create!(
  410. object: 'Ticket::Article',
  411. o_id: article.id,
  412. data: video_result.body,
  413. filename: video[:file_name] || "video-#{video[:file_id]}.#{type}",
  414. preferences: {
  415. 'Mime-Type' => video[:mime_type],
  416. },
  417. )
  418. return article
  419. end
  420. # add voice
  421. if params[:message][:voice]
  422. voice = params[:message][:voice]
  423. body = '&nbsp;'
  424. if params[:message][:caption]
  425. body = "<br>#{params[:message][:caption].text2html}"
  426. end
  427. document_result = get_file(params, voice)
  428. article.content_type = 'text/html'
  429. article.body = body
  430. article.save!
  431. Store.remove(
  432. object: 'Ticket::Article',
  433. o_id: article.id,
  434. )
  435. Store.create!(
  436. object: 'Ticket::Article',
  437. o_id: article.id,
  438. data: document_result.body,
  439. filename: voice[:file_path] || "audio-#{voice[:file_id]}.ogg",
  440. preferences: {
  441. 'Mime-Type' => voice[:mime_type],
  442. },
  443. )
  444. return article
  445. end
  446. # add sticker
  447. if params[:message][:sticker]
  448. sticker = params[:message][:sticker]
  449. emoji = sticker[:emoji]
  450. thumb = sticker[:thumb]
  451. body = '&nbsp;'
  452. if thumb
  453. width = thumb[:width]
  454. height = thumb[:height]
  455. thumb_result = get_file(params, thumb)
  456. body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/webp;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
  457. article.content_type = 'text/html'
  458. elsif emoji
  459. article.content_type = 'text/plain'
  460. body = emoji
  461. end
  462. article.body = body
  463. article.save!
  464. if sticker[:file_id]
  465. document_result = get_file(params, sticker)
  466. Store.remove(
  467. object: 'Ticket::Article',
  468. o_id: article.id,
  469. )
  470. Store.create!(
  471. object: 'Ticket::Article',
  472. o_id: article.id,
  473. data: document_result.body,
  474. filename: sticker[:file_name] || "#{sticker[:set_name]}.webp",
  475. preferences: {
  476. 'Mime-Type' => 'image/webp', # mime type is not given from Telegram API but this is actually WebP
  477. },
  478. )
  479. end
  480. return article
  481. end
  482. # add text
  483. if params[:message][:text]
  484. article.content_type = 'text/plain'
  485. article.body = params[:message][:text]
  486. article.save!
  487. return article
  488. end
  489. raise Exceptions::UnprocessableEntity, 'invalid telegram message'
  490. end
  491. def to_group(params, group_id, channel)
  492. # begin import
  493. Rails.logger.debug { 'import message' }
  494. # map channel_post params to message
  495. if params[:channel_post]
  496. return if params[:channel_post][:new_chat_title] # happens when channel title is renamed, we use [:chat][:title] already, safely ignore this.
  497. # NOTE: used .blank? which is a rails method. empty? does not work on integers (values like date, width, height) to check.
  498. # need delete_if to remove any empty hashes, .compact only removes keys with nil values.
  499. params[:message] = {
  500. document: {
  501. file_name: params.dig(:channel_post, :document, :file_name),
  502. mime_type: params.dig(:channel_post, :document, :mime_type),
  503. file_id: params.dig(:channel_post, :document, :file_id),
  504. file_size: params.dig(:channel_post, :document, :file_size),
  505. thumb: {
  506. file_id: params.dig(:channel_post, :document, :thumb, :file_id),
  507. file_size: params.dig(:channel_post, :document, :thumb, :file_size),
  508. width: params.dig(:channel_post, :document, :thumb, :width),
  509. height: params.dig(:channel_post, :document, :thumb, :height)
  510. }.compact
  511. }.compact_blank!,
  512. video: {
  513. duration: params.dig(:channel_post, :video, :duration),
  514. width: params.dig(:channel_post, :video, :width),
  515. height: params.dig(:channel_post, :video, :height),
  516. mime_type: params.dig(:channel_post, :video, :mime_type),
  517. file_id: params.dig(:channel_post, :video, :file_id),
  518. file_size: params.dig(:channel_post, :video, :file_size),
  519. thumb: {
  520. file_id: params.dig(:channel_post, :video, :thumb, :file_id),
  521. file_size: params.dig(:channel_post, :video, :thumb, :file_size),
  522. width: params.dig(:channel_post, :video, :thumb, :width),
  523. height: params.dig(:channel_post, :video, :thumb, :height)
  524. }.compact
  525. }.compact_blank!,
  526. voice: {
  527. duration: params.dig(:channel_post, :voice, :duration),
  528. mime_type: params.dig(:channel_post, :voice, :mime_type),
  529. file_id: params.dig(:channel_post, :voice, :file_id),
  530. file_size: params.dig(:channel_post, :voice, :file_size)
  531. }.compact,
  532. sticker: {
  533. width: params.dig(:channel_post, :sticker, :width),
  534. height: params.dig(:channel_post, :sticker, :height),
  535. emoji: params.dig(:channel_post, :sticker, :emoji),
  536. set_name: params.dig(:channel_post, :sticker, :set_name),
  537. file_id: params.dig(:channel_post, :sticker, :file_id),
  538. file_path: params.dig(:channel_post, :sticker, :file_path),
  539. file_size: params.dig(:channel_post, :sticker, :file_size),
  540. thumb: {
  541. file_id: params.dig(:channel_post, :sticker, :thumb, :file_id),
  542. file_size: params.dig(:channel_post, :sticker, :thumb, :file_size),
  543. width: params.dig(:channel_post, :sticker, :thumb, :width),
  544. height: params.dig(:channel_post, :sticker, :thumb, :height),
  545. file_path: params.dig(:channel_post, :sticker, :thumb, :file_path)
  546. }.compact
  547. }.compact_blank!,
  548. chat: {
  549. id: params.dig(:channel_post, :chat, :id),
  550. first_name: params.dig(:channel_post, :chat, :title),
  551. last_name: 'Channel',
  552. username: "channel#{params.dig(:channel_post, :chat, :id)}"
  553. },
  554. from: {
  555. id: params.dig(:channel_post, :chat, :id),
  556. first_name: params.dig(:channel_post, :chat, :title),
  557. last_name: 'Channel',
  558. username: "channel#{params.dig(:channel_post, :chat, :id)}"
  559. },
  560. caption: params.dig(:channel_post, :caption) || {},
  561. date: params.dig(:channel_post, :date),
  562. message_id: params.dig(:channel_post, :message_id),
  563. text: params.dig(:channel_post, :text),
  564. 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))
  565. }.compact_blank!
  566. params.delete(:channel_post) # discard unused :channel_post hash
  567. end
  568. # checks if the channel post is being edited, and map it when it is
  569. if params[:edited_channel_post]
  570. # updates on telegram can only be on messages, no attachments
  571. params[:edited_message] = {
  572. chat: {
  573. id: params.dig(:edited_channel_post, :chat, :id),
  574. first_name: params.dig(:edited_channel_post, :chat, :title),
  575. last_name: 'Channel',
  576. username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
  577. },
  578. from: {
  579. id: params.dig(:edited_channel_post, :chat, :id),
  580. first_name: params.dig(:edited_channel_post, :chat, :title),
  581. last_name: 'Channel',
  582. username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
  583. },
  584. date: params.dig(:edited_channel_post, :date),
  585. edit_date: params.dig(:edited_channel_post, :edit_date),
  586. message_id: params.dig(:edited_channel_post, :message_id),
  587. text: params.dig(:edited_channel_post, :text)
  588. }
  589. params.delete(:edited_channel_post) # discard unused :edited_channel_post hash
  590. end
  591. # prevent multiple update
  592. return if !params[:edited_message] && Ticket::Article.exists?(message_id: TelegramHelper.message_id(params))
  593. # update article
  594. if params[:edited_message]
  595. article = Ticket::Article.find_by(message_id: TelegramHelper.message_id(params))
  596. return if !article
  597. params[:message] = params[:edited_message]
  598. user = to_user(params)
  599. to_article(params, user, article.ticket, channel, article)
  600. return article
  601. end
  602. # send welcome message and don't create ticket
  603. text = params[:message][:text]
  604. if text.present? && text.start_with?('/start')
  605. message(params[:message][:chat][:id], channel.options[:welcome] || __('Welcome! Feel free to ask me a question!'), params[:message][:from][:language_code])
  606. return
  607. # find ticket and close it
  608. elsif text.present? && text.start_with?('/end')
  609. user = to_user(params)
  610. # get the last ticket of customer which is not closed yet, and close it
  611. state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
  612. possible_tickets = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).reorder(:updated_at)
  613. ticket = possible_tickets.find_each.find { |possible_ticket| possible_ticket.preferences[:channel_id] == channel.id }
  614. return if !ticket
  615. ticket.state = Ticket::State.find_by(name: 'closed')
  616. ticket.save!
  617. return if !channel.options[:goodbye]
  618. message(params[:message][:chat][:id], channel.options[:goodbye], params[:message][:from][:language_code])
  619. return
  620. end
  621. ticket = nil
  622. # use transaction
  623. Transaction.execute(reset_user_id: true, context: 'telegram') do
  624. user = to_user(params)
  625. ticket = to_ticket(params, user, group_id, channel)
  626. to_article(params, user, ticket, channel)
  627. end
  628. ticket
  629. end
  630. def from_article(article)
  631. Rails.logger.debug { "Create telegram personal message from article to '#{article[:to]}'..." }
  632. message = {}
  633. # TODO: create telegram message here
  634. Rails.logger.debug { message.inspect }
  635. message
  636. end
  637. def get_file(params, file)
  638. # telegram bot files are limited up to 20MB
  639. # https://core.telegram.org/bots/api#getfile
  640. if !validate_file_size(file)
  641. message_text = __('The Telegram file is larger than the allowed 20 MB.')
  642. message(params[:message][:chat][:id], "Sorry, we could not handle your message. #{message_text}", params[:message][:from][:language_code])
  643. raise Exceptions::UnprocessableEntity, message_text
  644. end
  645. result = download_file(file[:file_id])
  646. if !validate_download(result)
  647. message_text = __('The file could not be retrieved from the bot.')
  648. message(params[:message][:chat][:id], "Sorry, we could not handle your message. #{message_text}", params[:message][:from][:language_code])
  649. raise Exceptions::UnprocessableEntity, message_text
  650. end
  651. result
  652. end
  653. def download_file(file_id)
  654. document = nil
  655. Telegram::Bot::Client.run(@token) do |bot|
  656. document = bot.api.getFile(file_id: file_id)
  657. end
  658. url = "https://api.telegram.org/file/bot#{@token}/#{document.file_path}"
  659. UserAgent.get(
  660. url,
  661. {},
  662. {
  663. open_timeout: 20,
  664. read_timeout: 40,
  665. verify_ssl: true,
  666. },
  667. )
  668. end
  669. def validate_file_size(file)
  670. Rails.logger.error 'validate_file_size'
  671. Rails.logger.error file[:file_size]
  672. return false if file[:file_size] >= 20.megabytes
  673. true
  674. end
  675. def validate_download(result)
  676. return false if !result.success? || !result.body
  677. true
  678. end
  679. end