2021-06-01 12:20:20 +00:00
|
|
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
class Telegram
|
|
|
|
|
|
|
|
attr_accessor :client
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
check token and return bot attributes of token
|
|
|
|
|
|
|
|
bot = Telegram.check_token('token')
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.check_token(token)
|
|
|
|
api = TelegramAPI.new(token)
|
|
|
|
begin
|
2021-07-16 13:29:38 +00:00
|
|
|
bot = api.getMe
|
2017-02-15 02:35:22 +00:00
|
|
|
rescue
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'invalid api token'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
bot
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2019-07-30 13:47:53 +00:00
|
|
|
set webhook for bot
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
success = Telegram.set_webhook('token', callback_url)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
true|false
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.set_webhook(token, callback_url)
|
2017-11-23 08:09:44 +00:00
|
|
|
if callback_url.match?(%r{^http://}i)
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'webhook url need to start with https://, you use http://'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
api = TelegramAPI.new(token)
|
|
|
|
begin
|
|
|
|
api.setWebhook(callback_url)
|
|
|
|
rescue
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'Unable to set webhook at Telegram, seems to be a invalid url.'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
create or update channel, store bot attributes and verify token
|
|
|
|
|
|
|
|
channel = Telegram.create_or_update_channel('token', params)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
channel # instance of Channel
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.create_or_update_channel(token, params, channel = nil)
|
|
|
|
|
|
|
|
# verify token
|
|
|
|
bot = Telegram.check_token(token)
|
|
|
|
|
2020-09-30 09:07:01 +00:00
|
|
|
if !channel && Telegram.bot_duplicate?(bot['id'])
|
|
|
|
raise Exceptions::UnprocessableEntity, 'Bot already exists!'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
if params[:group_id].blank?
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'Group needed!'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:48:22 +00:00
|
|
|
group = Group.find_by(id: params[:group_id])
|
2017-02-15 02:35:22 +00:00
|
|
|
if !group
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'Group invalid!'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
|
2019-07-30 13:47:53 +00:00
|
|
|
# generate random callback token
|
2017-03-01 15:10:15 +00:00
|
|
|
callback_token = if Rails.env.test?
|
|
|
|
'callback_token'
|
|
|
|
else
|
|
|
|
SecureRandom.urlsafe_base64(10)
|
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
# set webhook / callback url for this bot @ telegram
|
|
|
|
callback_url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/channels_telegram_webhook/#{callback_token}?bid=#{bot['id']}"
|
|
|
|
Telegram.set_webhook(token, callback_url)
|
|
|
|
|
|
|
|
if !channel
|
|
|
|
channel = Telegram.bot_by_bot_id(bot['id'])
|
|
|
|
if !channel
|
|
|
|
channel = Channel.new
|
|
|
|
end
|
|
|
|
end
|
|
|
|
channel.area = 'Telegram::Bot'
|
|
|
|
channel.options = {
|
2018-12-19 17:31:51 +00:00
|
|
|
bot: {
|
|
|
|
id: bot['id'],
|
|
|
|
username: bot['username'],
|
2017-02-15 02:35:22 +00:00
|
|
|
first_name: bot['first_name'],
|
2018-12-19 17:31:51 +00:00
|
|
|
last_name: bot['last_name'],
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
callback_token: callback_token,
|
2018-12-19 17:31:51 +00:00
|
|
|
callback_url: callback_url,
|
|
|
|
api_token: token,
|
|
|
|
welcome: params[:welcome],
|
2019-08-12 15:25:32 +00:00
|
|
|
goodbye: params[:goodbye],
|
2017-02-15 02:35:22 +00:00
|
|
|
}
|
|
|
|
channel.group_id = group.id
|
|
|
|
channel.active = true
|
|
|
|
channel.save!
|
|
|
|
channel
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
check if bot already exists as channel
|
|
|
|
|
|
|
|
success = Telegram.bot_duplicate?(bot_id)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
channel # instance of Channel
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.bot_duplicate?(bot_id, channel_id = nil)
|
2017-10-01 12:25:52 +00:00
|
|
|
Channel.where(area: 'Telegram::Bot').each do |channel|
|
2017-02-15 02:35:22 +00:00
|
|
|
next if !channel.options
|
|
|
|
next if !channel.options[:bot]
|
|
|
|
next if !channel.options[:bot][:id]
|
|
|
|
next if channel.options[:bot][:id] != bot_id
|
|
|
|
next if channel.id.to_s == channel_id.to_s
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
return true
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
get channel by bot_id
|
|
|
|
|
|
|
|
channel = Telegram.bot_by_bot_id(bot_id)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
true|false
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.bot_by_bot_id(bot_id)
|
2017-10-01 12:25:52 +00:00
|
|
|
Channel.where(area: 'Telegram::Bot').each do |channel|
|
2017-02-15 02:35:22 +00:00
|
|
|
next if !channel.options
|
|
|
|
next if !channel.options[:bot]
|
|
|
|
next if !channel.options[:bot][:id]
|
|
|
|
return channel if channel.options[:bot][:id].to_s == bot_id.to_s
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
generate message_id for message
|
|
|
|
|
|
|
|
message_id = Telegram.message_id(message)
|
|
|
|
|
|
|
|
returns
|
|
|
|
|
|
|
|
message_id # 123456@telegram
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.message_id(params)
|
|
|
|
message_id = nil
|
2017-11-23 08:09:44 +00:00
|
|
|
%i[message edited_message].each do |key|
|
2017-02-15 02:35:22 +00:00
|
|
|
next if !params[key]
|
|
|
|
next if !params[key][:message_id]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
message_id = params[key][:message_id]
|
|
|
|
break
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-22 06:11:57 +00:00
|
|
|
if message_id
|
2017-11-23 08:09:44 +00:00
|
|
|
%i[message edited_message].each do |key|
|
2017-02-22 06:11:57 +00:00
|
|
|
next if !params[key]
|
|
|
|
next if !params[key][:chat]
|
|
|
|
next if !params[key][:chat][:id]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
message_id = "#{message_id}.#{params[key][:chat][:id]}"
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-22 06:11:57 +00:00
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
if !message_id
|
|
|
|
message_id = params[:update_id]
|
|
|
|
end
|
|
|
|
"#{message_id}@telegram"
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
client = Telegram.new('token')
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def initialize(token)
|
|
|
|
@token = token
|
|
|
|
@api = TelegramAPI.new(token)
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
client.message(chat_id, 'some message', language_code)
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
def message(chat_id, message, language_code = 'en')
|
2017-02-15 02:35:22 +00:00
|
|
|
return if Rails.env.test?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
locale = Locale.find_by(alias: language_code)
|
|
|
|
if !locale
|
|
|
|
locale = Locale.where('locale LIKE :prefix', prefix: "#{language_code}%").first
|
|
|
|
end
|
|
|
|
|
|
|
|
if locale
|
|
|
|
message = Translation.translate(locale[:locale], message)
|
|
|
|
end
|
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
@api.sendMessage(chat_id, message)
|
|
|
|
end
|
|
|
|
|
|
|
|
def user(params)
|
|
|
|
{
|
|
|
|
id: params[:message][:from][:id],
|
|
|
|
username: params[:message][:from][:username],
|
|
|
|
first_name: params[:message][:from][:first_name],
|
|
|
|
last_name: params[:message][:from][:last_name]
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_user(params)
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { 'Create user from message...' }
|
|
|
|
Rails.logger.debug { params.inspect }
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
# do message_user lookup
|
|
|
|
message_user = user(params)
|
|
|
|
|
|
|
|
auth = Authorization.find_by(uid: message_user[:id], provider: 'telegram')
|
|
|
|
|
|
|
|
# create or update user
|
2017-02-15 12:31:06 +00:00
|
|
|
login = message_user[:username] || message_user[:id]
|
2017-02-15 02:35:22 +00:00
|
|
|
user_data = {
|
2018-12-19 17:31:51 +00:00
|
|
|
login: login,
|
2017-02-15 02:35:22 +00:00
|
|
|
firstname: message_user[:first_name],
|
2018-12-19 17:31:51 +00:00
|
|
|
lastname: message_user[:last_name],
|
2017-02-15 02:35:22 +00:00
|
|
|
}
|
|
|
|
if auth
|
|
|
|
user = User.find(auth.user_id)
|
2017-09-11 11:16:08 +00:00
|
|
|
user.update!(user_data)
|
2017-02-15 02:35:22 +00:00
|
|
|
else
|
2017-02-15 12:31:06 +00:00
|
|
|
if message_user[:username]
|
|
|
|
user_data[:note] = "Telegram @#{message_user[:username]}"
|
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
user_data[:active] = true
|
|
|
|
user_data[:role_ids] = Role.signup_role_ids
|
|
|
|
user = User.create(user_data)
|
|
|
|
end
|
|
|
|
|
|
|
|
# create or update authorization
|
|
|
|
auth_data = {
|
|
|
|
uid: message_user[:id],
|
2017-02-15 12:31:06 +00:00
|
|
|
username: login,
|
2017-02-15 02:35:22 +00:00
|
|
|
user_id: user.id,
|
|
|
|
provider: 'telegram'
|
|
|
|
}
|
|
|
|
if auth
|
2017-09-11 11:16:08 +00:00
|
|
|
auth.update!(auth_data)
|
2017-02-15 02:35:22 +00:00
|
|
|
else
|
|
|
|
Authorization.create(auth_data)
|
|
|
|
end
|
|
|
|
|
|
|
|
user
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_ticket(params, user, group_id, channel)
|
|
|
|
UserInfo.current_user_id = user.id
|
|
|
|
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { 'Create ticket from message...' }
|
|
|
|
Rails.logger.debug { params.inspect }
|
|
|
|
Rails.logger.debug { user.inspect }
|
|
|
|
Rails.logger.debug { group_id.inspect }
|
2017-02-15 02:35:22 +00:00
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
# prepare title
|
|
|
|
title = '-'
|
2017-11-23 08:09:44 +00:00
|
|
|
%i[text caption].each do |area|
|
2017-02-22 06:11:57 +00:00
|
|
|
next if !params[:message]
|
|
|
|
next if !params[:message][area]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
title = params[:message][area]
|
|
|
|
break
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-22 06:11:57 +00:00
|
|
|
if title == '-'
|
2017-11-23 08:09:44 +00:00
|
|
|
%i[sticker photo document voice].each do |area|
|
2019-06-27 18:26:28 +00:00
|
|
|
|
|
|
|
next if !params[:message]
|
|
|
|
next if !params[:message][area]
|
|
|
|
next if !params[:message][area][:emoji]
|
|
|
|
|
|
|
|
title = params[:message][area][:emoji]
|
|
|
|
break
|
|
|
|
rescue
|
|
|
|
# just go ahead
|
|
|
|
title
|
|
|
|
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-22 06:11:57 +00:00
|
|
|
end
|
|
|
|
if title.length > 60
|
|
|
|
title = "#{title[0, 60]}..."
|
|
|
|
end
|
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
# find ticket or create one
|
2019-07-30 13:47:53 +00:00
|
|
|
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
|
|
|
possible_tickets = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).order(:updated_at)
|
2020-06-22 09:57:45 +00:00
|
|
|
ticket = possible_tickets.find_each.find { |possible_ticket| possible_ticket.preferences[:channel_id] == channel.id }
|
2017-02-22 06:11:57 +00:00
|
|
|
|
2019-07-30 13:47:53 +00:00
|
|
|
if ticket
|
2017-02-22 06:11:57 +00:00
|
|
|
# check if title need to be updated
|
|
|
|
if ticket.title == '-'
|
|
|
|
ticket.title = title
|
|
|
|
end
|
|
|
|
new_state = Ticket::State.find_by(default_create: true)
|
2017-02-15 02:35:22 +00:00
|
|
|
if ticket.state_id != new_state.id
|
2017-02-22 06:11:57 +00:00
|
|
|
ticket.state = Ticket::State.find_by(default_follow_up: true)
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
ticket.save!
|
|
|
|
return ticket
|
|
|
|
end
|
|
|
|
|
|
|
|
ticket = Ticket.new(
|
2018-12-19 17:31:51 +00:00
|
|
|
group_id: group_id,
|
|
|
|
title: title,
|
|
|
|
state_id: Ticket::State.find_by(default_create: true).id,
|
2017-02-22 06:11:57 +00:00
|
|
|
priority_id: Ticket::Priority.find_by(default_create: true).id,
|
2017-02-15 02:35:22 +00:00
|
|
|
customer_id: user.id,
|
|
|
|
preferences: {
|
|
|
|
channel_id: channel.id,
|
2018-12-19 17:31:51 +00:00
|
|
|
telegram: {
|
|
|
|
bid: params['bid'],
|
2017-02-15 02:35:22 +00:00
|
|
|
chat_id: params[:message][:chat][:id]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
ticket.save!
|
|
|
|
ticket
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_article(params, user, ticket, channel, article = nil)
|
|
|
|
|
|
|
|
if article
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { 'Update article from message...' }
|
2017-02-15 02:35:22 +00:00
|
|
|
else
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { 'Create article from message...' }
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { params.inspect }
|
|
|
|
Rails.logger.debug { user.inspect }
|
|
|
|
Rails.logger.debug { ticket.inspect }
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
UserInfo.current_user_id = user.id
|
|
|
|
|
|
|
|
if article
|
|
|
|
article.preferences[:edited_message] = {
|
2018-12-19 17:31:51 +00:00
|
|
|
message: {
|
2017-02-15 02:35:22 +00:00
|
|
|
created_at: params[:message][:date],
|
|
|
|
message_id: params[:message][:message_id],
|
2018-12-19 17:31:51 +00:00
|
|
|
from: params[:message][:from],
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
update_id: params[:update_id],
|
|
|
|
}
|
|
|
|
else
|
|
|
|
article = Ticket::Article.new(
|
2018-12-19 17:31:51 +00:00
|
|
|
ticket_id: ticket.id,
|
|
|
|
type_id: Ticket::Article::Type.find_by(name: 'telegram personal-message').id,
|
|
|
|
sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
|
|
|
|
from: user(params)[:username],
|
|
|
|
to: "@#{channel[:options][:bot][:username]}",
|
|
|
|
message_id: Telegram.message_id(params),
|
|
|
|
internal: false,
|
2017-02-15 02:35:22 +00:00
|
|
|
preferences: {
|
2018-12-19 17:31:51 +00:00
|
|
|
message: {
|
2017-02-15 02:35:22 +00:00
|
|
|
created_at: params[:message][:date],
|
|
|
|
message_id: params[:message][:message_id],
|
2018-12-19 17:31:51 +00:00
|
|
|
from: params[:message][:from],
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
update_id: params[:update_id],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# add photo
|
2017-02-15 02:35:22 +00:00
|
|
|
if params[:message][:photo]
|
|
|
|
|
|
|
|
# find photo with best resolution for us
|
2019-10-21 14:50:45 +00:00
|
|
|
photo = nil
|
|
|
|
max_width = 650 * 2
|
|
|
|
last_width = 0
|
2017-02-15 02:35:22 +00:00
|
|
|
last_height = 0
|
2019-10-21 14:50:45 +00:00
|
|
|
|
2017-10-01 12:25:52 +00:00
|
|
|
params[:message][:photo].each do |file|
|
2017-02-15 02:35:22 +00:00
|
|
|
if !photo
|
|
|
|
photo = file
|
|
|
|
last_width = file['width'].to_i
|
|
|
|
last_height = file['height'].to_i
|
|
|
|
end
|
2018-05-04 14:05:10 +00:00
|
|
|
next if file['width'].to_i >= max_width || file['width'].to_i <= last_width
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
photo = file
|
|
|
|
last_width = file['width'].to_i
|
2017-02-15 02:48:22 +00:00
|
|
|
last_height = file['height'].to_i
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-02-15 02:35:22 +00:00
|
|
|
if last_width > 650
|
|
|
|
last_width = (last_width / 2).to_i
|
|
|
|
last_height = (last_height / 2).to_i
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# download photo
|
|
|
|
photo_result = get_file(params, photo)
|
|
|
|
body = "<img style=\"width:#{last_width}px;height:#{last_height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(photo_result.body)}\">"
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
if params[:message][:caption]
|
|
|
|
body += "<br>#{params[:message][:caption].text2html}"
|
|
|
|
end
|
|
|
|
article.content_type = 'text/html'
|
2019-10-21 14:50:45 +00:00
|
|
|
article.body = body
|
2017-02-15 02:35:22 +00:00
|
|
|
article.save!
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
|
|
|
# add document
|
|
|
|
if params[:message][:document]
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
document = params[:message][:document]
|
|
|
|
thumb = params[:message][:document][:thumb]
|
|
|
|
body = ' '
|
|
|
|
|
|
|
|
if thumb
|
|
|
|
width = thumb[:width]
|
|
|
|
height = thumb[:height]
|
|
|
|
thumb_result = get_file(params, thumb)
|
|
|
|
body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
|
|
|
|
end
|
|
|
|
if params[:message][:caption]
|
|
|
|
body += "<br>#{params[:message][:caption].text2html}"
|
|
|
|
end
|
|
|
|
document_result = get_file(params, document)
|
|
|
|
article.content_type = 'text/html'
|
|
|
|
article.body = body
|
|
|
|
article.save!
|
|
|
|
|
|
|
|
Store.remove(
|
|
|
|
object: 'Ticket::Article',
|
|
|
|
o_id: article.id,
|
|
|
|
)
|
|
|
|
Store.add(
|
|
|
|
object: 'Ticket::Article',
|
|
|
|
o_id: article.id,
|
|
|
|
data: document_result.body,
|
|
|
|
filename: document[:file_name],
|
|
|
|
preferences: {
|
|
|
|
'Mime-Type' => document[:mime_type],
|
|
|
|
},
|
|
|
|
)
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
|
|
|
# add video
|
|
|
|
if params[:message][:video]
|
|
|
|
|
|
|
|
video = params[:message][:video]
|
|
|
|
thumb = params[:message][:video][:thumb]
|
2017-02-15 02:35:22 +00:00
|
|
|
body = ' '
|
2019-10-21 14:50:45 +00:00
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
if thumb
|
2019-10-21 14:50:45 +00:00
|
|
|
width = thumb[:width]
|
|
|
|
height = thumb[:height]
|
|
|
|
thumb_result = get_file(params, thumb)
|
|
|
|
body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
|
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
if params[:message][:caption]
|
|
|
|
body += "<br>#{params[:message][:caption].text2html}"
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
2019-10-21 14:50:45 +00:00
|
|
|
video_result = get_file(params, video)
|
2017-02-15 02:35:22 +00:00
|
|
|
article.content_type = 'text/html'
|
2019-10-21 14:50:45 +00:00
|
|
|
article.body = body
|
2017-02-15 02:35:22 +00:00
|
|
|
article.save!
|
2019-10-21 14:50:45 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
Store.remove(
|
|
|
|
object: 'Ticket::Article',
|
2018-12-19 17:31:51 +00:00
|
|
|
o_id: article.id,
|
2017-02-15 02:35:22 +00:00
|
|
|
)
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
# get video type
|
|
|
|
type = video[:mime_type].gsub(%r{(.+/)}, '')
|
2017-02-15 02:35:22 +00:00
|
|
|
Store.add(
|
2018-12-19 17:31:51 +00:00
|
|
|
object: 'Ticket::Article',
|
|
|
|
o_id: article.id,
|
2019-10-21 14:50:45 +00:00
|
|
|
data: video_result.body,
|
|
|
|
filename: video[:file_name] || "video-#{video[:file_id]}.#{type}",
|
2017-02-15 02:35:22 +00:00
|
|
|
preferences: {
|
2019-10-21 14:50:45 +00:00
|
|
|
'Mime-Type' => video[:mime_type],
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# add voice
|
2017-02-15 02:35:22 +00:00
|
|
|
if params[:message][:voice]
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
voice = params[:message][:voice]
|
|
|
|
body = ' '
|
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
if params[:message][:caption]
|
|
|
|
body = "<br>#{params[:message][:caption].text2html}"
|
|
|
|
end
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
document_result = get_file(params, voice)
|
2017-02-15 02:35:22 +00:00
|
|
|
article.content_type = 'text/html'
|
2019-10-21 14:50:45 +00:00
|
|
|
article.body = body
|
2017-02-15 02:35:22 +00:00
|
|
|
article.save!
|
2019-10-21 14:50:45 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
Store.remove(
|
|
|
|
object: 'Ticket::Article',
|
2018-12-19 17:31:51 +00:00
|
|
|
o_id: article.id,
|
2017-02-15 02:35:22 +00:00
|
|
|
)
|
|
|
|
Store.add(
|
2018-12-19 17:31:51 +00:00
|
|
|
object: 'Ticket::Article',
|
|
|
|
o_id: article.id,
|
|
|
|
data: document_result.body,
|
2019-10-21 14:50:45 +00:00
|
|
|
filename: voice[:file_path] || "audio-#{voice[:file_id]}.ogg",
|
2017-02-15 02:35:22 +00:00
|
|
|
preferences: {
|
2019-10-21 14:50:45 +00:00
|
|
|
'Mime-Type' => voice[:mime_type],
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# add sticker
|
2017-02-22 06:11:57 +00:00
|
|
|
if params[:message][:sticker]
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
sticker = params[:message][:sticker]
|
|
|
|
emoji = sticker[:emoji]
|
|
|
|
thumb = sticker[:thumb]
|
|
|
|
body = ' '
|
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
if thumb
|
2019-10-21 14:50:45 +00:00
|
|
|
width = thumb[:width]
|
2017-02-22 06:11:57 +00:00
|
|
|
height = thumb[:height]
|
2019-10-21 14:50:45 +00:00
|
|
|
thumb_result = get_file(params, thumb)
|
|
|
|
body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/webp;base64,#{Base64.strict_encode64(thumb_result.body)}\">"
|
2017-02-22 06:11:57 +00:00
|
|
|
article.content_type = 'text/html'
|
|
|
|
elsif emoji
|
|
|
|
article.content_type = 'text/plain'
|
|
|
|
body = emoji
|
|
|
|
end
|
2019-10-21 14:50:45 +00:00
|
|
|
|
2017-02-22 06:11:57 +00:00
|
|
|
article.body = body
|
|
|
|
article.save!
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
if sticker[:file_id]
|
|
|
|
|
|
|
|
document_result = get_file(params, sticker)
|
2017-02-22 06:11:57 +00:00
|
|
|
Store.remove(
|
|
|
|
object: 'Ticket::Article',
|
2018-12-19 17:31:51 +00:00
|
|
|
o_id: article.id,
|
2017-02-22 06:11:57 +00:00
|
|
|
)
|
|
|
|
Store.add(
|
2018-12-19 17:31:51 +00:00
|
|
|
object: 'Ticket::Article',
|
|
|
|
o_id: article.id,
|
|
|
|
data: document_result.body,
|
2019-10-21 14:50:45 +00:00
|
|
|
filename: sticker[:file_name] || "#{sticker[:set_name]}.webp",
|
2017-02-22 06:11:57 +00:00
|
|
|
preferences: {
|
2018-01-05 08:02:51 +00:00
|
|
|
'Mime-Type' => 'image/webp', # mime type is not given from Telegram API but this is actually WebP
|
2017-02-22 06:11:57 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
end
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# add text
|
2017-02-15 02:35:22 +00:00
|
|
|
if params[:message][:text]
|
|
|
|
article.content_type = 'text/plain'
|
|
|
|
article.body = params[:message][:text]
|
|
|
|
article.save!
|
|
|
|
return article
|
|
|
|
end
|
2019-10-21 14:50:45 +00:00
|
|
|
raise Exceptions::UnprocessableEntity, 'invalid telegram message'
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def to_group(params, group_id, channel)
|
2018-01-05 08:02:51 +00:00
|
|
|
# begin import
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { 'import message' }
|
2017-02-15 02:35:22 +00:00
|
|
|
|
2018-01-05 08:02:51 +00:00
|
|
|
# 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.
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2020-11-12 11:42:44 +00:00
|
|
|
# NOTE: used .blank? which is a rails method. empty? does not work on integers (values like date, width, height) to check.
|
2018-01-05 08:02:51 +00:00
|
|
|
# need delete_if to remove any empty hashes, .compact only removes keys with nil values.
|
|
|
|
params[:message] = {
|
2018-12-19 17:31:51 +00:00
|
|
|
document: {
|
2018-01-05 08:02:51 +00:00
|
|
|
file_name: params.dig(:channel_post, :document, :file_name),
|
|
|
|
mime_type: params.dig(:channel_post, :document, :mime_type),
|
2018-12-19 17:31:51 +00:00
|
|
|
file_id: params.dig(:channel_post, :document, :file_id),
|
2019-10-21 14:50:45 +00:00
|
|
|
file_size: params.dig(:channel_post, :document, :file_size),
|
2018-12-19 17:31:51 +00:00
|
|
|
thumb: {
|
|
|
|
file_id: params.dig(:channel_post, :document, :thumb, :file_id),
|
2018-01-05 08:02:51 +00:00
|
|
|
file_size: params.dig(:channel_post, :document, :thumb, :file_size),
|
2018-12-19 17:31:51 +00:00
|
|
|
width: params.dig(:channel_post, :document, :thumb, :width),
|
|
|
|
height: params.dig(:channel_post, :document, :thumb, :height)
|
2018-01-05 08:02:51 +00:00
|
|
|
}.compact
|
|
|
|
}.delete_if { |_, v| v.blank? },
|
2019-10-21 14:50:45 +00:00
|
|
|
video: {
|
|
|
|
duration: params.dig(:channel_post, :video, :duration),
|
|
|
|
width: params.dig(:channel_post, :video, :width),
|
|
|
|
height: params.dig(:channel_post, :video, :height),
|
|
|
|
mime_type: params.dig(:channel_post, :video, :mime_type),
|
|
|
|
file_id: params.dig(:channel_post, :video, :file_id),
|
|
|
|
file_size: params.dig(:channel_post, :video, :file_size),
|
|
|
|
thumb: {
|
|
|
|
file_id: params.dig(:channel_post, :video, :thumb, :file_id),
|
|
|
|
file_size: params.dig(:channel_post, :video, :thumb, :file_size),
|
|
|
|
width: params.dig(:channel_post, :video, :thumb, :width),
|
|
|
|
height: params.dig(:channel_post, :video, :thumb, :height)
|
|
|
|
}.compact
|
|
|
|
}.delete_if { |_, v| v.blank? },
|
2018-12-19 17:31:51 +00:00
|
|
|
voice: {
|
|
|
|
duration: params.dig(:channel_post, :voice, :duration),
|
2018-01-05 08:02:51 +00:00
|
|
|
mime_type: params.dig(:channel_post, :voice, :mime_type),
|
2018-12-19 17:31:51 +00:00
|
|
|
file_id: params.dig(:channel_post, :voice, :file_id),
|
2018-01-05 08:02:51 +00:00
|
|
|
file_size: params.dig(:channel_post, :voice, :file_size)
|
|
|
|
}.compact,
|
2018-12-19 17:31:51 +00:00
|
|
|
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),
|
2018-01-05 08:02:51 +00:00
|
|
|
file_path: params.dig(:channel_post, :sticker, :file_path),
|
2019-10-21 14:50:45 +00:00
|
|
|
file_size: params.dig(:channel_post, :sticker, :file_size),
|
2018-12-19 17:31:51 +00:00
|
|
|
thumb: {
|
|
|
|
file_id: params.dig(:channel_post, :sticker, :thumb, :file_id),
|
2018-01-05 08:02:51 +00:00
|
|
|
file_size: params.dig(:channel_post, :sticker, :thumb, :file_size),
|
2018-12-19 17:31:51 +00:00
|
|
|
width: params.dig(:channel_post, :sticker, :thumb, :width),
|
2019-10-21 14:50:45 +00:00
|
|
|
height: params.dig(:channel_post, :sticker, :thumb, :height),
|
2018-01-05 08:02:51 +00:00
|
|
|
file_path: params.dig(:channel_post, :sticker, :thumb, :file_path)
|
|
|
|
}.compact
|
|
|
|
}.delete_if { |_, v| v.blank? },
|
2018-12-19 17:31:51 +00:00
|
|
|
chat: {
|
|
|
|
id: params.dig(:channel_post, :chat, :id),
|
2018-01-05 08:02:51 +00:00
|
|
|
first_name: params.dig(:channel_post, :chat, :title),
|
2018-12-19 17:31:51 +00:00
|
|
|
last_name: 'Channel',
|
|
|
|
username: "channel#{params.dig(:channel_post, :chat, :id)}"
|
2018-01-05 08:02:51 +00:00
|
|
|
},
|
2018-12-19 17:31:51 +00:00
|
|
|
from: {
|
|
|
|
id: params.dig(:channel_post, :chat, :id),
|
2018-01-05 08:02:51 +00:00
|
|
|
first_name: params.dig(:channel_post, :chat, :title),
|
2018-12-19 17:31:51 +00:00
|
|
|
last_name: 'Channel',
|
|
|
|
username: "channel#{params.dig(:channel_post, :chat, :id)}"
|
2018-01-05 08:02:51 +00:00
|
|
|
},
|
2018-12-19 17:31:51 +00:00
|
|
|
caption: (params.dig(:channel_post, :caption) || {}),
|
|
|
|
date: params.dig(:channel_post, :date),
|
2018-01-05 08:02:51 +00:00
|
|
|
message_id: params.dig(:channel_post, :message_id),
|
2018-12-19 17:31:51 +00:00
|
|
|
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))
|
2018-01-05 08:02:51 +00:00
|
|
|
}.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] = {
|
2018-12-19 17:31:51 +00:00
|
|
|
chat: {
|
|
|
|
id: params.dig(:edited_channel_post, :chat, :id),
|
2018-01-05 08:02:51 +00:00
|
|
|
first_name: params.dig(:edited_channel_post, :chat, :title),
|
2018-12-19 17:31:51 +00:00
|
|
|
last_name: 'Channel',
|
|
|
|
username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
|
2018-01-05 08:02:51 +00:00
|
|
|
},
|
2018-12-19 17:31:51 +00:00
|
|
|
from: {
|
|
|
|
id: params.dig(:edited_channel_post, :chat, :id),
|
2018-01-05 08:02:51 +00:00
|
|
|
first_name: params.dig(:edited_channel_post, :chat, :title),
|
2018-12-19 17:31:51 +00:00
|
|
|
last_name: 'Channel',
|
|
|
|
username: "channel#{params.dig(:edited_channel_post, :chat, :id)}"
|
2018-01-05 08:02:51 +00:00
|
|
|
},
|
2018-12-19 17:31:51 +00:00
|
|
|
date: params.dig(:edited_channel_post, :date),
|
|
|
|
edit_date: params.dig(:edited_channel_post, :edit_date),
|
2018-01-05 08:02:51 +00:00
|
|
|
message_id: params.dig(:edited_channel_post, :message_id),
|
2018-12-19 17:31:51 +00:00
|
|
|
text: params.dig(:edited_channel_post, :text)
|
2018-01-05 08:02:51 +00:00
|
|
|
}
|
|
|
|
params.delete(:edited_channel_post) # discard unused :edited_channel_post hash
|
|
|
|
end
|
|
|
|
|
2019-07-30 13:47:53 +00:00
|
|
|
# prevent multiple update
|
2020-09-30 09:07:01 +00:00
|
|
|
return if !params[:edited_message] && Ticket::Article.exists?(message_id: Telegram.message_id(params))
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
# update article
|
|
|
|
if params[:edited_message]
|
|
|
|
article = Ticket::Article.find_by(message_id: Telegram.message_id(params))
|
|
|
|
return if !article
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
params[:message] = params[:edited_message]
|
|
|
|
user = to_user(params)
|
|
|
|
to_article(params, user, article.ticket, channel, article)
|
|
|
|
return article
|
|
|
|
end
|
|
|
|
|
|
|
|
# send welcome message and don't create ticket
|
|
|
|
text = params[:message][:text]
|
2020-05-25 07:05:17 +00:00
|
|
|
if text.present? && text.start_with?('/start')
|
2019-10-21 14:50:45 +00:00
|
|
|
message(params[:message][:chat][:id], channel.options[:welcome] || 'You are welcome! Just ask me something!', params[:message][:from][:language_code])
|
2017-02-15 02:35:22 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
# find ticket and close it
|
2020-05-25 07:05:17 +00:00
|
|
|
elsif text.present? && text.start_with?('/end')
|
2017-02-15 02:35:22 +00:00
|
|
|
user = to_user(params)
|
2019-08-12 15:25:32 +00:00
|
|
|
|
|
|
|
# get the last ticket of customer which is not closed yet, and close it
|
|
|
|
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
|
|
|
possible_tickets = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).order(:updated_at)
|
2020-06-22 09:57:45 +00:00
|
|
|
ticket = possible_tickets.find_each.find { |possible_ticket| possible_ticket.preferences[:channel_id] == channel.id }
|
2019-10-21 14:50:45 +00:00
|
|
|
|
|
|
|
return if !ticket
|
|
|
|
|
|
|
|
ticket.state = Ticket::State.find_by(name: 'closed')
|
2017-02-15 02:35:22 +00:00
|
|
|
ticket.save!
|
2019-08-12 15:25:32 +00:00
|
|
|
|
|
|
|
return if !channel.options[:goodbye]
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
message(params[:message][:chat][:id], channel.options[:goodbye], params[:message][:from][:language_code])
|
2017-02-15 02:35:22 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
ticket = nil
|
|
|
|
|
|
|
|
# use transaction
|
2021-08-20 03:36:30 +00:00
|
|
|
Transaction.execute(reset_user_id: true, context: 'telegram') do
|
2019-08-12 15:25:32 +00:00
|
|
|
user = to_user(params)
|
2017-02-15 02:35:22 +00:00
|
|
|
ticket = to_ticket(params, user, group_id, channel)
|
|
|
|
to_article(params, user, ticket, channel)
|
|
|
|
end
|
|
|
|
|
|
|
|
ticket
|
|
|
|
end
|
|
|
|
|
|
|
|
def from_article(article)
|
|
|
|
|
|
|
|
message = nil
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { "Create telegram personal message from article to '#{article[:to]}'..." }
|
2017-02-15 02:35:22 +00:00
|
|
|
|
|
|
|
message = {}
|
|
|
|
# TODO: create telegram message here
|
|
|
|
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { message.inspect }
|
2017-02-15 02:35:22 +00:00
|
|
|
message
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
def get_file(params, file)
|
2017-02-15 02:35:22 +00:00
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
# telegram bot files are limited up to 20MB
|
|
|
|
# https://core.telegram.org/bots/api#getfile
|
|
|
|
if !validate_file_size(file)
|
|
|
|
message_text = 'Telegram file is to big. (Maximum 20mb)'
|
|
|
|
message(params[:message][:chat][:id], "Sorry, we could not handle your message. #{message_text}", params[:message][:from][:language_code])
|
|
|
|
raise Exceptions::UnprocessableEntity, message_text
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
result = download_file(file[:file_id])
|
|
|
|
|
|
|
|
if !validate_download(result)
|
|
|
|
message_text = 'Unable to get you file from bot.'
|
|
|
|
message(params[:message][:chat][:id], "Sorry, we could not handle your message. #{message_text}", params[:message][:from][:language_code])
|
|
|
|
raise Exceptions::UnprocessableEntity, message_text
|
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
result
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def download_file(file_id)
|
|
|
|
document = @api.getFile(file_id)
|
|
|
|
url = "https://api.telegram.org/file/bot#{@token}/#{document['file_path']}"
|
|
|
|
UserAgent.get(
|
|
|
|
url,
|
|
|
|
{},
|
|
|
|
{
|
2017-02-15 02:48:22 +00:00
|
|
|
open_timeout: 20,
|
|
|
|
read_timeout: 40,
|
2021-07-20 13:31:46 +00:00
|
|
|
verify_ssl: true,
|
2017-02-15 02:35:22 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2019-10-21 14:50:45 +00:00
|
|
|
def validate_file_size(file)
|
|
|
|
Rails.logger.error 'validate_file_size'
|
|
|
|
Rails.logger.error file[:file_size]
|
|
|
|
return false if file[:file_size] >= 20.megabytes
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def validate_download(result)
|
|
|
|
return false if !result.success? || !result.body
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2017-02-15 02:35:22 +00:00
|
|
|
end
|