Telegram support and split of channel controllers into separate files. Thanks to @schurig
This commit is contained in:
parent
ed5da3dabe
commit
d34112a99f
42 changed files with 2108 additions and 227 deletions
1
Gemfile
1
Gemfile
|
@ -42,6 +42,7 @@ gem 'omniauth-linkedin-oauth2'
|
||||||
gem 'omniauth-twitter'
|
gem 'omniauth-twitter'
|
||||||
|
|
||||||
gem 'twitter'
|
gem 'twitter'
|
||||||
|
gem 'telegramAPI'
|
||||||
gem 'koala'
|
gem 'koala'
|
||||||
gem 'mail'
|
gem 'mail'
|
||||||
gem 'email_verifier'
|
gem 'email_verifier'
|
||||||
|
|
|
@ -198,6 +198,7 @@ GEM
|
||||||
nenv (0.3.0)
|
nenv (0.3.0)
|
||||||
nestful (1.1.1)
|
nestful (1.1.1)
|
||||||
net-ldap (0.15.0)
|
net-ldap (0.15.0)
|
||||||
|
netrc (0.11.0)
|
||||||
nokogiri (1.6.8)
|
nokogiri (1.6.8)
|
||||||
mini_portile2 (~> 2.1.0)
|
mini_portile2 (~> 2.1.0)
|
||||||
pkg-config (~> 1.1.7)
|
pkg-config (~> 1.1.7)
|
||||||
|
@ -293,6 +294,10 @@ GEM
|
||||||
rb-inotify (0.9.7)
|
rb-inotify (0.9.7)
|
||||||
ffi (>= 0.5.0)
|
ffi (>= 0.5.0)
|
||||||
ref (2.0.0)
|
ref (2.0.0)
|
||||||
|
rest-client (2.0.0)
|
||||||
|
http-cookie (>= 1.0.2, < 2.0)
|
||||||
|
mime-types (>= 1.16, < 4.0)
|
||||||
|
netrc (~> 0.8)
|
||||||
retriable (2.1.0)
|
retriable (2.1.0)
|
||||||
rspec-core (3.5.4)
|
rspec-core (3.5.4)
|
||||||
rspec-support (~> 3.5.0)
|
rspec-support (~> 3.5.0)
|
||||||
|
@ -358,6 +363,8 @@ GEM
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sqlite3 (1.3.11)
|
sqlite3 (1.3.11)
|
||||||
|
telegramAPI (1.2.2)
|
||||||
|
rest-client (~> 2.0, >= 1.7.3)
|
||||||
term-ansicolor (1.3.2)
|
term-ansicolor (1.3.2)
|
||||||
tins (~> 1.0)
|
tins (~> 1.0)
|
||||||
test-unit (3.2.1)
|
test-unit (3.2.1)
|
||||||
|
@ -467,6 +474,7 @@ DEPENDENCIES
|
||||||
spring-commands-rspec
|
spring-commands-rspec
|
||||||
sprockets
|
sprockets
|
||||||
sqlite3
|
sqlite3
|
||||||
|
telegramAPI
|
||||||
test-unit
|
test-unit
|
||||||
therubyracer
|
therubyracer
|
||||||
twitter
|
twitter
|
||||||
|
|
|
@ -243,7 +243,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_index'
|
id: 'email_index'
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: @apiPath + '/channels/email_index'
|
url: "#{@apiPath}/channels_email"
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@stopLoading()
|
@stopLoading()
|
||||||
|
@ -324,34 +324,44 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
||||||
delete: (e) =>
|
delete: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
new App.ControllerConfirm(
|
||||||
new App.ControllerGenericDestroyConfirm(
|
message: 'Sure?'
|
||||||
item: item
|
callback: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'email_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/channels_email"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
callback: @load
|
|
||||||
)
|
)
|
||||||
|
|
||||||
disable: (e) =>
|
disable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = false
|
id: 'email_disable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_email_disable"
|
||||||
@load()
|
data: JSON.stringify(id: id)
|
||||||
fail: =>
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
enable: (e) =>
|
enable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = true
|
id: 'email_enable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_email_enable"
|
||||||
@load()
|
data: JSON.stringify(id: id)
|
||||||
fail: =>
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -441,7 +451,7 @@ class App.ChannelEmailEdit extends App.ControllerModal
|
||||||
# show errors in form
|
# show errors in form
|
||||||
if errors
|
if errors
|
||||||
@log 'error', errors
|
@log 'error', errors
|
||||||
@formValidate( form: e.target, errors: errors )
|
@formValidate(form: e.target, errors: errors)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# disable form
|
# disable form
|
||||||
|
@ -449,16 +459,18 @@ class App.ChannelEmailEdit extends App.ControllerModal
|
||||||
|
|
||||||
# update
|
# update
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'channel_group_update'
|
id: 'channel_email_group'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: "#{@apiPath}/channels/group/#{@item.id}"
|
url: "#{@apiPath}/channels_email_group/#{@item.id}"
|
||||||
data: JSON.stringify( params )
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@callback()
|
@callback()
|
||||||
@close()
|
@close()
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@formEnable(e)
|
@formEnable(e)
|
||||||
|
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||||
)
|
)
|
||||||
|
|
||||||
class App.ChannelEmailAccountWizard extends App.WizardModal
|
class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
|
@ -651,7 +663,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_probe'
|
id: 'email_probe'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: @apiPath + '/channels/email_probe'
|
url: "#{@apiPath}/channels_email_probe"
|
||||||
data: JSON.stringify(params)
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
@ -683,7 +695,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@$('.js-inbound [name="options::password"]').val(@account['meta']['password'])
|
@$('.js-inbound [name="options::password"]').val(@account['meta']['password'])
|
||||||
|
|
||||||
@enable(e)
|
@enable(e)
|
||||||
fail: =>
|
error: =>
|
||||||
@enable(e)
|
@enable(e)
|
||||||
@showSlide('js-intro')
|
@showSlide('js-intro')
|
||||||
)
|
)
|
||||||
|
@ -705,7 +717,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_inbound'
|
id: 'email_inbound'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: @apiPath + '/channels/email_inbound'
|
url: "#{@apiPath}/channels_email_inbound"
|
||||||
data: JSON.stringify(params)
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
@ -738,9 +750,10 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@showAlert('js-inbound', data.message_human || data.message)
|
@showAlert('js-inbound', data.message_human || data.message)
|
||||||
@showInvalidField('js-inbound', data.invalid_field)
|
@showInvalidField('js-inbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@showSlide('js-inbound')
|
@showSlide('js-inbound')
|
||||||
@showAlert('js-inbound', data.message_human || data.message)
|
@showAlert('js-inbound', data.message_human || data.message || data.error)
|
||||||
@showInvalidField('js-inbound', data.invalid_field)
|
@showInvalidField('js-inbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
)
|
)
|
||||||
|
@ -768,8 +781,8 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_outbound'
|
id: 'email_outbound'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: @apiPath + '/channels/email_outbound'
|
url: "#{@apiPath}/channels_email_outbound"
|
||||||
data: JSON.stringify( params )
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
if data.result is 'ok'
|
if data.result is 'ok'
|
||||||
|
@ -783,9 +796,10 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@showAlert('js-outbound', data.message_human || data.message)
|
@showAlert('js-outbound', data.message_human || data.message)
|
||||||
@showInvalidField('js-outbound', data.invalid_field)
|
@showInvalidField('js-outbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@showSlide('js-outbound')
|
@showSlide('js-outbound')
|
||||||
@showAlert('js-outbound', data.message_human || data.message)
|
@showAlert('js-outbound', data.message_human || data.message || data.error)
|
||||||
@showInvalidField('js-outbound', data.invalid_field)
|
@showInvalidField('js-outbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
)
|
)
|
||||||
|
@ -810,7 +824,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_verify'
|
id: 'email_verify'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: @apiPath + '/channels/email_verify'
|
url: "#{@apiPath}/channels_email_verify"
|
||||||
data: JSON.stringify(account)
|
data: JSON.stringify(account)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
@ -835,7 +849,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||||
if data.subject && @account
|
if data.subject && @account
|
||||||
@account.subject = data.subject
|
@account.subject = data.subject
|
||||||
@verify(@account, count + 1)
|
@verify(@account, count + 1)
|
||||||
fail: =>
|
error: =>
|
||||||
@showSlide('js-intro')
|
@showSlide('js-intro')
|
||||||
@showAlert('js-intro', 'Unable to verify sending and receiving. Please check your settings.')
|
@showAlert('js-intro', 'Unable to verify sending and receiving. Please check your settings.')
|
||||||
)
|
)
|
||||||
|
@ -946,7 +960,7 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'email_outbound'
|
id: 'email_outbound'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: "#{@apiPath}/channels/email_notification"
|
url: "#{@apiPath}/channels_email_notification"
|
||||||
data: JSON.stringify(params)
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
@ -957,9 +971,10 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
|
||||||
@showAlert('js-outbound', data.message_human || data.message)
|
@showAlert('js-outbound', data.message_human || data.message)
|
||||||
@showInvalidField('js-outbound', data.invalid_field)
|
@showInvalidField('js-outbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@showSlide('js-outbound')
|
@showSlide('js-outbound')
|
||||||
@showAlert('js-outbound', data.message_human || data.message)
|
@showAlert('js-outbound', data.message_human || data.message || data.error)
|
||||||
@showInvalidField('js-outbound', data.invalid_field)
|
@showInvalidField('js-outbound', data.invalid_field)
|
||||||
@enable(e)
|
@enable(e)
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Index extends App.ControllerSubContent
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'facebook_index'
|
id: 'facebook_index'
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: "#{@apiPath}/channels/facebook_index"
|
url: "#{@apiPath}/channels_facebook"
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@stopLoading()
|
@stopLoading()
|
||||||
|
@ -62,9 +62,6 @@ class Index extends App.ControllerSubContent
|
||||||
@html App.view('facebook/list')(
|
@html App.view('facebook/list')(
|
||||||
channels: channels
|
channels: channels
|
||||||
)
|
)
|
||||||
# accounts: accounts
|
|
||||||
# showDescription: showDescription
|
|
||||||
# description: description
|
|
||||||
|
|
||||||
if @channel_id
|
if @channel_id
|
||||||
@edit(undefined, @channel_id)
|
@edit(undefined, @channel_id)
|
||||||
|
@ -103,41 +100,45 @@ class Index extends App.ControllerSubContent
|
||||||
delete: (e) =>
|
delete: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
new App.ControllerConfirm(
|
||||||
new App.ControllerGenericDestroyConfirm(
|
message: 'Sure?'
|
||||||
item: item
|
callback: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'facebook_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/channels_facebook"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
callback: @load
|
|
||||||
)
|
)
|
||||||
|
|
||||||
disable: (e) =>
|
disable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = false
|
id: 'facebook_disable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_facebook_disable"
|
||||||
@load()
|
data: JSON.stringify(id: id)
|
||||||
fail: =>
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
enable: (e) =>
|
enable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = true
|
id: 'facebook_enable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_facebook_enable"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
fail: =>
|
|
||||||
@load()
|
|
||||||
)
|
|
||||||
|
|
||||||
description: (e) =>
|
|
||||||
new App.ControllerGenericDescription(
|
|
||||||
description: App.Twitter.description
|
|
||||||
container: @el.closest('.content')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class AppConfig extends App.ControllerModal
|
class AppConfig extends App.ControllerModal
|
||||||
|
@ -182,7 +183,7 @@ class AppConfig extends App.ControllerModal
|
||||||
done: =>
|
done: =>
|
||||||
@isChanged = true
|
@isChanged = true
|
||||||
@close()
|
@close()
|
||||||
fail: ->
|
fail: =>
|
||||||
@el.find('.alert').removeClass('hidden').text('Unable to create entry.')
|
@el.find('.alert').removeClass('hidden').text('Unable to create entry.')
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -241,14 +242,16 @@ class AccountEdit extends App.ControllerModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'channel_facebook_update'
|
id: 'channel_facebook_update'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: "#{@apiPath}/channels/facebook_verify/#{@channel.id}"
|
url: "#{@apiPath}/channels_facebook/#{@channel.id}"
|
||||||
data: JSON.stringify(@channel.attributes())
|
data: JSON.stringify(@channel.attributes())
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@isChanged = true
|
@isChanged = true
|
||||||
@close()
|
@close()
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@formEnable(e)
|
@formEnable(e)
|
||||||
|
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set('Facebook', { prio: 5100, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: Index, permission: ['admin.channel_facebook'] }, 'NavBarAdmin')
|
App.Config.set('Facebook', { prio: 5100, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: Index, permission: ['admin.channel_facebook'] }, 'NavBarAdmin')
|
||||||
|
|
202
app/assets/javascripts/app/controllers/_channel/telegram.coffee
Normal file
202
app/assets/javascripts/app/controllers/_channel/telegram.coffee
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
class Index extends App.ControllerSubContent
|
||||||
|
requiredPermission: 'admin.channel_telegram'
|
||||||
|
events:
|
||||||
|
'click .js-new': 'new'
|
||||||
|
'click .js-edit': 'edit'
|
||||||
|
'click .js-delete': 'delete'
|
||||||
|
'click .js-disable': 'disable'
|
||||||
|
'click .js-enable': 'enable'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
|
||||||
|
#@interval(@load, 60000)
|
||||||
|
@load()
|
||||||
|
|
||||||
|
load: =>
|
||||||
|
@startLoading()
|
||||||
|
@ajax(
|
||||||
|
id: 'telegram_index'
|
||||||
|
type: 'GET'
|
||||||
|
url: "#{@apiPath}/channels_telegram"
|
||||||
|
processData: true
|
||||||
|
success: (data) =>
|
||||||
|
@stopLoading()
|
||||||
|
App.Collection.loadAssets(data.assets)
|
||||||
|
@render(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
render: (data) =>
|
||||||
|
|
||||||
|
channels = []
|
||||||
|
for channel_id in data.channel_ids
|
||||||
|
channel = App.Channel.find(channel_id)
|
||||||
|
if channel && channel.options
|
||||||
|
displayName = '-'
|
||||||
|
if channel.group_id
|
||||||
|
group = App.Group.find(channel.group_id)
|
||||||
|
displayName = group.displayName()
|
||||||
|
channel.options.groupName = displayName
|
||||||
|
channels.push channel
|
||||||
|
@html App.view('telegram/index')(
|
||||||
|
channels: channels
|
||||||
|
)
|
||||||
|
|
||||||
|
new: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
new BotAdd(
|
||||||
|
container: @el.parents('.content')
|
||||||
|
load: @load
|
||||||
|
)
|
||||||
|
|
||||||
|
edit: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).closest('.action').data('id')
|
||||||
|
channel = App.Channel.find(id)
|
||||||
|
new BotEdit(
|
||||||
|
channel: channel
|
||||||
|
container: @el.parents('.content')
|
||||||
|
load: @load
|
||||||
|
)
|
||||||
|
|
||||||
|
delete: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).closest('.action').data('id')
|
||||||
|
new App.ControllerConfirm(
|
||||||
|
message: 'Sure?'
|
||||||
|
callback: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'telegram_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/channels_telegram"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
|
container: @el.closest('.content')
|
||||||
|
)
|
||||||
|
|
||||||
|
disable: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).closest('.action').data('id')
|
||||||
|
@ajax(
|
||||||
|
id: 'telegram_disable'
|
||||||
|
type: 'POST'
|
||||||
|
url: "#{@apiPath}/channels_telegram_disable"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
|
|
||||||
|
enable: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).closest('.action').data('id')
|
||||||
|
@ajax(
|
||||||
|
id: 'telegram_enable'
|
||||||
|
type: 'POST'
|
||||||
|
url: "#{@apiPath}/channels_telegram_enable"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
|
|
||||||
|
class BotAdd extends App.ControllerModal
|
||||||
|
head: 'Add Telegram Bot'
|
||||||
|
shown: true
|
||||||
|
button: 'Add'
|
||||||
|
buttonCancel: true
|
||||||
|
small: true
|
||||||
|
|
||||||
|
content: ->
|
||||||
|
content = $(App.view('telegram/bot_add')())
|
||||||
|
createGroupSelection = (selected_id) ->
|
||||||
|
return App.UiElement.select.render(
|
||||||
|
name: 'group_id'
|
||||||
|
multiple: false
|
||||||
|
limit: 100
|
||||||
|
null: false
|
||||||
|
relation: 'Group'
|
||||||
|
nulloption: true
|
||||||
|
value: selected_id
|
||||||
|
class: 'form-control--small'
|
||||||
|
)
|
||||||
|
|
||||||
|
content.find('.js-select').on('click', (e) =>
|
||||||
|
@selectAll(e)
|
||||||
|
)
|
||||||
|
content.find('.js-messagesGroup').replaceWith createGroupSelection(1)
|
||||||
|
content
|
||||||
|
|
||||||
|
onClosed: =>
|
||||||
|
return if !@isChanged
|
||||||
|
@isChanged = false
|
||||||
|
@load()
|
||||||
|
|
||||||
|
onSubmit: (e) =>
|
||||||
|
@formDisable(e)
|
||||||
|
@ajax(
|
||||||
|
id: 'telegram_app_verify'
|
||||||
|
type: 'POST'
|
||||||
|
url: "#{@apiPath}/channels_telegram"
|
||||||
|
data: JSON.stringify(@formParams())
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@isChanged = true
|
||||||
|
@close()
|
||||||
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
|
@formEnable(e)
|
||||||
|
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save Bot.')
|
||||||
|
)
|
||||||
|
|
||||||
|
class BotEdit extends App.ControllerModal
|
||||||
|
head: 'Telegram Account'
|
||||||
|
shown: true
|
||||||
|
buttonCancel: true
|
||||||
|
|
||||||
|
content: ->
|
||||||
|
content = $(App.view('telegram/bot_edit')(channel: @channel))
|
||||||
|
|
||||||
|
createGroupSelection = (selected_id) ->
|
||||||
|
return App.UiElement.select.render(
|
||||||
|
name: 'group_id'
|
||||||
|
multiple: false
|
||||||
|
limit: 100
|
||||||
|
null: false
|
||||||
|
relation: 'Group'
|
||||||
|
nulloption: true
|
||||||
|
value: selected_id
|
||||||
|
class: 'form-control--small'
|
||||||
|
)
|
||||||
|
|
||||||
|
content.find('.js-messagesGroup').replaceWith createGroupSelection(@channel.group_id)
|
||||||
|
content
|
||||||
|
|
||||||
|
onClosed: =>
|
||||||
|
return if !@isChanged
|
||||||
|
@isChanged = false
|
||||||
|
@load()
|
||||||
|
|
||||||
|
onSubmit: (e) =>
|
||||||
|
@formDisable(e)
|
||||||
|
params = @formParams()
|
||||||
|
@channel.options = params
|
||||||
|
@ajax(
|
||||||
|
id: 'channel_telegram_update'
|
||||||
|
type: 'PUT'
|
||||||
|
url: "#{@apiPath}/channels_telegram/#{@channel.id}"
|
||||||
|
data: JSON.stringify(@formParams())
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@isChanged = true
|
||||||
|
@close()
|
||||||
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
|
@formEnable(e)
|
||||||
|
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Config.set('Telegram', { prio: 5100, name: 'Telegram', parent: '#channels', target: '#channels/telegram', controller: Index, permission: ['admin.channel_telegram'] }, 'NavBarAdmin')
|
|
@ -19,7 +19,7 @@ class Index extends App.ControllerSubContent
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'twitter_index'
|
id: 'twitter_index'
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
url: "#{@apiPath}/channels/twitter_index"
|
url: "#{@apiPath}/channels_twitter"
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@stopLoading()
|
@stopLoading()
|
||||||
|
@ -61,9 +61,6 @@ class Index extends App.ControllerSubContent
|
||||||
@html App.view('twitter/list')(
|
@html App.view('twitter/list')(
|
||||||
channels: channels
|
channels: channels
|
||||||
)
|
)
|
||||||
# accounts: accounts
|
|
||||||
# showDescription: showDescription
|
|
||||||
# description: description
|
|
||||||
|
|
||||||
if @channel_id
|
if @channel_id
|
||||||
@edit(undefined, @channel_id)
|
@edit(undefined, @channel_id)
|
||||||
|
@ -102,41 +99,45 @@ class Index extends App.ControllerSubContent
|
||||||
delete: (e) =>
|
delete: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
new App.ControllerConfirm(
|
||||||
new App.ControllerGenericDestroyConfirm(
|
message: 'Sure?'
|
||||||
item: item
|
callback: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'twitter_delete'
|
||||||
|
type: 'DELETE'
|
||||||
|
url: "#{@apiPath}/channels_twitter"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
|
@load()
|
||||||
|
)
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
callback: @load
|
|
||||||
)
|
)
|
||||||
|
|
||||||
disable: (e) =>
|
disable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = false
|
id: 'twitter_disable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_twitter_disable"
|
||||||
@load()
|
data: JSON.stringify(id: id)
|
||||||
fail: =>
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
)
|
)
|
||||||
|
|
||||||
enable: (e) =>
|
enable: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
id = $(e.target).closest('.action').data('id')
|
id = $(e.target).closest('.action').data('id')
|
||||||
item = App.Channel.find(id)
|
@ajax(
|
||||||
item.active = true
|
id: 'twitter_enable'
|
||||||
item.save(
|
type: 'POST'
|
||||||
done: =>
|
url: "#{@apiPath}/channels_twitter_enable"
|
||||||
|
data: JSON.stringify(id: id)
|
||||||
|
processData: true
|
||||||
|
success: =>
|
||||||
@load()
|
@load()
|
||||||
fail: =>
|
|
||||||
@load()
|
|
||||||
)
|
|
||||||
|
|
||||||
description: (e) =>
|
|
||||||
new App.ControllerGenericDescription(
|
|
||||||
description: App.Twitter.description
|
|
||||||
container: @el.closest('.content')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class AppConfig extends App.ControllerModal
|
class AppConfig extends App.ControllerModal
|
||||||
|
@ -277,14 +278,16 @@ class AccountEdit extends App.ControllerModal
|
||||||
@ajax(
|
@ajax(
|
||||||
id: 'channel_twitter_update'
|
id: 'channel_twitter_update'
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
url: "#{@apiPath}/channels/twitter_verify/#{@channel.id}"
|
url: "#{@apiPath}/channels_twitter/#{@channel.id}"
|
||||||
data: JSON.stringify(@channel.attributes())
|
data: JSON.stringify(@channel.attributes())
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@isChanged = true
|
@isChanged = true
|
||||||
@close()
|
@close()
|
||||||
fail: =>
|
error: (xhr) =>
|
||||||
|
data = JSON.parse(xhr.responseText)
|
||||||
@formEnable(e)
|
@formEnable(e)
|
||||||
|
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set('Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: Index, permission: ['admin.channel_twitter'] }, 'NavBarAdmin')
|
App.Config.set('Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: Index, permission: ['admin.channel_twitter'] }, 'NavBarAdmin')
|
||||||
|
|
|
@ -7,6 +7,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
'click [data-type=twitterStatusReply]': 'twitterStatusReply'
|
'click [data-type=twitterStatusReply]': 'twitterStatusReply'
|
||||||
'click [data-type=twitterDirectMessageReply]': 'twitterDirectMessageReply'
|
'click [data-type=twitterDirectMessageReply]': 'twitterDirectMessageReply'
|
||||||
'click [data-type=facebookFeedReply]': 'facebookFeedReply'
|
'click [data-type=facebookFeedReply]': 'facebookFeedReply'
|
||||||
|
'click [data-type=telegramPersonalMessageReply]': 'telegramPersonalMessageReply'
|
||||||
'click [data-type=delete]': 'delete'
|
'click [data-type=delete]': 'delete'
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
|
@ -151,6 +152,13 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
icon: 'reply'
|
icon: 'reply'
|
||||||
href: '#'
|
href: '#'
|
||||||
}
|
}
|
||||||
|
if article.sender.name is 'Customer' && article.type.name is 'telegram personal-message'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'telegramPersonalMessageReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
actions.push {
|
actions.push {
|
||||||
name: 'split'
|
name: 'split'
|
||||||
|
@ -399,6 +407,34 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
||||||
|
|
||||||
|
telegramPersonalMessageReply: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
article_id = $(e.target).parents('[data-id]').data('id')
|
||||||
|
article = App.TicketArticle.fullLocal(article_id)
|
||||||
|
sender = App.TicketArticleSender.find(article.sender_id)
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
customer = App.User.find(article.created_by_id)
|
||||||
|
|
||||||
|
@scrollToCompose()
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
# get current body
|
||||||
|
articleNew.body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html().trim() || ''
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew, position: 'end' } )
|
||||||
|
|
||||||
delete: (e) =>
|
delete: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
possibleArticleType['email'] = true
|
possibleArticleType['email'] = true
|
||||||
else if articleTypeCreate is 'facebook feed post'
|
else if articleTypeCreate is 'facebook feed post'
|
||||||
possibleArticleType['facebook feed comment'] = true
|
possibleArticleType['facebook feed comment'] = true
|
||||||
|
else if articleTypeCreate is 'telegram personal-message'
|
||||||
|
possibleArticleType['telegram personal-message'] = true
|
||||||
if @ticket && @ticket.customer_id
|
if @ticket && @ticket.customer_id
|
||||||
customer = App.User.find(@ticket.customer_id)
|
customer = App.User.find(@ticket.customer_id)
|
||||||
if customer.email
|
if customer.email
|
||||||
|
@ -105,6 +107,16 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
internal: false,
|
internal: false,
|
||||||
features: ['attachment']
|
features: ['attachment']
|
||||||
}
|
}
|
||||||
|
if possibleArticleType['telegram personal-message']
|
||||||
|
@articleTypes.push {
|
||||||
|
name: 'telegram personal-message'
|
||||||
|
icon: 'telegram'
|
||||||
|
attributes: []
|
||||||
|
internal: false,
|
||||||
|
features: ['attachment']
|
||||||
|
maxTextLength: 10000
|
||||||
|
warningTextLength: 5000
|
||||||
|
}
|
||||||
|
|
||||||
if @permissionCheck('ticket.customer')
|
if @permissionCheck('ticket.customer')
|
||||||
@type = 'note'
|
@type = 'note'
|
||||||
|
@ -335,6 +347,11 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
params.content_type = 'text/plain'
|
params.content_type = 'text/plain'
|
||||||
params.body = App.Utils.html2text(params.body, true)
|
params.body = App.Utils.html2text(params.body, true)
|
||||||
|
|
||||||
|
if params.type is 'telegram personal-message'
|
||||||
|
App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
|
||||||
|
params.content_type = 'text/plain'
|
||||||
|
params.body = App.Utils.html2text(params.body, true)
|
||||||
|
|
||||||
params
|
params
|
||||||
|
|
||||||
validate: =>
|
validate: =>
|
||||||
|
@ -499,7 +516,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
@$('[data-name=body] [data-signature=true]').remove()
|
@$('[data-name=body] [data-signature=true]').remove()
|
||||||
|
|
||||||
# remove richtext
|
# remove richtext
|
||||||
if @type is 'twitter status' || @type is 'twitter direct-message'
|
if @type is 'twitter status' || @type is 'twitter direct-message' || @type is 'telegram personal-message'
|
||||||
rawHTML = @$('[data-name=body]').html()
|
rawHTML = @$('[data-name=body]').html()
|
||||||
cleanHTML = App.Utils.htmlRemoveRichtext(rawHTML)
|
cleanHTML = App.Utils.htmlRemoveRichtext(rawHTML)
|
||||||
if cleanHTML && cleanHTML.html() != rawHTML
|
if cleanHTML && cleanHTML.html() != rawHTML
|
||||||
|
|
32
app/assets/javascripts/app/views/telegram/bot_add.jst.eco
Normal file
32
app/assets/javascripts/app/views/telegram/bot_add.jst.eco
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<div class="alert alert--danger hidden" role="alert"></div>
|
||||||
|
<p>
|
||||||
|
<%- @T('The tutorial on how to manage a %s is hosted on our [online documentation](https://zammad.org/documentation/channel/telegram).', 'Telegram Bot') %>
|
||||||
|
</p>
|
||||||
|
<fieldset>
|
||||||
|
<h2><%- @T('Enter your %s App Keys', 'Telegram') %></h2>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for="api_token"><%- @T('%s Api Token', 'Telegram') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<input id="api_token" type="text" name="api_token" value="" class="form-control" required autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2><%- @T('Settings') %></h2>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for="welcome"><%- @T('Welcome message') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<input id="welcome" type="text" name="welcome" value="" placeholder="<%- @Ti('You are welcome! Just ask me something!') %>" class="form-control" required autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for=""><%- @T('Choose which group %s will get added to.', 'messages') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<div class="js-messagesGroup"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
29
app/assets/javascripts/app/views/telegram/bot_edit.jst.eco
Normal file
29
app/assets/javascripts/app/views/telegram/bot_edit.jst.eco
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="alert alert--danger hidden" role="alert"></div>
|
||||||
|
<fieldset>
|
||||||
|
<h2><%- @T('Enter your %s App Keys', 'Telegram') %></h2>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for="api_token"><%- @T('%s Api Token', 'Telegram') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<input id="api_token" type="text" name="api_token" value="<%= @channel.options.api_token %>" class="form-control" required autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2><%- @T('Settings') %></h2>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for="welcome"><%- @T('welcome message') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<input id="welcome" type="text" name="welcome" value="<%= @channel.options.welcome %>" placeholder="<%- @Ti('You are welcome! Just ask me something!') %>" class="form-control" required autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input form-group">
|
||||||
|
<div class="formGroup-label">
|
||||||
|
<label for=""><%- @T('Choose which group %s will get added to.', 'messages') %> <span>*</span></label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<div class="js-messagesGroup"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
48
app/assets/javascripts/app/views/telegram/index.jst.eco
Normal file
48
app/assets/javascripts/app/views/telegram/index.jst.eco
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="page-header-title">
|
||||||
|
<h1><%- @T('Telegram') %> <small><%- @T('Bots') %></small></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-header-meta">
|
||||||
|
<a class="btn btn--success js-new"><%- @T('Add Bot') %></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-content">
|
||||||
|
|
||||||
|
<% if _.isEmpty(@channels): %>
|
||||||
|
<div class="page-description">
|
||||||
|
<p><%- @T('You have no configured %s right now.', 'Telegram Bot') %></p>
|
||||||
|
</div>
|
||||||
|
<% else: %>
|
||||||
|
|
||||||
|
<% for channel in @channels: %>
|
||||||
|
<div class="action <% if channel.active isnt true: %>is-inactive<% end %>" data-id="<%= channel.id %>">
|
||||||
|
<div class="action-block action-row">
|
||||||
|
<h2><%- @Icon('status', 'supergood-color inline') %> <%= channel.options.bot.first_name %> <span class="text-muted">@<%= channel.options.bot.username %></span></h2>
|
||||||
|
</div>
|
||||||
|
<div class="action-flow action-flow--row">
|
||||||
|
<div class="action-block">
|
||||||
|
<h3><%- @T('Messages') %></h3>
|
||||||
|
@<%= channel.options.bot.username %>
|
||||||
|
</div>
|
||||||
|
<%- @Icon('arrow-right', 'action-flow-icon') %>
|
||||||
|
<div class="action-block">
|
||||||
|
<h3><%- @T('Group') %></h3>
|
||||||
|
<% if channel.options: %>
|
||||||
|
<%= channel.options.groupName %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="action-controls">
|
||||||
|
<div class="btn btn--danger btn--secondary js-delete"><%- @T('Delete') %></div>
|
||||||
|
<% if channel.active is true: %>
|
||||||
|
<div class="btn btn--secondary js-disable"><%- @T('Disable') %></div>
|
||||||
|
<% else: %>
|
||||||
|
<div class="btn btn--secondary js-enable"><%- @T('Enable') %></div>
|
||||||
|
<% end %>
|
||||||
|
<div class="btn js-edit"><%- @T('Edit') %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
|
@ -1,99 +1,9 @@
|
||||||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class ChannelsController < ApplicationController
|
class ChannelsEmailController < ApplicationController
|
||||||
before_action :authentication_check
|
before_action :authentication_check
|
||||||
|
|
||||||
=begin
|
def index
|
||||||
|
|
||||||
Resource:
|
|
||||||
POST /api/v1/channels/group/{id}.json
|
|
||||||
|
|
||||||
Response:
|
|
||||||
{}
|
|
||||||
|
|
||||||
Test:
|
|
||||||
curl http://localhost/api/v1/group/channels.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST '{group_id:123}'
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def group_update
|
|
||||||
permission_check('admin')
|
|
||||||
check_access
|
|
||||||
|
|
||||||
channel = Channel.find(params[:id])
|
|
||||||
channel.group_id = params[:group_id]
|
|
||||||
channel.save
|
|
||||||
render json: {}
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
Resource:
|
|
||||||
DELETE /api/v1/channels/{id}.json
|
|
||||||
|
|
||||||
Response:
|
|
||||||
{}
|
|
||||||
|
|
||||||
Test:
|
|
||||||
curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
permission_check('admin')
|
|
||||||
check_access
|
|
||||||
model_destroy_render(Channel, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def twitter_index
|
|
||||||
permission_check('admin.channel_twitter')
|
|
||||||
assets = {}
|
|
||||||
ExternalCredential.where(name: 'twitter').each { |external_credential|
|
|
||||||
assets = external_credential.assets(assets)
|
|
||||||
}
|
|
||||||
channel_ids = []
|
|
||||||
Channel.order(:id).each { |channel|
|
|
||||||
next if channel.area != 'Twitter::Account'
|
|
||||||
assets = channel.assets(assets)
|
|
||||||
channel_ids.push channel.id
|
|
||||||
}
|
|
||||||
render json: {
|
|
||||||
assets: assets,
|
|
||||||
channel_ids: channel_ids,
|
|
||||||
callback_url: ExternalCredential.callback_url('twitter'),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def twitter_verify
|
|
||||||
permission_check('admin.channel_twitter')
|
|
||||||
model_update_render(Channel, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def facebook_index
|
|
||||||
permission_check('admin.channel_facebook')
|
|
||||||
assets = {}
|
|
||||||
ExternalCredential.where(name: 'facebook').each { |external_credential|
|
|
||||||
assets = external_credential.assets(assets)
|
|
||||||
}
|
|
||||||
channel_ids = []
|
|
||||||
Channel.order(:id).each { |channel|
|
|
||||||
next if channel.area != 'Facebook::Account'
|
|
||||||
assets = channel.assets(assets)
|
|
||||||
channel_ids.push channel.id
|
|
||||||
}
|
|
||||||
render json: {
|
|
||||||
assets: assets,
|
|
||||||
channel_ids: channel_ids,
|
|
||||||
callback_url: ExternalCredential.callback_url('facebook'),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def facebook_verify
|
|
||||||
permission_check('admin.channel_facebook')
|
|
||||||
model_update_render(Channel, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def email_index
|
|
||||||
permission_check('admin.channel_email')
|
permission_check('admin.channel_email')
|
||||||
system_online_service = Setting.get('system_online_service')
|
system_online_service = Setting.get('system_online_service')
|
||||||
account_channel_ids = []
|
account_channel_ids = []
|
||||||
|
@ -142,7 +52,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_probe
|
def probe
|
||||||
|
|
||||||
# check admin permissions
|
# check admin permissions
|
||||||
permission_check('admin.channel_email')
|
permission_check('admin.channel_email')
|
||||||
|
@ -156,13 +66,13 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
|
|
||||||
# verify if user+host already exists
|
# verify if user+host already exists
|
||||||
if result[:result] == 'ok'
|
if result[:result] == 'ok'
|
||||||
return if email_account_duplicate?(result)
|
return if account_duplicate?(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_outbound
|
def outbound
|
||||||
|
|
||||||
# check admin permissions
|
# check admin permissions
|
||||||
permission_check('admin.channel_email')
|
permission_check('admin.channel_email')
|
||||||
|
@ -174,7 +84,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
render json: EmailHelper::Probe.outbound(params, params[:email])
|
render json: EmailHelper::Probe.outbound(params, params[:email])
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_inbound
|
def inbound
|
||||||
|
|
||||||
# check admin permissions
|
# check admin permissions
|
||||||
permission_check('admin.channel_email')
|
permission_check('admin.channel_email')
|
||||||
|
@ -186,12 +96,12 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
result = EmailHelper::Probe.inbound(params)
|
result = EmailHelper::Probe.inbound(params)
|
||||||
|
|
||||||
# check account duplicate
|
# check account duplicate
|
||||||
return if email_account_duplicate?({ setting: { inbound: params } }, params[:channel_id])
|
return if account_duplicate?({ setting: { inbound: params } }, params[:channel_id])
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_verify
|
def verify
|
||||||
|
|
||||||
# check admin permissions
|
# check admin permissions
|
||||||
permission_check('admin.channel_email')
|
permission_check('admin.channel_email')
|
||||||
|
@ -204,7 +114,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
return if channel_id && !check_access(channel_id)
|
return if channel_id && !check_access(channel_id)
|
||||||
|
|
||||||
# check account duplicate
|
# check account duplicate
|
||||||
return if email_account_duplicate?({ setting: { inbound: params[:inbound] } }, channel_id)
|
return if account_duplicate?({ setting: { inbound: params[:inbound] } }, channel_id)
|
||||||
|
|
||||||
# check delivery for 30 sek.
|
# check delivery for 30 sek.
|
||||||
result = EmailHelper::Verify.email(
|
result = EmailHelper::Verify.email(
|
||||||
|
@ -284,7 +194,38 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_notification
|
def enable
|
||||||
|
permission_check('admin.channel_email')
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
|
||||||
|
channel.active = true
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
permission_check('admin.channel_email')
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
|
||||||
|
channel.active = false
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
permission_check('admin.channel_email')
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
|
||||||
|
channel.destroy
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def group
|
||||||
|
check_access
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Email::Account')
|
||||||
|
channel.group_id = params[:group_id]
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def notification
|
||||||
|
|
||||||
check_online_service
|
check_online_service
|
||||||
|
|
||||||
|
@ -323,7 +264,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def email_account_duplicate?(result, channel_id = nil)
|
def account_duplicate?(result, channel_id = nil)
|
||||||
Channel.where(area: 'Email::Account').each { |channel|
|
Channel.where(area: 'Email::Account').each { |channel|
|
||||||
next if !channel.options
|
next if !channel.options
|
||||||
next if !channel.options[:inbound]
|
next if !channel.options[:inbound]
|
47
app/controllers/channels_facebook_controller.rb
Normal file
47
app/controllers/channels_facebook_controller.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ChannelsFacebookController < ApplicationController
|
||||||
|
before_action { authentication_check(permission: 'admin.channel_facebook') }
|
||||||
|
|
||||||
|
def index
|
||||||
|
assets = {}
|
||||||
|
ExternalCredential.where(name: 'facebook').each { |external_credential|
|
||||||
|
assets = external_credential.assets(assets)
|
||||||
|
}
|
||||||
|
channel_ids = []
|
||||||
|
Channel.where(area: 'Facebook::Account').order(:id).each { |channel|
|
||||||
|
assets = channel.assets(assets)
|
||||||
|
channel_ids.push channel.id
|
||||||
|
}
|
||||||
|
render json: {
|
||||||
|
assets: assets,
|
||||||
|
channel_ids: channel_ids,
|
||||||
|
callback_url: ExternalCredential.callback_url('facebook'),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
model_update_render(Channel, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Facebook::Account')
|
||||||
|
channel.active = true
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Facebook::Account')
|
||||||
|
channel.active = false
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Facebook::Account')
|
||||||
|
channel.destroy
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
74
app/controllers/channels_telegram_controller.rb
Normal file
74
app/controllers/channels_telegram_controller.rb
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ChannelsTelegramController < ApplicationController
|
||||||
|
before_action -> { authentication_check(permission: 'admin.channel_telegram') }, except: [:webhook]
|
||||||
|
|
||||||
|
def index
|
||||||
|
assets = {}
|
||||||
|
channel_ids = []
|
||||||
|
Channel.where(area: 'Telegram::Bot').order(:id).each { |channel|
|
||||||
|
assets = channel.assets(assets)
|
||||||
|
channel_ids.push channel.id
|
||||||
|
}
|
||||||
|
render json: {
|
||||||
|
assets: assets,
|
||||||
|
channel_ids: channel_ids
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add
|
||||||
|
begin
|
||||||
|
channel = Telegram.create_or_update_channel(params[:api_token], params)
|
||||||
|
rescue => e
|
||||||
|
raise Exceptions::UnprocessableEntity, e.message
|
||||||
|
end
|
||||||
|
render json: channel
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Telegram::Bot')
|
||||||
|
begin
|
||||||
|
channel = Telegram.create_or_update_channel(params[:api_token], params, channel)
|
||||||
|
rescue => e
|
||||||
|
raise Exceptions::UnprocessableEntity, e.message
|
||||||
|
end
|
||||||
|
render json: channel
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Telegram::Bot')
|
||||||
|
channel.active = true
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Telegram::Bot')
|
||||||
|
channel.active = false
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Telegram::Bot')
|
||||||
|
channel.destroy
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def webhook
|
||||||
|
raise Exceptions::UnprocessableEntity, 'bot param missing' if params['bid'].blank?
|
||||||
|
|
||||||
|
channel = Telegram.bot_by_bot_id(params['bid'])
|
||||||
|
raise Exceptions::UnprocessableEntity, 'bot not found' if !channel
|
||||||
|
|
||||||
|
if channel.options[:callback_token] != params['callback_token']
|
||||||
|
raise Exceptions::UnprocessableEntity, 'invalid callback token'
|
||||||
|
end
|
||||||
|
|
||||||
|
telegram = Telegram.new(channel.options[:api_token])
|
||||||
|
telegram.to_group(params, channel.group_id, channel)
|
||||||
|
|
||||||
|
render json: {}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
47
app/controllers/channels_twitter_controller.rb
Normal file
47
app/controllers/channels_twitter_controller.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ChannelsTwitterController < ApplicationController
|
||||||
|
before_action { authentication_check(permission: 'admin.channel_twitter') }
|
||||||
|
|
||||||
|
def index
|
||||||
|
assets = {}
|
||||||
|
ExternalCredential.where(name: 'twitter').each { |external_credential|
|
||||||
|
assets = external_credential.assets(assets)
|
||||||
|
}
|
||||||
|
channel_ids = []
|
||||||
|
Channel.where(area: 'Twitter::Account').order(:id).each { |channel|
|
||||||
|
assets = channel.assets(assets)
|
||||||
|
channel_ids.push channel.id
|
||||||
|
}
|
||||||
|
render json: {
|
||||||
|
assets: assets,
|
||||||
|
channel_ids: channel_ids,
|
||||||
|
callback_url: ExternalCredential.callback_url('twitter'),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
model_update_render(Channel, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
|
||||||
|
channel.active = true
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
|
||||||
|
channel.active = false
|
||||||
|
channel.save!
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
|
||||||
|
channel.destroy
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
44
app/models/channel/driver/telegram.rb
Normal file
44
app/models/channel/driver/telegram.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class Channel::Driver::Telegram
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
instance = Channel::Driver::Telegram.new
|
||||||
|
instance.send(
|
||||||
|
{
|
||||||
|
adapter: 'telegram',
|
||||||
|
auth: {
|
||||||
|
api_key: api_key
|
||||||
|
},
|
||||||
|
},
|
||||||
|
telegram_attributes,
|
||||||
|
notification
|
||||||
|
)
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def send(options, article, _notification = false)
|
||||||
|
|
||||||
|
# return if we run import mode
|
||||||
|
return if Setting.get('import_mode')
|
||||||
|
|
||||||
|
options = check_external_credential(options)
|
||||||
|
|
||||||
|
@client = Telegram.new(options[:auth][:api_key])
|
||||||
|
message = @client.from_article(article)
|
||||||
|
message
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_external_credential(options)
|
||||||
|
if options[:auth] && options[:auth][:external_credential_id]
|
||||||
|
external_credential = ExternalCredential.find_by(id: options[:auth][:external_credential_id])
|
||||||
|
raise "No such ExternalCredential.find(#{options[:auth][:external_credential_id]})" if !external_credential
|
||||||
|
options[:auth][:api_key] = external_credential.credentials['api_key']
|
||||||
|
end
|
||||||
|
options
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
25
app/models/observer/ticket/article/communicate_telegram.rb
Normal file
25
app/models/observer/ticket/article/communicate_telegram.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class Observer::Ticket::Article::CommunicateTelegram < ActiveRecord::Observer
|
||||||
|
observe 'ticket::_article'
|
||||||
|
|
||||||
|
def after_create(record)
|
||||||
|
|
||||||
|
# return if we run import mode
|
||||||
|
return if Setting.get('import_mode')
|
||||||
|
|
||||||
|
# if sender is customer, do not communicate
|
||||||
|
return if !record.sender_id
|
||||||
|
sender = Ticket::Article::Sender.lookup(id: record.sender_id)
|
||||||
|
return if sender.nil?
|
||||||
|
return if sender['name'] == 'Customer'
|
||||||
|
|
||||||
|
# only apply on telegram messages
|
||||||
|
return if !record.type_id
|
||||||
|
type = Ticket::Article::Type.lookup(id: record.type_id)
|
||||||
|
return if type['name'] !~ /\Atelegram/i
|
||||||
|
|
||||||
|
Delayed::Job.enqueue(Observer::Ticket::Article::CommunicateTelegram::BackgroundJob.new(record.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,108 @@
|
||||||
|
class Observer::Ticket::Article::CommunicateTelegram::BackgroundJob
|
||||||
|
def initialize(id)
|
||||||
|
@article_id = id
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
article = Ticket::Article.find(@article_id)
|
||||||
|
|
||||||
|
# set retry count
|
||||||
|
if !article.preferences['delivery_retry']
|
||||||
|
article.preferences['delivery_retry'] = 0
|
||||||
|
end
|
||||||
|
article.preferences['delivery_retry'] += 1
|
||||||
|
|
||||||
|
ticket = Ticket.lookup(id: article.ticket_id)
|
||||||
|
log_error(article, "Can't find ticket.preferences for Ticket.find(#{article.ticket_id})") if !ticket.preferences
|
||||||
|
log_error(article, "Can't find ticket.preferences['telegram'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']
|
||||||
|
log_error(article, "Can't find ticket.preferences['telegram']['chat_id'] for Ticket.find(#{article.ticket_id})") if !ticket.preferences['telegram']['chat_id']
|
||||||
|
if ticket.preferences['telegram'] && ticket.preferences['telegram']['bid']
|
||||||
|
channel = Telegram.bot_by_bot_id(ticket.preferences['telegram']['bid'])
|
||||||
|
end
|
||||||
|
if !channel
|
||||||
|
channel = Channel.lookup(id: ticket.preferences['channel_id'])
|
||||||
|
end
|
||||||
|
log_error(article, "No such channel for bot #{ticket.preferences['bid']} or channel id #{ticket.preferences['channel_id']}") if !channel
|
||||||
|
#log_error(article, "Channel.find(#{channel.id}) isn't a telegram channel!") if channel.options[:adapter] !~ /\Atelegram/i
|
||||||
|
log_error(article, "Channel.find(#{channel.id}) has not telegram api token!") if channel.options[:api_token].blank?
|
||||||
|
|
||||||
|
begin
|
||||||
|
api = TelegramAPI.new(channel.options[:api_token])
|
||||||
|
chat_id = ticket.preferences[:telegram][:chat_id]
|
||||||
|
result = api.sendMessage(chat_id, article.body)
|
||||||
|
article.attachments.each { |file|
|
||||||
|
parts = file.filename.split(/^(.*)(\..+?)$/)
|
||||||
|
t = Tempfile.new([parts[1], parts[2]])
|
||||||
|
t.binmode
|
||||||
|
t.write(file.content)
|
||||||
|
t.rewind
|
||||||
|
api.sendDocument(chat_id, t.path.to_s)
|
||||||
|
}
|
||||||
|
rescue => e
|
||||||
|
log_error(article, e.message)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# fill article with message info
|
||||||
|
article.from = "@#{result['from']['username']}"
|
||||||
|
article.to = "@#{result['chat']['username']}"
|
||||||
|
|
||||||
|
article.preferences['telegram'] = {
|
||||||
|
date: result['date'],
|
||||||
|
from_id: result['from']['id'],
|
||||||
|
chat_id: result['chat']['id'],
|
||||||
|
message_id: result['message_id']
|
||||||
|
}
|
||||||
|
|
||||||
|
# set delivery status
|
||||||
|
article.preferences['delivery_status_message'] = nil
|
||||||
|
article.preferences['delivery_status'] = 'success'
|
||||||
|
article.preferences['delivery_status_date'] = Time.zone.now
|
||||||
|
|
||||||
|
article.message_id = "telegram.#{result['message_id']}.#{result['chat']['id']}"
|
||||||
|
|
||||||
|
article.save!
|
||||||
|
|
||||||
|
Rails.logger.info "Send telegram message to: '#{article.to}' (from #{article.from})"
|
||||||
|
|
||||||
|
article
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_error(local_record, message)
|
||||||
|
local_record.preferences['delivery_status'] = 'fail'
|
||||||
|
local_record.preferences['delivery_status_message'] = message
|
||||||
|
local_record.preferences['delivery_status_date'] = Time.zone.now
|
||||||
|
local_record.save
|
||||||
|
Rails.logger.error message
|
||||||
|
|
||||||
|
if local_record.preferences['delivery_retry'] > 3
|
||||||
|
Ticket::Article.create(
|
||||||
|
ticket_id: local_record.ticket_id,
|
||||||
|
content_type: 'text/plain',
|
||||||
|
body: "Unable to send telegram message: #{message}",
|
||||||
|
internal: true,
|
||||||
|
sender: Ticket::Article::Sender.find_by(name: 'System'),
|
||||||
|
type: Ticket::Article::Type.find_by(name: 'note'),
|
||||||
|
preferences: {
|
||||||
|
delivery_article_id_related: local_record.id,
|
||||||
|
delivery_message: true,
|
||||||
|
},
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
raise message
|
||||||
|
end
|
||||||
|
|
||||||
|
def max_attempts
|
||||||
|
4
|
||||||
|
end
|
||||||
|
|
||||||
|
def reschedule_at(current_time, attempts)
|
||||||
|
if Rails.env.production?
|
||||||
|
return current_time + attempts * 120.seconds
|
||||||
|
end
|
||||||
|
current_time + 5.seconds
|
||||||
|
end
|
||||||
|
end
|
|
@ -30,6 +30,7 @@ module Zammad
|
||||||
'observer::_ticket::_article::_communicate_email',
|
'observer::_ticket::_article::_communicate_email',
|
||||||
'observer::_ticket::_article::_communicate_facebook',
|
'observer::_ticket::_article::_communicate_facebook',
|
||||||
'observer::_ticket::_article::_communicate_twitter',
|
'observer::_ticket::_article::_communicate_twitter',
|
||||||
|
'observer::_ticket::_article::_communicate_telegram',
|
||||||
'observer::_ticket::_reset_new_state',
|
'observer::_ticket::_reset_new_state',
|
||||||
'observer::_ticket::_ref_object_touch',
|
'observer::_ticket::_ref_object_touch',
|
||||||
'observer::_ticket::_online_notification_seen',
|
'observer::_ticket::_online_notification_seen',
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
Zammad::Application.routes.draw do
|
|
||||||
api_path = Rails.configuration.api_path
|
|
||||||
|
|
||||||
# email helper
|
|
||||||
match api_path + '/channels/email_index', to: 'channels#email_index', via: :get
|
|
||||||
match api_path + '/channels/email_probe', to: 'channels#email_probe', via: :post
|
|
||||||
match api_path + '/channels/email_outbound', to: 'channels#email_outbound', via: :post
|
|
||||||
match api_path + '/channels/email_inbound', to: 'channels#email_inbound', via: :post
|
|
||||||
match api_path + '/channels/email_verify', to: 'channels#email_verify', via: :post
|
|
||||||
match api_path + '/channels/email_notification', to: 'channels#email_notification', via: :post
|
|
||||||
|
|
||||||
# twitter helper
|
|
||||||
match api_path + '/channels/twitter_index', to: 'channels#twitter_index', via: :get
|
|
||||||
match api_path + '/channels/twitter_verify/:id', to: 'channels#twitter_verify', via: :post
|
|
||||||
|
|
||||||
# facebook helper
|
|
||||||
match api_path + '/channels/facebook_index', to: 'channels#facebook_index', via: :get
|
|
||||||
match api_path + '/channels/facebook_verify/:id', to: 'channels#facebook_verify', via: :post
|
|
||||||
|
|
||||||
# channels
|
|
||||||
match api_path + '/channels/group/:id', to: 'channels#group_update', via: :post
|
|
||||||
match api_path + '/channels/:id', to: 'channels#destroy', via: :delete
|
|
||||||
|
|
||||||
end
|
|
15
config/routes/channel_email.rb
Normal file
15
config/routes/channel_email.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
match api_path + '/channels_email', to: 'channels_email#index', via: :get
|
||||||
|
match api_path + '/channels_email_probe', to: 'channels_email#probe', via: :post
|
||||||
|
match api_path + '/channels_email_outbound', to: 'channels_email#outbound', via: :post
|
||||||
|
match api_path + '/channels_email_inbound', to: 'channels_email#inbound', via: :post
|
||||||
|
match api_path + '/channels_email_verify', to: 'channels_email#verify', via: :post
|
||||||
|
match api_path + '/channels_email_notification', to: 'channels_email#notification', via: :post
|
||||||
|
match api_path + '/channels_email_disable', to: 'channels_email#disable', via: :post
|
||||||
|
match api_path + '/channels_email_enable', to: 'channels_email#enable', via: :post
|
||||||
|
match api_path + '/channels_email', to: 'channels_email#destroy', via: :delete
|
||||||
|
match api_path + '/channels_email_group/:id', to: 'channels_email#group', via: :post
|
||||||
|
|
||||||
|
end
|
9
config/routes/channel_facebook.rb
Normal file
9
config/routes/channel_facebook.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
match api_path + '/channels_facebook', to: 'channels_facebook#index', via: :get
|
||||||
|
match api_path + '/channels_facebook/:id', to: 'channels_facebook#update', via: :post
|
||||||
|
match api_path + '/channels_facebook_disable', to: 'channels_facebook#disable', via: :post
|
||||||
|
match api_path + '/channels_facebook_enable', to: 'channels_facebook#enable', via: :post
|
||||||
|
match api_path + '/channels_facebook', to: 'channels_facebook#destroy', via: :delete
|
||||||
|
end
|
12
config/routes/channel_telegram.rb
Normal file
12
config/routes/channel_telegram.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
match api_path + '/channels_telegram', to: 'channels_telegram#index', via: :get
|
||||||
|
match api_path + '/channels_telegram', to: 'channels_telegram#add', via: :post
|
||||||
|
match api_path + '/channels_telegram/:id', to: 'channels_telegram#update', via: :put
|
||||||
|
match api_path + '/channels_telegram_webhook/:callback_token', to: 'channels_telegram#webhook', via: :post
|
||||||
|
match api_path + '/channels_telegram_disable', to: 'channels_telegram#disable', via: :post
|
||||||
|
match api_path + '/channels_telegram_enable', to: 'channels_telegram#enable', via: :post
|
||||||
|
match api_path + '/channels_telegram', to: 'channels_telegram#destroy', via: :delete
|
||||||
|
|
||||||
|
end
|
9
config/routes/channel_twitter.rb
Normal file
9
config/routes/channel_twitter.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
match api_path + '/channels_twitter', to: 'channels_twitter#index', via: :get
|
||||||
|
match api_path + '/channels_twitter/:id', to: 'channels_twitter#update', via: :post
|
||||||
|
match api_path + '/channels_twitter_disable', to: 'channels_twitter#disable', via: :post
|
||||||
|
match api_path + '/channels_twitter_enable', to: 'channels_twitter#enable', via: :post
|
||||||
|
match api_path + '/channels_twitter', to: 'channels_twitter#destroy', via: :delete
|
||||||
|
end
|
22
db/migrate/20170215000001_telegram_support.rb
Normal file
22
db/migrate/20170215000001_telegram_support.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class TelegramSupport < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
|
||||||
|
# return if it's a new setup
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
Permission.create_if_not_exists(
|
||||||
|
name: 'admin.channel_telegram',
|
||||||
|
note: 'Manage %s',
|
||||||
|
preferences: {
|
||||||
|
translations: ['Channel - Telegram']
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
Ticket::Article::Type.create_if_not_exists(
|
||||||
|
id: 12,
|
||||||
|
name: 'telegram personal-message',
|
||||||
|
communication: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -2894,6 +2894,13 @@ Permission.create_if_not_exists(
|
||||||
translations: ['Channel - Facebook']
|
translations: ['Channel - Facebook']
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
Permission.create_if_not_exists(
|
||||||
|
name: 'admin.channel_telegram',
|
||||||
|
note: 'Manage %s',
|
||||||
|
preferences: {
|
||||||
|
translations: ['Channel - Telegram']
|
||||||
|
},
|
||||||
|
)
|
||||||
Permission.create_if_not_exists(
|
Permission.create_if_not_exists(
|
||||||
name: 'admin.channel_chat',
|
name: 'admin.channel_chat',
|
||||||
note: 'Manage %s',
|
note: 'Manage %s',
|
||||||
|
@ -3241,6 +3248,7 @@ Ticket::Article::Type.create_if_not_exists(id: 8, name: 'facebook feed post', co
|
||||||
Ticket::Article::Type.create_if_not_exists(id: 9, name: 'facebook feed comment', communication: true)
|
Ticket::Article::Type.create_if_not_exists(id: 9, name: 'facebook feed comment', communication: true)
|
||||||
Ticket::Article::Type.create_if_not_exists(id: 10, name: 'note', communication: false)
|
Ticket::Article::Type.create_if_not_exists(id: 10, name: 'note', communication: false)
|
||||||
Ticket::Article::Type.create_if_not_exists(id: 11, name: 'web', communication: true)
|
Ticket::Article::Type.create_if_not_exists(id: 11, name: 'web', communication: true)
|
||||||
|
Ticket::Article::Type.create_if_not_exists(id: 12, name: 'telegram personal-message', communication: true)
|
||||||
|
|
||||||
Ticket::Article::Sender.create_if_not_exists(id: 1, name: 'Agent')
|
Ticket::Article::Sender.create_if_not_exists(id: 1, name: 'Agent')
|
||||||
Ticket::Article::Sender.create_if_not_exists(id: 2, name: 'Customer')
|
Ticket::Article::Sender.create_if_not_exists(id: 2, name: 'Customer')
|
||||||
|
|
573
lib/telegram.rb
Normal file
573
lib/telegram.rb
Normal file
|
@ -0,0 +1,573 @@
|
||||||
|
# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
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
|
||||||
|
bot = api.getMe()
|
||||||
|
rescue
|
||||||
|
raise 'invalid api token'
|
||||||
|
end
|
||||||
|
bot
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
set webhool for bot
|
||||||
|
|
||||||
|
success = Telegram.set_webhook('token', callback_url)
|
||||||
|
|
||||||
|
returns
|
||||||
|
|
||||||
|
true|false
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def self.set_webhook(token, callback_url)
|
||||||
|
if callback_url =~ /^http:\/\//i
|
||||||
|
raise 'webhook url need to start with https://, you use http://'
|
||||||
|
end
|
||||||
|
api = TelegramAPI.new(token)
|
||||||
|
begin
|
||||||
|
api.setWebhook(callback_url)
|
||||||
|
rescue
|
||||||
|
raise 'Unable to set webhook at Telegram, seems to be a invalid url.'
|
||||||
|
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)
|
||||||
|
|
||||||
|
if !channel
|
||||||
|
if Telegram.bot_duplicate?(bot['id'])
|
||||||
|
raise 'Bot already exists!'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:group_id].blank?
|
||||||
|
raise 'Group needed!'
|
||||||
|
else
|
||||||
|
group = Group.find_by(id: params[:group_id])
|
||||||
|
end
|
||||||
|
if !group
|
||||||
|
raise 'Group invalid!'
|
||||||
|
end
|
||||||
|
|
||||||
|
# generate randam callback token
|
||||||
|
callback_token = SecureRandom.urlsafe_base64(10)
|
||||||
|
|
||||||
|
# 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 = {
|
||||||
|
bot: {
|
||||||
|
id: bot['id'],
|
||||||
|
username: bot['username'],
|
||||||
|
first_name: bot['first_name'],
|
||||||
|
last_name: bot['last_name'],
|
||||||
|
},
|
||||||
|
callback_token: callback_token,
|
||||||
|
callback_url: callback_url,
|
||||||
|
api_token: token,
|
||||||
|
welcome: params[:welcome],
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
Channel.where(area: 'Telegram::Bot').each { |channel|
|
||||||
|
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
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
Channel.where(area: 'Telegram::Bot').each { |channel|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
[:message, :edited_message].each { |key|
|
||||||
|
next if !params[key]
|
||||||
|
next if !params[key][:message_id]
|
||||||
|
message_id = params[key][:message_id]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
client.message(chat_id, 'some message')
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def message(chat_id, message)
|
||||||
|
return if Rails.env.test?
|
||||||
|
@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)
|
||||||
|
Rails.logger.debug 'Create user from message...'
|
||||||
|
Rails.logger.debug params.inspect
|
||||||
|
|
||||||
|
# do message_user lookup
|
||||||
|
message_user = user(params)
|
||||||
|
|
||||||
|
auth = Authorization.find_by(uid: message_user[:id], provider: 'telegram')
|
||||||
|
|
||||||
|
# create or update user
|
||||||
|
user_data = {
|
||||||
|
login: message_user[:username],
|
||||||
|
firstname: message_user[:first_name],
|
||||||
|
lastname: message_user[:last_name],
|
||||||
|
}
|
||||||
|
if auth
|
||||||
|
user = User.find(auth.user_id)
|
||||||
|
user.update_attributes(user_data)
|
||||||
|
else
|
||||||
|
user_data[:note] = "Telegram @#{message_user[:username]}"
|
||||||
|
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],
|
||||||
|
username: message_user[:username],
|
||||||
|
user_id: user.id,
|
||||||
|
provider: 'telegram'
|
||||||
|
}
|
||||||
|
if auth
|
||||||
|
auth.update_attributes(auth_data)
|
||||||
|
else
|
||||||
|
Authorization.create(auth_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ticket(params, user, group_id, channel)
|
||||||
|
UserInfo.current_user_id = user.id
|
||||||
|
|
||||||
|
Rails.logger.debug 'Create ticket from message...'
|
||||||
|
Rails.logger.debug params.inspect
|
||||||
|
Rails.logger.debug user.inspect
|
||||||
|
Rails.logger.debug group_id.inspect
|
||||||
|
|
||||||
|
# find ticket or create one
|
||||||
|
state_ids = Ticket::State.where(name: %w(closed merged removed)).pluck(:id)
|
||||||
|
ticket = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).order(:updated_at).first
|
||||||
|
if ticket
|
||||||
|
new_state = Ticket::State.find_by(name: 'new')
|
||||||
|
if ticket.state_id != new_state.id
|
||||||
|
ticket.state = Ticket::State.find_by(name: 'open')
|
||||||
|
end
|
||||||
|
ticket.save!
|
||||||
|
return ticket
|
||||||
|
end
|
||||||
|
|
||||||
|
# prepare title
|
||||||
|
title = params[:message][:text]
|
||||||
|
if title.length > 60
|
||||||
|
title = "#{title[0, 60]}..."
|
||||||
|
end
|
||||||
|
|
||||||
|
ticket = Ticket.new(
|
||||||
|
group_id: group_id,
|
||||||
|
title: title,
|
||||||
|
state_id: Ticket::State.find_by(name: 'new').id,
|
||||||
|
priority_id: Ticket::Priority.find_by(name: '2 normal').id,
|
||||||
|
customer_id: user.id,
|
||||||
|
preferences: {
|
||||||
|
channel_id: channel.id,
|
||||||
|
telegram: {
|
||||||
|
bid: params['bid'],
|
||||||
|
chat_id: params[:message][:chat][:id]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
ticket.save!
|
||||||
|
ticket
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_article(params, user, ticket, channel, article = nil)
|
||||||
|
|
||||||
|
if article
|
||||||
|
Rails.logger.debug 'Update article from message...'
|
||||||
|
else
|
||||||
|
Rails.logger.debug 'Create article from message...'
|
||||||
|
end
|
||||||
|
Rails.logger.debug params.inspect
|
||||||
|
Rails.logger.debug user.inspect
|
||||||
|
Rails.logger.debug ticket.inspect
|
||||||
|
|
||||||
|
UserInfo.current_user_id = user.id
|
||||||
|
|
||||||
|
if article
|
||||||
|
article.preferences[:edited_message] = {
|
||||||
|
message: {
|
||||||
|
created_at: params[:message][:date],
|
||||||
|
message_id: params[:message][:message_id],
|
||||||
|
from: params[:message][:from],
|
||||||
|
},
|
||||||
|
update_id: params[:update_id],
|
||||||
|
}
|
||||||
|
else
|
||||||
|
article = Ticket::Article.new(
|
||||||
|
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,
|
||||||
|
preferences: {
|
||||||
|
message: {
|
||||||
|
created_at: params[:message][:date],
|
||||||
|
message_id: params[:message][:message_id],
|
||||||
|
from: params[:message][:from],
|
||||||
|
},
|
||||||
|
update_id: params[:update_id],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# add article
|
||||||
|
if params[:message][:photo]
|
||||||
|
|
||||||
|
# find photo with best resolution for us
|
||||||
|
photo = nil
|
||||||
|
max_width = 650 * 2
|
||||||
|
last_width = 0
|
||||||
|
last_height = 0
|
||||||
|
params[:message][:photo].each { |file|
|
||||||
|
if !photo
|
||||||
|
photo = file
|
||||||
|
last_width = file['width'].to_i
|
||||||
|
last_height = file['height'].to_i
|
||||||
|
end
|
||||||
|
if file['width'].to_i < max_width && last_width < file['width'].to_i
|
||||||
|
photo = file
|
||||||
|
last_width = file['width'].to_i
|
||||||
|
last_height = file['height'].to_i
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if last_width > 650
|
||||||
|
last_width = (last_width / 2).to_i
|
||||||
|
last_height = (last_height / 2).to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
# download image
|
||||||
|
result = download_file(photo['file_id'])
|
||||||
|
if !result.success? || !result.body
|
||||||
|
raise "Unable for download image from telegram: #{result.code}"
|
||||||
|
end
|
||||||
|
body = "<img style=\"width:#{last_width}px;height:#{last_height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(result.body)}\">"
|
||||||
|
if params[:message][:caption]
|
||||||
|
body += "<br>#{params[:message][:caption].text2html}"
|
||||||
|
end
|
||||||
|
article.content_type = 'text/html'
|
||||||
|
article.body = body
|
||||||
|
article.save!
|
||||||
|
return article
|
||||||
|
end
|
||||||
|
|
||||||
|
# add document
|
||||||
|
if params[:message][:document]
|
||||||
|
thump = params[:message][:document][:thumb]
|
||||||
|
body = ' '
|
||||||
|
if thump
|
||||||
|
width = thump[:width]
|
||||||
|
height = thump[:height]
|
||||||
|
result = download_file(thump['file_id'])
|
||||||
|
if !result.success? || !result.body
|
||||||
|
raise "Unable for download image from telegram: #{result.code}"
|
||||||
|
end
|
||||||
|
body = "<img style=\"width:#{width}px;height:#{height}px;\" src=\"data:image/png;base64,#{Base64.strict_encode64(result.body)}\">"
|
||||||
|
end
|
||||||
|
document_result = download_file(params[:message][:document][:file_id])
|
||||||
|
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: params[:message][:document][:file_name],
|
||||||
|
preferences: {
|
||||||
|
'Mime-Type' => params[:message][:document][:mime_type],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return article
|
||||||
|
end
|
||||||
|
|
||||||
|
# voice
|
||||||
|
if params[:message][:voice]
|
||||||
|
body = ' '
|
||||||
|
if params[:message][:caption]
|
||||||
|
body = "<br>#{params[:message][:caption].text2html}"
|
||||||
|
end
|
||||||
|
document_result = download_file(params[:message][:voice][:file_id])
|
||||||
|
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: params[:message][:voice][:file_path] || 'audio',
|
||||||
|
preferences: {
|
||||||
|
'Mime-Type' => params[:message][:voice][:mime_type],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return article
|
||||||
|
end
|
||||||
|
|
||||||
|
# text
|
||||||
|
if params[:message][:text]
|
||||||
|
article.content_type = 'text/plain'
|
||||||
|
article.body = params[:message][:text]
|
||||||
|
article.save!
|
||||||
|
return article
|
||||||
|
end
|
||||||
|
raise 'invalid action'
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_group(params, group_id, channel)
|
||||||
|
Rails.logger.debug 'import message'
|
||||||
|
|
||||||
|
# prevent multible update
|
||||||
|
if !params[:edited_message]
|
||||||
|
return if Ticket::Article.find_by(message_id: Telegram.message_id(params))
|
||||||
|
end
|
||||||
|
|
||||||
|
# update article
|
||||||
|
if params[:edited_message]
|
||||||
|
article = Ticket::Article.find_by(message_id: Telegram.message_id(params))
|
||||||
|
return if !article
|
||||||
|
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]
|
||||||
|
if text.present? && text =~ /^\/start/
|
||||||
|
message(params[:message][:chat][:id], channel.options[:welcome] || 'You are welcome! Just ask me something!')
|
||||||
|
return
|
||||||
|
|
||||||
|
# find ticket and close it
|
||||||
|
elsif text.present? && text =~ /^\/end/
|
||||||
|
user = to_user(params)
|
||||||
|
ticket = Ticket.where(customer_id: user.id).order(:updated_at).first
|
||||||
|
ticket.state = Ticket::State.find_by(name: 'closed')
|
||||||
|
ticket.save!
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
ticket = nil
|
||||||
|
|
||||||
|
# use transaction
|
||||||
|
Transaction.execute(reset_user_id: true) do
|
||||||
|
user = to_user(params)
|
||||||
|
ticket = to_ticket(params, user, group_id, channel)
|
||||||
|
to_article(params, user, ticket, channel)
|
||||||
|
end
|
||||||
|
|
||||||
|
ticket
|
||||||
|
end
|
||||||
|
|
||||||
|
def from_article(article)
|
||||||
|
|
||||||
|
message = nil
|
||||||
|
Rails.logger.debug "Create telegram personal message from article to '#{article[:to]}'..."
|
||||||
|
|
||||||
|
message = {}
|
||||||
|
# TODO: create telegram message here
|
||||||
|
|
||||||
|
Rails.logger.debug message.inspect
|
||||||
|
message
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_state(channel, telegram_update, ticket = nil)
|
||||||
|
message = telegram_update['message']
|
||||||
|
message_user = user(message)
|
||||||
|
|
||||||
|
# no changes in post is from page user it self
|
||||||
|
if channel.options[:bot][:id].to_s == message_user[:id].to_s
|
||||||
|
if !ticket
|
||||||
|
return Ticket::State.find_by(name: 'closed') if !ticket
|
||||||
|
end
|
||||||
|
return ticket.state
|
||||||
|
end
|
||||||
|
|
||||||
|
state = Ticket::State.find_by(name: 'new')
|
||||||
|
return state if !ticket
|
||||||
|
return ticket.state if ticket.state.name == 'new'
|
||||||
|
Ticket::State.find_by(name: 'open')
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_file(file_id)
|
||||||
|
if Rails.env.test?
|
||||||
|
result = Result.new(
|
||||||
|
success: true,
|
||||||
|
body: 'ok',
|
||||||
|
data: 'ok',
|
||||||
|
code: 200,
|
||||||
|
content_type: 'application/stream',
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
document = @api.getFile(file_id)
|
||||||
|
url = "https://api.telegram.org/file/bot#{@token}/#{document['file_path']}"
|
||||||
|
UserAgent.get(
|
||||||
|
url,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
open_timeout: 20,
|
||||||
|
read_timeout: 40,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
class Result
|
||||||
|
|
||||||
|
attr_reader :error
|
||||||
|
attr_reader :body
|
||||||
|
attr_reader :data
|
||||||
|
attr_reader :code
|
||||||
|
attr_reader :content_type
|
||||||
|
|
||||||
|
def initialize(options)
|
||||||
|
@success = options[:success]
|
||||||
|
@body = options[:body]
|
||||||
|
@data = options[:data]
|
||||||
|
@code = options[:code]
|
||||||
|
@content_type = options[:content_type]
|
||||||
|
@error = options[:error]
|
||||||
|
end
|
||||||
|
|
||||||
|
def success?
|
||||||
|
return true if @success
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
68
test/controllers/channels_controller_test.rb
Normal file
68
test/controllers/channels_controller_test.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ChannelsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
|
||||||
|
# set accept header
|
||||||
|
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: %w(Admin Agent))
|
||||||
|
groups = Group.all
|
||||||
|
|
||||||
|
UserInfo.current_user_id = 1
|
||||||
|
@admin = User.create_or_update(
|
||||||
|
login: 'packages-admin',
|
||||||
|
firstname: 'Packages',
|
||||||
|
lastname: 'Admin',
|
||||||
|
email: 'packages-admin@example.com',
|
||||||
|
password: 'adminpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create agent
|
||||||
|
roles = Role.where(name: 'Agent')
|
||||||
|
@agent = User.create_or_update(
|
||||||
|
login: 'packages-agent@example.com',
|
||||||
|
firstname: 'Rest',
|
||||||
|
lastname: 'Agent',
|
||||||
|
email: 'packages-agent@example.com',
|
||||||
|
password: 'agentpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
)
|
||||||
|
|
||||||
|
# create customer without org
|
||||||
|
roles = Role.where(name: 'Customer')
|
||||||
|
@customer_without_org = User.create_or_update(
|
||||||
|
login: 'packages-customer1@example.com',
|
||||||
|
firstname: 'Packages',
|
||||||
|
lastname: 'Customer1',
|
||||||
|
email: 'packages-customer1@example.com',
|
||||||
|
password: 'customer1pw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test '01 telegram_webhook creates ticket' do
|
||||||
|
json = File.read('test/fixtures/telegram/personal_message_content.json')
|
||||||
|
post '/api/v1/channels/telegram_webhook', json, @headers
|
||||||
|
puts JSON.parse(@response.body).inspect
|
||||||
|
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal({ 'ok' => 'ok' }, result)
|
||||||
|
end
|
||||||
|
|
||||||
|
test '0x telegram_webhook with existing ticket adds ticket_article'
|
||||||
|
test '0x telegram_webhook sends welcome message on /start'
|
||||||
|
test '0x telegram_webhook closes the ticket on /stop'
|
||||||
|
end
|
21
test/fixtures/telegram/personal1_message_content1.json
vendored
Normal file
21
test/fixtures/telegram/personal1_message_content1.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":10001,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":1365,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"Hello, I need your Help"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal1_message_content2.json
vendored
Normal file
21
test/fixtures/telegram/personal1_message_content2.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":10002,
|
||||||
|
"message":{
|
||||||
|
"date":1441645535,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":1366,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"Hello, I need your Help 2"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal1_message_end.json
vendored
Normal file
21
test/fixtures/telegram/personal1_message_end.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":10003,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":1367,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"/end"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal1_message_start.json
vendored
Normal file
21
test/fixtures/telegram/personal1_message_start.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":10000,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":1365,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"/start"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal2_message_content1.json
vendored
Normal file
21
test/fixtures/telegram/personal2_message_content1.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":20001,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":2365,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"Can you help me with my feature?"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal2_message_content2.json
vendored
Normal file
21
test/fixtures/telegram/personal2_message_content2.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":20002,
|
||||||
|
"message":{
|
||||||
|
"date":1441645536,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":2366,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"Yes of course! <b>lalal</b>"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal2_message_start.json
vendored
Normal file
21
test/fixtures/telegram/personal2_message_start.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":20000,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"message_id":2364,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname",
|
||||||
|
"id":1111111,
|
||||||
|
"first_name":"Test Firstname",
|
||||||
|
"username":"Testusername"
|
||||||
|
},
|
||||||
|
"text":"/start"
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal3_message_content1.json
vendored
Normal file
21
test/fixtures/telegram/personal3_message_content1.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":30001,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"message_id":3365,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"text":"Can you help me with my feature?"
|
||||||
|
}
|
||||||
|
}
|
42
test/fixtures/telegram/personal3_message_content2.json
vendored
Normal file
42
test/fixtures/telegram/personal3_message_content2.json
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"update_id": 30002,
|
||||||
|
"message": {
|
||||||
|
"message_id": 3366,
|
||||||
|
"from": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"chat": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2",
|
||||||
|
"type": "private"
|
||||||
|
},
|
||||||
|
"date": 1486036832,
|
||||||
|
"photo": [
|
||||||
|
{
|
||||||
|
"file_id": "ABC-123VabcOcv123w0ABBL_aoY-F849YYABC",
|
||||||
|
"file_size": 1016,
|
||||||
|
"width": 90,
|
||||||
|
"height": 82
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file_id": "ABC-123VabcOcv123w0ABPlhIiVSfO9TYoABC",
|
||||||
|
"file_size": 7378,
|
||||||
|
"width": 320,
|
||||||
|
"height": 291
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file_id": "ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC",
|
||||||
|
"file_size": 16433,
|
||||||
|
"width": 720,
|
||||||
|
"height": 654
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"caption": "caption 123<b>abc</b>"
|
||||||
|
}
|
||||||
|
}
|
33
test/fixtures/telegram/personal3_message_content3.json
vendored
Normal file
33
test/fixtures/telegram/personal3_message_content3.json
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"update_id": 30003,
|
||||||
|
"message": {
|
||||||
|
"message_id": 3367,
|
||||||
|
"from": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"chat": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2",
|
||||||
|
"type": "private"
|
||||||
|
},
|
||||||
|
"date": 1486036832,
|
||||||
|
"document": {
|
||||||
|
"file_name": "blockposter-162412.pdf",
|
||||||
|
"mime_type": "application/pdf",
|
||||||
|
"thumb": {
|
||||||
|
"file_id": "AAQCABO0I4INAATATQAB5HWPq4XgxQACAg",
|
||||||
|
"file_size": 8752,
|
||||||
|
"width": 200,
|
||||||
|
"height": 200
|
||||||
|
},
|
||||||
|
"file_id": "BQADAgADDgAD7x6ZSC_-1LMkOEmoAg",
|
||||||
|
"file_size": 3622849
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
test/fixtures/telegram/personal3_message_content4.json
vendored
Normal file
22
test/fixtures/telegram/personal3_message_content4.json
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"update_id":30004,
|
||||||
|
"edited_message": {
|
||||||
|
"message_id":3365,
|
||||||
|
"from": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"chat": {
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"date": 1487116688,
|
||||||
|
"edit_date": 1487116889,
|
||||||
|
"text": "UPDATE: 1231444"
|
||||||
|
}
|
||||||
|
}
|
26
test/fixtures/telegram/personal3_message_content5.json
vendored
Normal file
26
test/fixtures/telegram/personal3_message_content5.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"update_id":30005,
|
||||||
|
"message":{
|
||||||
|
"message_id":3368,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"date":1487119496,
|
||||||
|
"voice":{
|
||||||
|
"duration":1,
|
||||||
|
"mime_type":"audio/ogg",
|
||||||
|
"file_id":"AwADAgADVQADCEIYSZwyOmSZK9iZAg",
|
||||||
|
"file_size":6030
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
test/fixtures/telegram/personal3_message_start.json
vendored
Normal file
21
test/fixtures/telegram/personal3_message_start.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"update_id":30000,
|
||||||
|
"message":{
|
||||||
|
"date":1441645532,
|
||||||
|
"chat":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"type": "private",
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"message_id":3364,
|
||||||
|
"from":{
|
||||||
|
"last_name":"Test Lastname2",
|
||||||
|
"id":1111112,
|
||||||
|
"first_name":"Test Firstname2",
|
||||||
|
"username":"Testusername2"
|
||||||
|
},
|
||||||
|
"text":"/start start"
|
||||||
|
}
|
||||||
|
}
|
196
test/integration/telegram_controller_test.rb
Normal file
196
test/integration/telegram_controller_test.rb
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
class TelegramControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||||
|
|
||||||
|
# configure telegram channel
|
||||||
|
token = ENV['TELEGRAM_TOKEN']
|
||||||
|
group_id = Group.find_by(name: 'Users').id
|
||||||
|
#bot = Telegram.check_token(token)
|
||||||
|
#Setting.set('http_type', 'http')
|
||||||
|
Setting.set('http_type', 'https')
|
||||||
|
Setting.set('fqdn', 'me.zammad.com')
|
||||||
|
Channel.where(area: 'Telegram::Bot').destroy_all
|
||||||
|
@channel = Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' })
|
||||||
|
|
||||||
|
groups = Group.where(name: 'Users')
|
||||||
|
roles = Role.where(name: %w(Agent))
|
||||||
|
agent = User.create_or_update(
|
||||||
|
login: 'telegram-agent@example.com',
|
||||||
|
firstname: 'E',
|
||||||
|
lastname: 'S',
|
||||||
|
email: 'telegram-agent@example.com',
|
||||||
|
password: 'agentpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'basic call' do
|
||||||
|
Ticket.destroy_all
|
||||||
|
|
||||||
|
# start communication #1
|
||||||
|
post '/api/v1/channels/telegram_webhook', read_messaage('personal1_message_start'), @headers
|
||||||
|
assert_response(404)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
|
||||||
|
post '/api/v1/channels_telegram_webhook/not_existing', read_messaage('personal1_message_start'), @headers
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal('bot param missing', result['error'])
|
||||||
|
|
||||||
|
callback_url = "/api/v1/channels_telegram_webhook/not_existing?bid=#{@channel.options[:bot][:id]}"
|
||||||
|
post callback_url, read_messaage('personal1_message_start'), @headers
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal('invalid callback token', result['error'])
|
||||||
|
|
||||||
|
callback_url = "/api/v1/channels_telegram_webhook/#{@channel.options[:callback_token]}?bid=#{@channel.options[:bot][:id]}"
|
||||||
|
post callback_url, read_messaage('personal1_message_start'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
# send message1
|
||||||
|
post callback_url, read_messaage('personal1_message_content1'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(1, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Hello, I need your Help', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal('Hello, I need your Help', ticket.articles.first.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.first.content_type)
|
||||||
|
|
||||||
|
# send same message again, ignore it
|
||||||
|
post callback_url, read_messaage('personal1_message_content1'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Hello, I need your Help', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal('Hello, I need your Help', ticket.articles.first.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.first.content_type)
|
||||||
|
|
||||||
|
# send message2
|
||||||
|
post callback_url, read_messaage('personal1_message_content2'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Hello, I need your Help', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_equal('Hello, I need your Help 2', ticket.articles.last.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.last.content_type)
|
||||||
|
|
||||||
|
# send end message
|
||||||
|
post callback_url, read_messaage('personal1_message_end'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Hello, I need your Help', ticket.title)
|
||||||
|
assert_equal('closed', ticket.state.name)
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_equal('Hello, I need your Help 2', ticket.articles.last.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.last.content_type)
|
||||||
|
|
||||||
|
# start communication #2
|
||||||
|
post callback_url, read_messaage('personal2_message_start'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
# send message1
|
||||||
|
post callback_url, read_messaage('personal2_message_content1'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(2, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.articles.first.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.first.content_type)
|
||||||
|
|
||||||
|
# send message2
|
||||||
|
post callback_url, read_messaage('personal2_message_content2'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(2, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_equal('Yes of course! <b>lalal</b>', ticket.articles.last.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.last.content_type)
|
||||||
|
|
||||||
|
# start communication #3
|
||||||
|
post callback_url, read_messaage('personal3_message_start'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
# send message1
|
||||||
|
post callback_url, read_messaage('personal3_message_content1'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(3, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(1, ticket.articles.count)
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.articles.last.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.last.content_type)
|
||||||
|
|
||||||
|
# send message2
|
||||||
|
post callback_url, read_messaage('personal3_message_content2'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(3, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(2, ticket.articles.count)
|
||||||
|
assert_match(/<img style="width:360px;height:327px;"/i, ticket.articles.last.body)
|
||||||
|
assert_equal('text/html', ticket.articles.last.content_type)
|
||||||
|
|
||||||
|
# send message3
|
||||||
|
post callback_url, read_messaage('personal3_message_content3'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(3, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(3, ticket.articles.count)
|
||||||
|
assert_match(/<img style="width:200px;height:200px;"/i, ticket.articles.last.body)
|
||||||
|
assert_equal('text/html', ticket.articles.last.content_type)
|
||||||
|
assert_equal(1, ticket.articles.last.attachments.count)
|
||||||
|
|
||||||
|
# update message1
|
||||||
|
post callback_url, read_messaage('personal3_message_content4'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(3, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(3, ticket.articles.count)
|
||||||
|
assert_match(/<img style="width:200px;height:200px;"/i, ticket.articles.last.body)
|
||||||
|
assert_equal('text/html', ticket.articles.last.content_type)
|
||||||
|
assert_equal(1, ticket.articles.last.attachments.count)
|
||||||
|
|
||||||
|
assert_equal('UPDATE: 1231444', ticket.articles.first.body)
|
||||||
|
assert_equal('text/plain', ticket.articles.first.content_type)
|
||||||
|
|
||||||
|
# send voice5
|
||||||
|
post callback_url, read_messaage('personal3_message_content5'), @headers
|
||||||
|
assert_response(200)
|
||||||
|
assert_equal(3, Ticket.count)
|
||||||
|
ticket = Ticket.last
|
||||||
|
assert_equal('Can you help me with my feature?', ticket.title)
|
||||||
|
assert_equal('new', ticket.state.name)
|
||||||
|
assert_equal(4, ticket.articles.count)
|
||||||
|
#assert_match(/ /i, ticket.articles.last.body)
|
||||||
|
assert_equal('text/html', ticket.articles.last.content_type)
|
||||||
|
assert_equal(1, ticket.articles.last.attachments.count)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_messaage(file)
|
||||||
|
File.read("test/fixtures/telegram/#{file}.json")
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue