telegram.rb 24 KB

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