telegram_spec.rb 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. require 'rails_helper'
  2. RSpec.describe 'Telegram Webhook Integration', type: :request do
  3. let!(:token) { 'valid_token' }
  4. let!(:token2) { 'valid_token2' }
  5. let!(:bot_id) { 123_456_789 }
  6. let!(:bot_id2) { 987_654_321 }
  7. let!(:group_id) { Group.find_by(name: 'Users').id }
  8. let!(:group_id2) { create(:group).id }
  9. describe 'request handling' do
  10. describe 'check_token' do
  11. it 'invalid token' do
  12. stub_request(:post, 'https://api.telegram.org/botinvalid_token/getMe')
  13. .to_return(status: 404, body: '{"ok":false,"error_code":404,"description":"Not Found"}', headers: {})
  14. expect do
  15. Telegram.check_token('invalid_token')
  16. end.to raise_error(Exceptions::UnprocessableEntity)
  17. end
  18. it 'valid token' do
  19. stub_request(:post, "https://api.telegram.org/bot#{token}/getMe")
  20. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  21. bot = Telegram.check_token(token)
  22. expect(bot['id']).to eq(bot_id)
  23. end
  24. end
  25. describe 'create_or_update_channel' do
  26. it 'via http' do
  27. Setting.set('http_type', 'http')
  28. stub_request(:post, "https://api.telegram.org/bot#{token}/getMe")
  29. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  30. expect do
  31. Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!', goodbye: 'goodbye' })
  32. end.to raise_error(Exceptions::UnprocessableEntity)
  33. end
  34. it 'via https and invalid port' do
  35. UserInfo.current_user_id = 1
  36. Setting.set('http_type', 'https')
  37. Setting.set('fqdn', 'somehost.example.com:12345')
  38. stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe")
  39. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  40. stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook")
  41. .with(body: { 'url' => "https://somehost.example.com:12345/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" })
  42. .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443"}', headers: {})
  43. expect do
  44. Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!', goodbye: 'goodbye' })
  45. end.to raise_error(Exceptions::UnprocessableEntity)
  46. end
  47. it 'via https and invalid host' do
  48. Setting.set('http_type', 'https')
  49. Setting.set('fqdn', 'somehost.example.com')
  50. stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe")
  51. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  52. stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook")
  53. .with(body: { 'url' => "https://somehost.example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" })
  54. .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: getaddrinfo: Name or service not known"}', headers: {})
  55. expect do
  56. Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!', goodbye: 'goodbye' })
  57. end.to raise_error(Exceptions::UnprocessableEntity)
  58. end
  59. it 'with https, valid token, host and port' do
  60. Setting.set('http_type', 'https')
  61. Setting.set('fqdn', 'example.com')
  62. UserInfo.current_user_id = 1
  63. stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe")
  64. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  65. stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook")
  66. .with(body: { 'url' => "https://example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" })
  67. .to_return(status: 200, body: '{"ok":true,"result":true,"description":"Webhook was set"}', headers: {})
  68. channel = Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!', goodbye: 'goodbye' })
  69. expect(channel).to be_truthy
  70. end
  71. end
  72. describe 'communication' do
  73. before do
  74. UserInfo.current_user_id = 1
  75. Channel.where(area: 'Telegram::Bot').destroy_all
  76. Setting.set('http_type', 'https')
  77. Setting.set('fqdn', 'example.com')
  78. stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe")
  79. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {})
  80. stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook")
  81. .with(body: { 'url' => "https://example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" })
  82. .to_return(status: 200, body: '{"ok":true,"result":true,"description":"Webhook was set"}', headers: {})
  83. stub_request(:post, "https://api.telegram.org:443/bot#{token2}/getMe")
  84. .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id2},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot2\"}}", headers: {})
  85. stub_request(:post, "https://api.telegram.org:443/bot#{token2}/setWebhook")
  86. .with(body: { 'url' => "https://example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id2}" })
  87. .to_return(status: 200, body: '{"ok":true,"result":true,"description":"Webhook was set"}', headers: {})
  88. end
  89. let!(:channel) { Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!', goodbye: 'goodbye' }) }
  90. let!(:channel2) { Telegram.create_or_update_channel(token2, { group_id: group_id2, welcome: 'hi!', goodbye: 'goodbye' }) }
  91. let!(:callback_url) { "/api/v1/channels_telegram_webhook/#{channel.options[:callback_token]}?bid=#{channel.options[:bot][:id]}" }
  92. let!(:callback_url2) { "/api/v1/channels_telegram_webhook/#{channel2.options[:callback_token]}?bid=#{channel2.options[:bot][:id]}" }
  93. describe 'private' do
  94. before do
  95. init_mocks
  96. end
  97. it 'no found message' do
  98. post '/api/v1/channels_telegram_webhook', params: read_message('private', 'start'), as: :json
  99. expect(response).to have_http_status(:not_found)
  100. end
  101. it 'bot id is missing' do
  102. post '/api/v1/channels_telegram_webhook/not_existing', params: read_message('private', 'start'), as: :json
  103. expect(response).to have_http_status(:unprocessable_entity)
  104. expect(json_response['error']).to eq('bot id is missing')
  105. end
  106. it 'invalid callback token' do
  107. callback_url = "/api/v1/channels_telegram_webhook/not_existing?bid=#{channel.options[:bot][:id]}"
  108. post callback_url, params: read_message('private', 'start'), as: :json
  109. expect(response).to have_http_status(:unprocessable_entity)
  110. expect(json_response['error']).to eq('invalid callback token')
  111. end
  112. it 'start message' do
  113. post callback_url, params: read_message('private', 'start'), as: :json
  114. expect(response).to have_http_status(:ok)
  115. end
  116. it 'text message' do
  117. post callback_url, params: read_message('private', 'text'), as: :json
  118. expect(response).to have_http_status(:ok)
  119. ticket = Ticket.last
  120. expect(ticket.title).to eq('Hello, I need your Help')
  121. expect(ticket.state.name).to eq('new')
  122. expect(ticket.articles.count).to eq(1)
  123. expect(ticket.articles.first.body).to eq('Hello, I need your Help')
  124. expect(ticket.articles.first.content_type).to eq('text/plain')
  125. end
  126. it 'ignore same text message' do
  127. post callback_url, params: read_message('private', 'text'), as: :json
  128. expect(response).to have_http_status(:ok)
  129. post callback_url, params: read_message('private', 'text'), as: :json
  130. expect(response).to have_http_status(:ok)
  131. ticket = Ticket.last
  132. expect(ticket.title).to eq('Hello, I need your Help')
  133. expect(ticket.state.name).to eq('new')
  134. expect(ticket.articles.count).to eq(1)
  135. expect(ticket.articles.first.body).to eq('Hello, I need your Help')
  136. expect(ticket.articles.first.content_type).to eq('text/plain')
  137. end
  138. it 'document message' do
  139. post callback_url, params: read_message('private', 'document'), as: :json
  140. expect(response).to have_http_status(:ok)
  141. ticket = Ticket.last
  142. expect(ticket.articles.last.body).to match(/<img style="width:200px;height:200px;"/i)
  143. expect(ticket.articles.last.content_type).to eq('text/html')
  144. expect(ticket.articles.last.attachments.count).to eq(1)
  145. expect(Store.last.filename).to eq('document.pdf')
  146. end
  147. it 'photo message' do
  148. post callback_url, params: read_message('private', 'photo'), as: :json
  149. expect(response).to have_http_status(:ok)
  150. ticket = Ticket.last
  151. expect(ticket.articles.last.body).to match(/<img style="width:360px;height:327px;"/i)
  152. expect(ticket.articles.last.content_type).to eq('text/html')
  153. end
  154. it 'video message' do
  155. post callback_url, params: read_message('private', 'video'), as: :json
  156. expect(response).to have_http_status(:ok)
  157. ticket = Ticket.last
  158. expect(ticket.articles.count).to eq(1)
  159. expect(ticket.articles.last.body).to match(/<img style="/i)
  160. expect(ticket.articles.last.content_type).to eq('text/html')
  161. expect(ticket.articles.last.attachments.count).to eq(1)
  162. expect(Store.last.filename).to eq('video-videofileid.mp4')
  163. end
  164. it 'sticker message' do
  165. post callback_url, params: read_message('private', 'sticker'), as: :json
  166. expect(response).to have_http_status(:ok)
  167. ticket = Ticket.last
  168. if Rails.application.config.db_4bytes_utf8
  169. expect(ticket.title).to eq('😄')
  170. else
  171. expect(ticket.title).to eq('')
  172. end
  173. expect(ticket.state.name).to eq('new')
  174. expect(ticket.articles.count).to eq(1)
  175. expect(ticket.articles.last.body).to match(/<img style="/i)
  176. expect(ticket.articles.last.content_type).to eq('text/html')
  177. expect(ticket.articles.last.attachments.count).to eq(1)
  178. expect(Store.last.filename).to eq('HotCherry.webp')
  179. end
  180. it 'voice message' do
  181. post callback_url, params: read_message('private', 'voice'), as: :json
  182. expect(response).to have_http_status(:ok)
  183. ticket = Ticket.last
  184. expect(ticket.articles.count).to eq(1)
  185. expect(ticket.articles.last.content_type).to eq('text/html')
  186. expect(ticket.articles.last.attachments.count).to eq(1)
  187. expect(Store.last.filename).to eq('audio-voicefileid.ogg')
  188. end
  189. it 'end message' do
  190. post callback_url, params: read_message('private', 'text'), as: :json
  191. expect(response).to have_http_status(:ok)
  192. post callback_url, params: read_message('private', 'end'), as: :json
  193. expect(response).to have_http_status(:ok)
  194. ticket = Ticket.last
  195. expect(ticket.state.name).to eq('closed')
  196. expect(ticket.articles.count).to eq(1)
  197. expect(ticket.articles.last.body).to eq('Hello, I need your Help')
  198. expect(ticket.articles.last.content_type).to eq('text/plain')
  199. end
  200. end
  201. describe 'channel' do
  202. before do
  203. init_mocks
  204. end
  205. it 'start message' do
  206. post callback_url, params: read_message('channel', 'start'), as: :json
  207. expect(response).to have_http_status(:ok)
  208. end
  209. it 'text message' do
  210. post callback_url, params: read_message('channel', 'text'), as: :json
  211. expect(response).to have_http_status(:ok)
  212. ticket = Ticket.last
  213. expect(ticket.title).to eq('Hello, I need your Help')
  214. expect(ticket.state.name).to eq('new')
  215. expect(ticket.articles.count).to eq(1)
  216. expect(ticket.articles.first.body).to eq('Hello, I need your Help')
  217. expect(ticket.articles.first.content_type).to eq('text/plain')
  218. end
  219. it 'ignore same text message' do
  220. post callback_url, params: read_message('channel', 'text'), as: :json
  221. expect(response).to have_http_status(:ok)
  222. post callback_url, params: read_message('channel', 'text'), as: :json
  223. expect(response).to have_http_status(:ok)
  224. ticket = Ticket.last
  225. expect(ticket.title).to eq('Hello, I need your Help')
  226. expect(ticket.state.name).to eq('new')
  227. expect(ticket.articles.count).to eq(1)
  228. expect(ticket.articles.first.body).to eq('Hello, I need your Help')
  229. expect(ticket.articles.first.content_type).to eq('text/plain')
  230. end
  231. it 'document message' do
  232. post callback_url, params: read_message('channel', 'document'), as: :json
  233. expect(response).to have_http_status(:ok)
  234. ticket = Ticket.last
  235. expect(ticket.articles.last.body).to match(/<img style="width:200px;height:200px;"/i)
  236. expect(ticket.articles.last.content_type).to eq('text/html')
  237. expect(ticket.articles.last.attachments.count).to eq(1)
  238. expect(Store.last.filename).to eq('document.pdf')
  239. end
  240. it 'photo message' do
  241. post callback_url, params: read_message('channel', 'photo'), as: :json
  242. expect(response).to have_http_status(:ok)
  243. ticket = Ticket.last
  244. expect(ticket.articles.last.body).to match(/<img style="width:360px;height:327px;"/i)
  245. expect(ticket.articles.last.content_type).to eq('text/html')
  246. end
  247. it 'video message' do
  248. post callback_url, params: read_message('channel', 'video'), as: :json
  249. expect(response).to have_http_status(:ok)
  250. ticket = Ticket.last
  251. expect(ticket.articles.count).to eq(1)
  252. expect(ticket.articles.last.body).to match(/<img style="/i)
  253. expect(ticket.articles.last.content_type).to eq('text/html')
  254. expect(ticket.articles.last.attachments.count).to eq(1)
  255. expect(Store.last.filename).to eq('video-videofileid.mp4')
  256. end
  257. it 'sticker message' do
  258. post callback_url, params: read_message('channel', 'sticker'), as: :json
  259. expect(response).to have_http_status(:ok)
  260. ticket = Ticket.last
  261. if Rails.application.config.db_4bytes_utf8
  262. expect(ticket.title).to eq('😄')
  263. else
  264. expect(ticket.title).to eq('')
  265. end
  266. expect(ticket.state.name).to eq('new')
  267. expect(ticket.articles.count).to eq(1)
  268. expect(ticket.articles.last.body).to match(/<img style="/i)
  269. expect(ticket.articles.last.content_type).to eq('text/html')
  270. expect(ticket.articles.last.attachments.count).to eq(1)
  271. expect(Store.last.filename).to eq('HotCherry.webp')
  272. end
  273. it 'voice message' do
  274. post callback_url, params: read_message('channel', 'voice'), as: :json
  275. expect(response).to have_http_status(:ok)
  276. ticket = Ticket.last
  277. expect(ticket.articles.count).to eq(1)
  278. expect(ticket.articles.last.content_type).to eq('text/html')
  279. expect(ticket.articles.last.attachments.count).to eq(1)
  280. expect(Store.last.filename).to eq('audio-voicefileid.ogg')
  281. end
  282. it 'end message' do
  283. post callback_url, params: read_message('channel', 'text'), as: :json
  284. expect(response).to have_http_status(:ok)
  285. post callback_url, params: read_message('channel', 'end'), as: :json
  286. expect(response).to have_http_status(:ok)
  287. ticket = Ticket.last
  288. expect(ticket.state.name).to eq('closed')
  289. expect(ticket.articles.count).to eq(1)
  290. expect(ticket.articles.last.body).to eq('Hello, I need your Help')
  291. expect(ticket.articles.last.content_type).to eq('text/plain')
  292. end
  293. end
  294. it 'with two bots and different groups' do
  295. Ticket.destroy_all
  296. # send start message
  297. post callback_url, params: read_message('private', 'start'), as: :json
  298. expect(response).to have_http_status(:ok)
  299. # send text message
  300. post callback_url, params: read_message('private', 'text'), as: :json
  301. expect(response).to have_http_status(:ok)
  302. expect(Ticket.count).to eq(1)
  303. ticket1 = Ticket.last
  304. expect(ticket1.title).to eq('Hello, I need your Help')
  305. expect(ticket1.state.name).to eq('new')
  306. expect(ticket1.articles.count).to eq(1)
  307. expect(ticket1.articles.first.body).to eq('Hello, I need your Help')
  308. expect(ticket1.articles.first.content_type).to eq('text/plain')
  309. expect(ticket1.articles.first.from).to eq('Test Firstname Test Lastname')
  310. expect(ticket1.articles.first.to).to eq('@ChrispressoBot')
  311. # send start2 message
  312. post callback_url2, params: read_message('private', 'start2'), as: :json
  313. expect(response).to have_http_status(:ok)
  314. # send text2 message
  315. post callback_url2, params: read_message('private', 'text2'), as: :json
  316. expect(response).to have_http_status(:ok)
  317. expect(Ticket.count).to eq(2)
  318. ticket2 = Ticket.last
  319. expect(ticket2.title).to eq('Can you help me with my feature?')
  320. expect(ticket2.state.name).to eq('new')
  321. expect(ticket2.articles.count).to eq(1)
  322. expect(ticket2.articles.first.body).to eq('Can you help me with my feature?')
  323. expect(ticket2.articles.first.content_type).to eq('text/plain')
  324. expect(ticket2.articles.first.from).to eq('Test Firstname2 Test Lastname2')
  325. expect(ticket2.articles.first.to).to eq('@ChrispressoBot2')
  326. end
  327. end
  328. def read_message(type, file)
  329. JSON.parse(File.read(Rails.root.join('test', 'data', 'telegram', type, "#{file}.json")))
  330. end
  331. def init_mocks
  332. # create mocks for every file type
  333. %w[document documentthumb voice sticker stickerthumb video videothumb photo].each do |file|
  334. stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
  335. .with(body: { 'file_id' => "#{file}fileid" })
  336. .to_return(status: 200, body: "{\"result\":{\"file_size\":123456,\"file_id\":\"#{file}fileid\",\"file_path\":\"documentfile\"}}", headers: {})
  337. stub_request(:get, "https://api.telegram.org/file/bot#{token}/#{file}file")
  338. .to_return(status: 200, body: "#{file}file", headers: {})
  339. end
  340. [1, 2, 3].each do |id|
  341. stub_request(:post, "https://api.telegram.org/bot#{token}/getFile")
  342. .with(body: { 'file_id' => "photofileid#{id}" })
  343. .to_return(status: 200, body: "{\"result\":{\"file_size\":3622849,\"file_id\":\"photofileid#{id}\",\"file_path\":\"photofile\"}}", headers: {})
  344. stub_request(:get, "https://api.telegram.org/file/bot#{token}/photofile")
  345. .to_return(status: 200, body: 'photofile', headers: {})
  346. end
  347. end
  348. end
  349. end