Rewrite of channel api.
This commit is contained in:
parent
89546a09a2
commit
6a733396f9
38 changed files with 1570 additions and 613 deletions
|
@ -7,19 +7,9 @@ class App.ChannelEmail extends App.ControllerTabs
|
|||
|
||||
@tabs = [
|
||||
{
|
||||
name: 'Inbound',
|
||||
target: 'c-inbound',
|
||||
controller: App.ChannelEmailInbound,
|
||||
},
|
||||
{
|
||||
name: 'Outbound',
|
||||
target: 'c-outbound',
|
||||
controller: App.ChannelEmailOutbound,
|
||||
},
|
||||
{
|
||||
name: 'Adresses',
|
||||
target: 'c-address',
|
||||
controller: App.ChannelEmailAddress,
|
||||
name: 'Email Accounts',
|
||||
target: 'c-channel',
|
||||
controller: App.ChannelEmailAccountOverview,
|
||||
},
|
||||
{
|
||||
name: 'Signatures',
|
||||
|
@ -132,100 +122,6 @@ class App.ChannelEmailFilterEdit extends App.ControllerModal
|
|||
@hide()
|
||||
)
|
||||
|
||||
|
||||
class App.ChannelEmailAddress extends App.Controller
|
||||
events:
|
||||
'click [data-type=new]': 'new'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
App.EmailAddress.subscribe( @render, initFetch: true )
|
||||
|
||||
render: =>
|
||||
data = App.EmailAddress.search( sortBy: 'realname' )
|
||||
|
||||
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn--success">' + App.i18n.translateContent('New') + '</a></div>' )
|
||||
|
||||
new App.ControllerTable(
|
||||
el: template.find('.overview')
|
||||
model: App.EmailAddress
|
||||
objects: data
|
||||
bindRow:
|
||||
events:
|
||||
'click': @edit
|
||||
)
|
||||
|
||||
@html template
|
||||
|
||||
new: (e) =>
|
||||
e.preventDefault()
|
||||
new App.ChannelEmailAddressEdit(
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
edit: (id, e) =>
|
||||
e.preventDefault()
|
||||
item = App.EmailAddress.find(id)
|
||||
new App.ChannelEmailAddressEdit(
|
||||
object: item
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
class App.ChannelEmailAddressEdit extends App.ControllerModal
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@head = 'Email-Address'
|
||||
@button = true
|
||||
@close = true
|
||||
@cancel = true
|
||||
|
||||
if @object
|
||||
@form = new App.ControllerForm(
|
||||
model: App.EmailAddress
|
||||
params: @object
|
||||
autofocus: true
|
||||
)
|
||||
else
|
||||
@form = new App.ControllerForm(
|
||||
model: App.EmailAddress,
|
||||
autofocus: true,
|
||||
)
|
||||
|
||||
@content = @form.form
|
||||
|
||||
@show()
|
||||
|
||||
onSubmit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
|
||||
object = @object || new App.EmailAddress
|
||||
object.load(params)
|
||||
|
||||
# validate form
|
||||
errors = @form.validate( params )
|
||||
|
||||
# show errors in form
|
||||
if errors
|
||||
@log 'error', errors
|
||||
@formValidate( form: e.target, errors: errors )
|
||||
return false
|
||||
|
||||
# disable form
|
||||
@formDisable(e)
|
||||
|
||||
# save object
|
||||
object.save(
|
||||
done: =>
|
||||
@hide()
|
||||
fail: =>
|
||||
@hide()
|
||||
)
|
||||
|
||||
class App.ChannelEmailSignature extends App.Controller
|
||||
events:
|
||||
'click [data-type=new]': 'new'
|
||||
|
@ -317,193 +213,575 @@ class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
|||
@hide()
|
||||
)
|
||||
|
||||
class App.ChannelEmailInbound extends App.Controller
|
||||
class App.ChannelEmailAccountOverview extends App.Controller
|
||||
events:
|
||||
'click [data-type=new]': 'new'
|
||||
'click [data-type="new"]': 'wizard'
|
||||
'click [data-type="delete"]': 'delete'
|
||||
'click [data-type="edit-inbound"]': 'edit_inbound'
|
||||
'click [data-type="edit-outbound"]': 'edit_outbound'
|
||||
'click [data-type="email-address-new"]': 'email_address_new'
|
||||
'click [data-type="email-address-edit"]': 'email_address_edit'
|
||||
'click [data-type="edit-notification-outbound"]': 'edit_notification_outbound'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
App.Channel.subscribe( @render, initFetch: true )
|
||||
@interval(@load, 20000)
|
||||
|
||||
render: =>
|
||||
channels = App.Channel.search( filter: { area: 'Email::Inbound' } )
|
||||
load: =>
|
||||
@ajax(
|
||||
id: 'email_index'
|
||||
type: 'GET'
|
||||
url: @apiPath + '/channels/email_index'
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn--success">' + App.i18n.translateContent('New') + '</a></div>' )
|
||||
# load assets
|
||||
App.Collection.loadAssets( data.assets )
|
||||
|
||||
new App.ControllerTable(
|
||||
el: template.find('.overview')
|
||||
model: App.Channel
|
||||
objects: channels
|
||||
bindRow:
|
||||
events:
|
||||
'click': @edit
|
||||
@render()
|
||||
)
|
||||
@html template
|
||||
|
||||
new: (e) =>
|
||||
e.preventDefault()
|
||||
new App.ChannelEmailInboundEdit(
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
edit: (id, e) =>
|
||||
e.preventDefault()
|
||||
item = App.Channel.find(id)
|
||||
new App.ChannelEmailInboundEdit(
|
||||
object: item
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
|
||||
class App.ChannelEmailInboundEdit extends App.ControllerModal
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@head = 'Email Channel'
|
||||
@button = true
|
||||
@close = true
|
||||
@cancel = true
|
||||
|
||||
if @object
|
||||
@form = new App.ControllerForm(
|
||||
model: App.Channel
|
||||
params: @object
|
||||
autofocus: true
|
||||
)
|
||||
else
|
||||
@form = new App.ControllerForm(
|
||||
model: App.Channel
|
||||
autofocus: true
|
||||
)
|
||||
|
||||
@content = @form.form
|
||||
|
||||
@show()
|
||||
|
||||
onSubmit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
params['area'] = 'Email::Inbound'
|
||||
|
||||
object = @object || new App.Channel
|
||||
object.load(params)
|
||||
|
||||
# validate form
|
||||
errors = @form.validate( params )
|
||||
|
||||
# show errors in form
|
||||
if errors
|
||||
@log 'error', errors
|
||||
@formValidate( form: e.target, errors: errors )
|
||||
return false
|
||||
|
||||
# disable form
|
||||
@formDisable(e)
|
||||
|
||||
# save object
|
||||
object.save(
|
||||
done: =>
|
||||
@hide()
|
||||
fail: =>
|
||||
@hide()
|
||||
)
|
||||
|
||||
class App.ChannelEmailOutbound extends App.Controller
|
||||
events:
|
||||
'change [name="adapter"]': 'toggle'
|
||||
'submit #mail_adapter': 'update'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
App.Channel.subscribe( @render, initFetch: true )
|
||||
|
||||
render: =>
|
||||
|
||||
@html App.view('channel/email_outbound')()
|
||||
|
||||
# get current Email::Outbound channel
|
||||
channels = App.Channel.all()
|
||||
adapters = {}
|
||||
adapter_used = undefined
|
||||
channel_used = undefined
|
||||
# get channels
|
||||
channels = App.Channel.search( filter: { area: 'Email::Account' } )
|
||||
for channel in channels
|
||||
if channel.area is 'Email::Outbound'
|
||||
email_addresses = App.EmailAddress.search( filter: { channel_id: channel.id } )
|
||||
channel.email_addresses = email_addresses
|
||||
|
||||
adapters[channel.adapter] = channel.adapter
|
||||
if @adapter_used
|
||||
if @adapter_used is channel.adapter
|
||||
adapter_used = channel.adapter
|
||||
channel_used = channel
|
||||
else if channel.active is true
|
||||
adapter_used = channel.adapter
|
||||
channel_used = channel
|
||||
# get all unlinked email addresses
|
||||
email_addresses_all = App.EmailAddress.all()
|
||||
email_addresses_not_used = []
|
||||
for email_address in email_addresses_all
|
||||
if !email_address.channel_id || !App.Channel.exists(email_address.channel_id)
|
||||
email_addresses_not_used.push email_address
|
||||
|
||||
configure_attributes = [
|
||||
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , default: adapter_used },
|
||||
# get channels
|
||||
channel = App.Channel.search( filter: { area: 'Email::Notification', active: true } )[0]
|
||||
|
||||
@html App.view('channel/email_account_overview')(
|
||||
channels: channels
|
||||
email_addresses_not_used: email_addresses_not_used
|
||||
channel: channel
|
||||
)
|
||||
|
||||
wizard: (e) =>
|
||||
e.preventDefault()
|
||||
new App.ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
callback: @load
|
||||
)
|
||||
|
||||
edit_inbound: (e) =>
|
||||
e.preventDefault()
|
||||
id = $(e.target).closest('tr').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-inbound'
|
||||
new App.ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
slide: slide
|
||||
channel: channel
|
||||
callback: @load
|
||||
)
|
||||
|
||||
edit_outbound: (e) =>
|
||||
e.preventDefault()
|
||||
id = $(e.target).closest('tr').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-outbound'
|
||||
new App.ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
slide: slide
|
||||
channel: channel
|
||||
callback: @load
|
||||
)
|
||||
|
||||
delete: (e) =>
|
||||
e.preventDefault()
|
||||
id = $(e.target).closest('tr').data('id')
|
||||
item = App.Channel.find(id)
|
||||
new App.ControllerGenericDestroyConfirm(
|
||||
item: item
|
||||
container: @el.closest('.content')
|
||||
callback: @load
|
||||
)
|
||||
|
||||
email_address_new: (e) =>
|
||||
e.preventDefault()
|
||||
channel_id = $(e.target).closest('tr').data('id')
|
||||
new App.ControllerGenericNew(
|
||||
pageData:
|
||||
object: 'Email Address'
|
||||
genericObject: 'EmailAddress'
|
||||
container: @el.closest('.content')
|
||||
item:
|
||||
channel_id: channel_id
|
||||
callback: @load
|
||||
)
|
||||
|
||||
email_address_edit: (e) =>
|
||||
e.preventDefault()
|
||||
id = $(e.target).closest('li').data('id')
|
||||
new App.ControllerGenericEdit(
|
||||
pageData:
|
||||
object: 'Email Address'
|
||||
genericObject: 'EmailAddress'
|
||||
container: @el.closest('.content')
|
||||
id: id
|
||||
callback: @load
|
||||
)
|
||||
|
||||
edit_notification_outbound: (e) =>
|
||||
e.preventDefault()
|
||||
id = $(e.target).closest('tr').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-outbound'
|
||||
new App.ChannelEmailNotificationWizard(
|
||||
container: @el.closest('.content')
|
||||
channel: channel
|
||||
callback: @load
|
||||
)
|
||||
|
||||
class App.ChannelEmailAccountWizard extends App.Controller
|
||||
elements:
|
||||
'.modal-body': 'body'
|
||||
|
||||
className: 'modal fade'
|
||||
|
||||
events:
|
||||
'submit .js-intro': 'probeBasedOnIntro'
|
||||
'submit .js-inbound': 'probeInbound'
|
||||
'change .js-outbound [name=adapter]': 'toggleOutboundAdapter'
|
||||
'submit .js-outbound': 'probleOutbound'
|
||||
'click .js-back': 'goToSlide'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# store account settings
|
||||
@account =
|
||||
inbound:
|
||||
adapter: undefined
|
||||
options: undefined
|
||||
outbound:
|
||||
adapter: undefined
|
||||
options: undefined
|
||||
meta: {}
|
||||
|
||||
if @channel
|
||||
@account =
|
||||
inbound: @channel.options.inbound
|
||||
outbound: @channel.options.outbound
|
||||
meta: {}
|
||||
|
||||
if @container
|
||||
@el.addClass('modal--local')
|
||||
|
||||
@render()
|
||||
|
||||
@el.modal
|
||||
keyboard: true
|
||||
show: true
|
||||
backdrop: true
|
||||
container: @container
|
||||
.on
|
||||
'show.bs.modal': @onShow
|
||||
'shown.bs.modal': @onComplete
|
||||
'hidden.bs.modal': =>
|
||||
if @callback
|
||||
@callback()
|
||||
$('.modal').remove()
|
||||
|
||||
if @slide
|
||||
@showSlide(@slide)
|
||||
|
||||
render: =>
|
||||
@html App.view('channel/email_account_wizard')()
|
||||
@showSlide('js-intro')
|
||||
|
||||
# outbound
|
||||
adapters =
|
||||
sendmail: 'Local MTA (Sendmail/Postfix/Exim/...) - use server setup'
|
||||
smtp: 'SMTP - configure your own outgoing SMTP settings'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @el.find('#form-email-adapter'),
|
||||
model: { configure_attributes: configure_attributes, className: '' },
|
||||
autofocus: true,
|
||||
el: @$('.base-outbound-type')
|
||||
model:
|
||||
configure_attributes: configureAttributesOutbound
|
||||
className: ''
|
||||
params:
|
||||
adapter: @account.outbound.adapter || 'sendmail'
|
||||
)
|
||||
@toggleOutboundAdapter()
|
||||
|
||||
# inbound
|
||||
configureAttributesInbound = [
|
||||
{ name: 'adapter', display: 'Type', tag: 'select', multiple: false, null: false, options: { imap: 'IMAP', pop3: 'POP3' } },
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, single: true },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-inbound-settings'),
|
||||
model:
|
||||
configure_attributes: configureAttributesInbound
|
||||
className: ''
|
||||
params: @account.inbound
|
||||
)
|
||||
|
||||
# if adapter_used is 'Sendmail'
|
||||
# # some form
|
||||
toggleOutboundAdapter: =>
|
||||
|
||||
if adapter_used is 'SMTP'
|
||||
configure_attributes = [
|
||||
{ name: 'host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['host']) },
|
||||
{ name: 'user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['user']) },
|
||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['password']) },
|
||||
{ name: 'ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , translate: true, default: (channel_used['options']&&channel_used['options']['ssl']) },
|
||||
{ name: 'port', display: 'Port', tag: 'input', type: 'text', limit: 5, null: false, class: 'span1', autocapitalize: false, default: ((channel_used['options']&&channel_used['options']['port']) || 25) },
|
||||
# fill user / password based on intro info
|
||||
channel_used = { options: {} }
|
||||
if @account['meta']
|
||||
channel_used['options']['user'] = @account['meta']['email']
|
||||
channel_used['options']['password'] = @account['meta']['password']
|
||||
|
||||
# show used backend
|
||||
@el.find('.base-outbound-settings').html('')
|
||||
adapter = @$('.js-outbound [name=adapter]').val()
|
||||
if adapter is 'smtp'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autofocus: true },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false, single: true },
|
||||
]
|
||||
@form = new App.ControllerForm(
|
||||
el: @el.find('#form-email-adapter-settings'),
|
||||
model: { configure_attributes: configure_attributes, className: '' },
|
||||
autofocus: true,
|
||||
el: @$('.base-outbound-settings')
|
||||
model:
|
||||
configure_attributes: configureAttributesOutbound
|
||||
className: ''
|
||||
params: @account.outbound
|
||||
)
|
||||
|
||||
toggle: (e) =>
|
||||
probeBasedOnIntro: (e) =>
|
||||
e.preventDefault()
|
||||
params = @formParam(e.target)
|
||||
|
||||
# remember account settings
|
||||
@account.meta = params
|
||||
|
||||
# let backend know about the channel
|
||||
if @channel
|
||||
params.channel_id = @channel.id
|
||||
|
||||
@disable(e)
|
||||
@$('.js-probe .js-email').text( params.email )
|
||||
@showSlide('js-probe')
|
||||
|
||||
@ajax(
|
||||
id: 'email_probe'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_probe'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
if data.setting
|
||||
for key, value of data.setting
|
||||
@account[key] = value
|
||||
@verify(@account)
|
||||
else if data.result is 'duplicate'
|
||||
@showSlide('js-intro')
|
||||
@showAlert('js-intro', 'Account already exists!' )
|
||||
else
|
||||
@showSlide('js-inbound')
|
||||
@showAlert('js-inbound', 'Unable to detect your server settings. Manual configuration needed.' )
|
||||
@$('.js-inbound [name="options::user"]').val( @account['meta']['email'] )
|
||||
@$('.js-inbound [name="options::password"]').val( @account['meta']['password'] )
|
||||
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
@showSlide('js-intro')
|
||||
)
|
||||
|
||||
probeInbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
|
||||
# render page with new selected adapter
|
||||
if @adapter_used isnt params['adapter']
|
||||
# let backend know about the channel
|
||||
params.channel_id = @channel.id
|
||||
|
||||
# set selected adapter
|
||||
@adapter_used = params['adapter']
|
||||
@disable(e)
|
||||
|
||||
@render()
|
||||
@showSlide('js-test')
|
||||
|
||||
update: (e) =>
|
||||
@ajax(
|
||||
id: 'email_inbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_inbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
|
||||
# remember account settings
|
||||
@account.inbound = params
|
||||
|
||||
@showSlide('js-outbound')
|
||||
if !@channel
|
||||
@$('.js-outbound [name="options::user"]').val( @account['meta']['email'] )
|
||||
@$('.js-outbound [name="options::password"]').val( @account['meta']['password'] )
|
||||
|
||||
else
|
||||
@showSlide('js-inbound')
|
||||
@showAlert('js-inbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@showSlide('js-inbound')
|
||||
@showAlert('js-inbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
probleOutbound: (e) =>
|
||||
e.preventDefault()
|
||||
params = @formParam(e.target)
|
||||
|
||||
# errors = @form.validate( params )
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
params['email'] = @account['meta']['email']
|
||||
|
||||
# update Email::Outbound adapter
|
||||
channels = App.Channel.all()
|
||||
for channel in channels
|
||||
if channel.area is 'Email::Outbound' && channel.adapter is params['adapter']
|
||||
channel.updateAttributes(
|
||||
options: {
|
||||
host: params['host'],
|
||||
user: params['user'],
|
||||
password: params['password'],
|
||||
ssl: params['ssl'],
|
||||
port: params['port'],
|
||||
},
|
||||
active: true,
|
||||
)
|
||||
if !params['email'] && @channel
|
||||
email_addresses = App.EmailAddress.search( filter: { channel_id: @channel.id } )
|
||||
if email_addresses && email_addresses[0]
|
||||
params['email'] = email_addresses[0].email
|
||||
|
||||
# set all other Email::Outbound adapters to inactive
|
||||
channels = App.Channel.all()
|
||||
for channel in channels
|
||||
if channel.area is 'Email::Outbound' && channel.adapter isnt params['adapter']
|
||||
channel.updateAttributes( active: false )
|
||||
# let backend know about the channel
|
||||
params.channel_id = @channel.id
|
||||
|
||||
@disable(e)
|
||||
|
||||
@showSlide('js-test')
|
||||
|
||||
@ajax(
|
||||
id: 'email_outbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_outbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
|
||||
# remember account settings
|
||||
@account.outbound = params
|
||||
|
||||
@verify(@account)
|
||||
else
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
verify: (account, count = 0) =>
|
||||
@showSlide('js-verify')
|
||||
|
||||
# let backend know about the channel
|
||||
if @channel
|
||||
account.channel_id = @channel.id
|
||||
|
||||
if !account.email && @channel
|
||||
email_addresses = App.EmailAddress.search( filter: { channel_id: @channel.id } )
|
||||
if email_addresses && email_addresses[0]
|
||||
account.email = email_addresses[0].email
|
||||
|
||||
@ajax(
|
||||
id: 'email_verify'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_verify'
|
||||
data: JSON.stringify( account )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@el.remove()
|
||||
else
|
||||
if count is 2
|
||||
@showAlert('js-verify', data.message_human || data.message )
|
||||
@delay(
|
||||
=>
|
||||
@showSlide('js-intro')
|
||||
@showAlert('js-intro', 'Unable to verify sending and receiving. Please check your settings.' )
|
||||
|
||||
2300
|
||||
)
|
||||
else
|
||||
if data.subject && @account
|
||||
@account.subject = data.subject
|
||||
@verify( @account, count + 1 )
|
||||
fail: =>
|
||||
@showSlide('js-intro')
|
||||
@showAlert('js-intro', 'Unable to verify sending and receiving. Please check your settings.' )
|
||||
)
|
||||
|
||||
goToSlide: (e) =>
|
||||
e.preventDefault()
|
||||
slide = $(e.target).data('slide')
|
||||
@showSlide(slide)
|
||||
|
||||
showSlide: (name) =>
|
||||
@hideAlert(name)
|
||||
@$('.setup.wizard').addClass('hide')
|
||||
@$(".setup.wizard.#{name}").removeClass('hide')
|
||||
@$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus()
|
||||
|
||||
showAlert: (screen, message) =>
|
||||
@$(".#{screen}").find('.alert').removeClass('hide').text( App.i18n.translateInline( message ) )
|
||||
|
||||
hideAlert: (screen) =>
|
||||
@$(".#{screen}").find('.alert').addClass('hide')
|
||||
|
||||
disable: (e) =>
|
||||
@formDisable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', true)
|
||||
|
||||
enable: (e) =>
|
||||
@formEnable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', false)
|
||||
|
||||
class App.ChannelEmailNotificationWizard extends App.Controller
|
||||
elements:
|
||||
'.modal-body': 'body'
|
||||
|
||||
className: 'modal fade'
|
||||
|
||||
events:
|
||||
'change .js-outbound [name=adapter]': 'toggleOutboundAdapter'
|
||||
'submit .js-outbound': 'probleOutbound'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# store account settings
|
||||
@account =
|
||||
inbound:
|
||||
adapter: undefined
|
||||
options: undefined
|
||||
outbound:
|
||||
adapter: undefined
|
||||
options: undefined
|
||||
meta: {}
|
||||
|
||||
if @channel
|
||||
@account =
|
||||
inbound: @channel.options.inbound
|
||||
outbound: @channel.options.outbound
|
||||
|
||||
if @container
|
||||
@el.addClass('modal--local')
|
||||
|
||||
@render()
|
||||
|
||||
@el.modal
|
||||
keyboard: true
|
||||
show: true
|
||||
backdrop: true
|
||||
container: @container
|
||||
.on
|
||||
'show.bs.modal': @onShow
|
||||
'shown.bs.modal': @onComplete
|
||||
'hidden.bs.modal': =>
|
||||
if @callback
|
||||
@callback()
|
||||
$('.modal').remove()
|
||||
|
||||
if @slide
|
||||
@showSlide(@slide)
|
||||
|
||||
render: =>
|
||||
@html App.view('channel/email_notification_wizard')()
|
||||
@showSlide('js-outbound')
|
||||
|
||||
# outbound
|
||||
adapters =
|
||||
sendmail: 'Local MTA (Sendmail/Postfix/Exim/...) - use server setup'
|
||||
smtp: 'SMTP - configure your own outgoing SMTP settings'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-outbound-type')
|
||||
model:
|
||||
configure_attributes: configureAttributesOutbound
|
||||
className: ''
|
||||
params:
|
||||
adapter: @account.outbound.adapter || 'sendmail'
|
||||
)
|
||||
@toggleOutboundAdapter()
|
||||
|
||||
toggleOutboundAdapter: =>
|
||||
|
||||
# show used backend
|
||||
@el.find('.base-outbound-settings').html('')
|
||||
adapter = @$('.js-outbound [name=adapter]').val()
|
||||
if adapter is 'smtp'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autofocus: true },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false, single: true },
|
||||
]
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.base-outbound-settings')
|
||||
model:
|
||||
configure_attributes: configureAttributesOutbound
|
||||
className: ''
|
||||
params: @account.outbound
|
||||
)
|
||||
|
||||
probleOutbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
|
||||
# let backend know about the channel
|
||||
params.channel_id = @channel.id
|
||||
|
||||
@disable(e)
|
||||
|
||||
@showSlide('js-test')
|
||||
|
||||
@ajax(
|
||||
id: 'email_outbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_notification'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@el.remove()
|
||||
else
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
showSlide: (name) =>
|
||||
@hideAlert(name)
|
||||
@$('.setup.wizard').addClass('hide')
|
||||
@$(".setup.wizard.#{name}").removeClass('hide')
|
||||
@$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus()
|
||||
|
||||
showAlert: (screen, message) =>
|
||||
@$(".#{screen}").find('.alert').removeClass('hide').text( App.i18n.translateInline( message ) )
|
||||
|
||||
hideAlert: (screen) =>
|
||||
@$(".#{screen}").find('.alert').addClass('hide')
|
||||
|
||||
disable: (e) =>
|
||||
@formDisable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', true)
|
||||
|
||||
enable: (e) =>
|
||||
@formEnable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', false)
|
|
@ -364,7 +364,7 @@ class Base extends App.ControllerContent
|
|||
if App.Config.get('system_online_service')
|
||||
@navigate 'getting_started/channel/email_pre_configured'
|
||||
else
|
||||
@navigate 'getting_started/channel'
|
||||
@navigate 'getting_started/email_notification'
|
||||
else
|
||||
for key, value of data.messages
|
||||
@showAlert( key, value )
|
||||
|
@ -394,6 +394,151 @@ class Base extends App.ControllerContent
|
|||
|
||||
App.Config.set( 'getting_started/base', Base, 'Routes' )
|
||||
|
||||
class EmailNotification extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
events:
|
||||
'change .js-outbound [name=adapter]': 'toggleOutboundAdapter'
|
||||
'submit .js-outbound': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# redirect if we are not admin
|
||||
if !@authenticate(true)
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Email Notifications'
|
||||
|
||||
@adapters = [
|
||||
{
|
||||
name: 'Email'
|
||||
class: 'email'
|
||||
link: '#getting_started/channel/email'
|
||||
},
|
||||
]
|
||||
|
||||
@fetch()
|
||||
|
||||
release: =>
|
||||
@el.removeClass('fit getstarted')
|
||||
|
||||
fetch: ->
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'getting_started',
|
||||
type: 'GET',
|
||||
url: @apiPath + '/getting_started',
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if import is active
|
||||
if data.import_mode == true
|
||||
@navigate '#import/' + data.import_backend
|
||||
return
|
||||
|
||||
# render page
|
||||
@render()
|
||||
)
|
||||
|
||||
render: ->
|
||||
@html App.view('getting_started/email_notification')()
|
||||
adapters =
|
||||
sendmail: 'Local MTA (Sendmail/Postfix/Exim/...) - use server setup'
|
||||
smtp: 'SMTP - configure your own outgoing SMTP settings'
|
||||
adapter_used = 'sendmail'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , default: adapter_used },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-outbound-type'),
|
||||
model: { configure_attributes: configureAttributesOutbound, className: '' },
|
||||
)
|
||||
@toggleOutboundAdapter()
|
||||
|
||||
toggleOutboundAdapter: =>
|
||||
|
||||
# show used backend
|
||||
channel_used = { options: {} }
|
||||
adapter = @$('.js-outbound [name=adapter]').val()
|
||||
if adapter is 'smtp'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autofocus: true, default: (channel_used['options']&&channel_used['options']['host']) },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['user']) },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false, single: true, default: (channel_used['options']&&channel_used['options']['password']) },
|
||||
]
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.base-outbound-settings')
|
||||
model: { configure_attributes: configureAttributesOutbound, className: '' }
|
||||
)
|
||||
else
|
||||
@el.find('.base-outbound-settings').html('')
|
||||
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
params['email'] = 'me@localhost'
|
||||
@disable(e)
|
||||
|
||||
@showSlide('js-test')
|
||||
|
||||
@ajax(
|
||||
id: 'email_notification'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/channels/email_notification'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
for key, value of data.settings
|
||||
App.Config.set( key, value )
|
||||
if App.Config.get('system_online_service')
|
||||
@navigate 'getting_started/channel/email_pre_configured'
|
||||
else
|
||||
@navigate 'getting_started/channel'
|
||||
else
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
|
||||
fail: =>
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
goToSlide: (e) =>
|
||||
e.preventDefault()
|
||||
slide = $(e.target).data('slide')
|
||||
@showSlide(slide)
|
||||
|
||||
showSlide: (name) =>
|
||||
@hideAlert(name)
|
||||
@$('.setup.wizard').addClass('hide')
|
||||
@$(".setup.wizard.#{name}").removeClass('hide')
|
||||
@$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus()
|
||||
|
||||
showAlert: (screen, message) =>
|
||||
@$(".#{screen}").find('.alert').removeClass('hide').text( App.i18n.translateInline( message ) )
|
||||
|
||||
hideAlert: (screen) =>
|
||||
@$(".#{screen}").find('.alert').addClass('hide')
|
||||
|
||||
disable: (e) =>
|
||||
@formDisable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', true)
|
||||
|
||||
enable: (e) =>
|
||||
@formEnable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', false)
|
||||
|
||||
App.Config.set( 'getting_started/email_notification', EmailNotification, 'Routes' )
|
||||
|
||||
class Channel extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
|
||||
|
@ -610,7 +755,7 @@ class ChannelEmail extends App.ControllerContent
|
|||
@ajax(
|
||||
id: 'email_probe'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_probe'
|
||||
url: @apiPath + '/channels/email_probe'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
@ -643,7 +788,7 @@ class ChannelEmail extends App.ControllerContent
|
|||
@ajax(
|
||||
id: 'email_inbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_inbound'
|
||||
url: @apiPath + '/channels/email_inbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
@ -679,7 +824,7 @@ class ChannelEmail extends App.ControllerContent
|
|||
@ajax(
|
||||
id: 'email_outbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_outbound'
|
||||
url: @apiPath + '/channels/email_outbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
@ -705,7 +850,7 @@ class ChannelEmail extends App.ControllerContent
|
|||
@ajax(
|
||||
id: 'email_verify'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_verify'
|
||||
url: @apiPath + '/channels/email_verify'
|
||||
data: JSON.stringify( account )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
|
|
@ -2,18 +2,20 @@ class App.Channel extends App.Model
|
|||
@configure 'Channel', 'adapter', 'area', 'options', 'group_id', 'active', 'updated_at'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/channels'
|
||||
@configure_delete = true
|
||||
|
||||
@configure_attributes = [
|
||||
{ name: 'adapter', display: 'Type', tag: 'select', multiple: false, null: false, options: { IMAP: 'IMAP', POP3: 'POP3' } },
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: true, options: { true: 'yes', false: 'no' }, translate: true, default: true},
|
||||
{ name: 'options::folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, nulloption: true, relation: 'Group' },
|
||||
{ name: 'active', display: 'Active', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true },
|
||||
]
|
||||
@configure_overview = [
|
||||
'adapter', 'options::host', 'options::user', 'group'
|
||||
]
|
||||
displayName: ->
|
||||
name = ''
|
||||
if @options
|
||||
if @options.inbound
|
||||
name += "#{@options.inbound.options.user}@#{@options.inbound.options.host} (#{@options.inbound.adapter})"
|
||||
if @options.outbound
|
||||
if @options.outbound
|
||||
if name != ''
|
||||
name += ' / '
|
||||
if @options.outbound.options
|
||||
name += "#{@options.outbound.options.host} (#{@options.outbound.adapter})"
|
||||
else
|
||||
name += " (#{@options.outbound.adapter})"
|
||||
if name == ''
|
||||
name = '???'
|
||||
name
|
|
@ -1,11 +1,20 @@
|
|||
class App.EmailAddress extends App.Model
|
||||
@configure 'EmailAddress', 'realname', 'email', 'note', 'active', 'updated_at'
|
||||
@configure 'EmailAddress', 'realname', 'email', 'channel_id', 'note', 'active', 'updated_at'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/email_addresses'
|
||||
|
||||
@filterChannel: (options, type) =>
|
||||
return options if type isnt 'collection'
|
||||
_.filter(
|
||||
options
|
||||
(channel) ->
|
||||
return channel if channel && channel.area is 'Email::Account'
|
||||
)
|
||||
|
||||
@configure_attributes = [
|
||||
{ name: 'realname', display: 'Realname', tag: 'input', type: 'text', limit: 250, null: false },
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'text', limit: 250, null: false },
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 250, null: false },
|
||||
{ name: 'channel_id', display: 'Channel', tag: 'select', multiple: false, null: false, relation: 'Channel', nulloption: true, filter: @filterChannel },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
|
||||
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
<h1><%- @T('Email Accounts') %></h1>
|
||||
|
||||
<% if !_.isEmpty(@email_addresses_not_used): %>
|
||||
<h2><%- @T('Not linked email addresses') %></h2>
|
||||
<ul>
|
||||
<% for email_address in @email_addresses_not_used: %>
|
||||
<li data-id="<%= email_address.id %>"><a href="" data-type="email-address-edit"><%= email_address.email %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
<table class="table table-hover user-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%- @T('Inbound') %></th>
|
||||
<th><%- @T('Outbound') %></th>
|
||||
<th><%- @T('Email Adresses') %></th>
|
||||
<th><%- @T('Action') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for channel in @channels: %>
|
||||
<tr data-id="<%- channel.id %>">
|
||||
<td class="<% if channel.status_in is 'ok': %>success<% else if channel.status_in is 'error': %>danger<% else: %>warning<% end %>">
|
||||
<%- @T('State') %>: <%- @T(channel.status_in || 'unknown') %><br>
|
||||
<%= channel.options.inbound.options.user %><br>
|
||||
<a href="#" data-type="edit-inbound"><%= channel.options.inbound.options.host %> (<%= channel.options.inbound.adapter %>)</a>
|
||||
</td>
|
||||
<td class="<% if channel.status_out is 'ok': %>success<% else if channel.status_out is 'error': %>danger<% else: %>warning<% end %>">
|
||||
<%- @T('State') %>: <%- @T(channel.status_out || 'unknown') %><br>
|
||||
<% if channel.options.outbound && channel.options.outbound.options: %>
|
||||
<%= channel.options.outbound.options.user %><br>
|
||||
<a href="#" data-type="edit-outbound"><%= channel.options.outbound.options.host %>
|
||||
<% end %>
|
||||
(<%= channel.options.outbound.adapter %>)</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<% if !_.isEmpty(channel.email_addresses): %>
|
||||
<% for email_address in channel.email_addresses: %>
|
||||
<li data-id="<%= email_address.id %>"><a href="" data-type="email-address-edit"><%= email_address.email %></a>
|
||||
<% end %>
|
||||
<% else: %>
|
||||
<li><%- @T('none') %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<a href="#" data-type="email-address-new" title="<%- @Ti('New Email Address') %>"><svg class="icon-trash"><use xlink:href="#icon-plus"></use></svg></a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" data-type="delete" title="<%- @Ti('Delete') %>"><svg class="icon-trash"><use xlink:href="#icon-trash"></use></svg></a>
|
||||
</td>
|
||||
</tr>
|
||||
<% if channel.status_in is 'error': %>
|
||||
<tr>
|
||||
<td colspan="4"><%= channel.last_log_in %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if channel.status_out is 'error': %>
|
||||
<tr>
|
||||
<td colspan="4"><%= channel.last_log_out %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<a data-type="new" class="btn btn--success"><%- @T('New') %></a>
|
||||
|
||||
<h1><%- @T('Notification Account') %></h1>
|
||||
|
||||
<table class="table table-hover user-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%- @T('Outbound') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-id="<%- @channel.id %>">
|
||||
<td class="<% if @channel.status_out is 'ok': %>success<% else if @channel.status_out is 'error': %>danger<% else: %>warning<% end %>">
|
||||
<%- @T('State') %>: <%- @T(@channel.status_out || 'unknown') %><br>
|
||||
<% if @channel.options.outbound && @channel.options.outbound.options: %>
|
||||
<%= @channel.options.outbound.options.user %><br>
|
||||
<a href="#" data-type="edit-notification-outbound"><%= @channel.options.outbound.options.host %>
|
||||
<% end %>
|
||||
(<%= @channel.options.outbound.adapter %>)</a>
|
||||
</td>
|
||||
</tr>
|
||||
<% if @channel.status_in is 'error': %>
|
||||
<tr>
|
||||
<td colspan="1"><%= @channel.last_log_in %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @channel.status_out is 'error': %>
|
||||
<tr>
|
||||
<td colspan="1"><%= @channel.last_log_out %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
|
@ -0,0 +1,92 @@
|
|||
<div class="modal-dialog">
|
||||
|
||||
<form class="setup wizard js-intro">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Full Name') %></label>
|
||||
<input type="text" class="form-control" value="" name="realname" placeholder="<%- @Ti('Organization Support') %>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Email') %></label>
|
||||
<input type="email" class="form-control" value="" name="email" placeholder="<%- @Ti('support@example.com') %>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Password') %></label>
|
||||
<input type="password" class="form-control" name="password" value="" required>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<button class="btn btn--primary align-right"><%- @T('Connect') %></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-probe">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Testing') %> <span class="js-email"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-test">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Verifying...') %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-verify">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Verify sending and receiving') %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-inbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Inbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-inbound-settings"></div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--text btn--secondary js-back" data-slide="js-intro"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-outbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Outbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-outbound-type"></div>
|
||||
<div class="base-outbound-settings"></div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--text btn--secondary js-back" data-slide="js-inbound"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,39 @@
|
|||
<div class="modal-dialog">
|
||||
|
||||
<form class="setup wizard hide js-probe">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Testing') %> <span class="js-email"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-test">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Verifying...') %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard js-outbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Outbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-outbound-type"></div>
|
||||
<div class="base-outbound-settings"></div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<form id="mail_adapter">
|
||||
<div id="form-email-adapter"></div>
|
||||
<div id="form-email-adapter-settings"></div>
|
||||
<button data-type="" type="submit" class="btn"><%- @T( 'Submit' ) %></botton>
|
||||
</form>
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--text btn--secondary" href="#getting_started/base"><%- @T('Go Back') %></a>
|
||||
<a class="btn btn--text btn--secondary" href="#getting_started/email_notification"><%- @T('Go Back') %></a>
|
||||
<a class="btn align-right" href="#getting_started/finish"><%- @T( 'Skip' ) %></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
|
||||
<form class="setup wizard hide js-inbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('E-Mail Inbound') %></h2>
|
||||
<h2><%- @T('Email Inbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-inbound-settings"></div>
|
||||
|
@ -78,7 +78,7 @@
|
|||
|
||||
<form class="setup wizard hide js-outbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('E-Mail Outbound') %></h2>
|
||||
<h2><%- @T('Email Outbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-outbound-type"></div>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<div class="main flex vertical centered darkBackground">
|
||||
<svg class="wizard-logo icon-full-logo"><use xlink:href="#icon-full-logo" /></svg>
|
||||
|
||||
<form class="setup wizard js-outbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Notification') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-outbound-type"></div>
|
||||
<div class="base-outbound-settings"></div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--text btn--secondary" href="#getting_started/base"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-test">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Notification') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> <%- @T('Verifying...') %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
|
@ -11,14 +11,25 @@ JSON
|
|||
Example:
|
||||
{
|
||||
"id":1,
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
"group_id:": 1,
|
||||
"options":{
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
"inbound": {
|
||||
"adapter":"IMAP",
|
||||
"options": {
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
},
|
||||
"outbound":{
|
||||
"adapter":"SMTP",
|
||||
"options": {
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"start_tls":true
|
||||
}
|
||||
},
|
||||
"active":true,
|
||||
"updated_at":"2012-09-14T17:51:53Z",
|
||||
|
@ -29,10 +40,10 @@ Example:
|
|||
|
||||
{
|
||||
"id":1,
|
||||
"area":"Twitter::Inbound",
|
||||
"adapter":"Twitter",
|
||||
"area":"Twitter::Account",
|
||||
"group_id:": 1,
|
||||
"options":{
|
||||
"adapter":"Twitter",
|
||||
"auth": {
|
||||
"consumer_key":"PJ4c3dYYRtSZZZdOKo8ow",
|
||||
"consumer_secret":"ggAdnJE2Al1Vv0cwwvX5bdvKOieFs0vjCIh5M8Dxk",
|
||||
|
@ -84,14 +95,12 @@ Response:
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
...
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
...
|
||||
}
|
||||
]
|
||||
|
@ -114,8 +123,7 @@ GET /api/v1/channels/#{id}.json
|
|||
Response:
|
||||
{
|
||||
"id": 1,
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
...
|
||||
}
|
||||
|
||||
|
@ -136,22 +144,33 @@ POST /api/v1/channels.json
|
|||
|
||||
Payload:
|
||||
{
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
"group_id:": 1,
|
||||
"options":{
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
"inbound":
|
||||
"adapter":"IMAP",
|
||||
"options":{
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
},
|
||||
},
|
||||
"outbound":{
|
||||
"adapter":"SMTP",
|
||||
"options": {
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"start_tls":true
|
||||
}
|
||||
},
|
||||
"active":true,
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
...
|
||||
}
|
||||
|
||||
|
@ -173,14 +192,26 @@ PUT /api/v1/channels/{id}.json
|
|||
Payload:
|
||||
{
|
||||
"id":1,
|
||||
"area":"Email::Inbound",
|
||||
"adapter":"IMAP",
|
||||
"area":"Email::Account",
|
||||
"group_id:": 1,
|
||||
"options":{
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
"inbound":
|
||||
"adapter":"IMAP",
|
||||
"options":{
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"ssl":true
|
||||
},
|
||||
},
|
||||
"outbound":{
|
||||
"adapter":"SMTP",
|
||||
"options": {
|
||||
"host":"mail.example.com",
|
||||
"user":"some_user",
|
||||
"password":"some_password",
|
||||
"start_tls":true
|
||||
}
|
||||
},
|
||||
"active":true,
|
||||
}
|
||||
|
@ -219,4 +250,207 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
|
|||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
model_destory_render(Channel, params)
|
||||
end
|
||||
|
||||
def email_index
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
assets = {}
|
||||
Channel.all.each {|channel|
|
||||
assets = channel.assets(assets)
|
||||
}
|
||||
EmailAddress.all.each {|email_address|
|
||||
assets = email_address.assets(assets)
|
||||
}
|
||||
render json: {
|
||||
assets: assets
|
||||
}
|
||||
end
|
||||
|
||||
def email_probe
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# probe settings based on email and password
|
||||
result = EmailHelper::Probe.full(
|
||||
email: params[:email],
|
||||
password: params[:password],
|
||||
)
|
||||
|
||||
# verify if user+host already exists
|
||||
if result[:result] == 'ok'
|
||||
return if email_account_duplicate?(result)
|
||||
end
|
||||
|
||||
render json: result
|
||||
end
|
||||
|
||||
def email_outbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# connection test
|
||||
render json: EmailHelper::Probe.outbound(params, params[:email])
|
||||
end
|
||||
|
||||
def email_inbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# connection test
|
||||
result = EmailHelper::Probe.inbound(params)
|
||||
|
||||
# check account duplicate
|
||||
return if email_account_duplicate?({ setting: { inbound: params } }, params[:channel_id])
|
||||
|
||||
render json: result
|
||||
end
|
||||
|
||||
def email_verify
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
email = params[:email] || params[:meta][:email]
|
||||
email = email.downcase
|
||||
channel_id = params[:channel_id]
|
||||
|
||||
# check account duplicate
|
||||
return if email_account_duplicate?({ setting: { inbound: params[:inbound] } }, channel_id)
|
||||
|
||||
# check delivery for 30 sek.
|
||||
result = EmailHelper::Verify.email(
|
||||
outbound: params[:outbound],
|
||||
inbound: params[:inbound],
|
||||
sender: email,
|
||||
subject: params[:subject],
|
||||
)
|
||||
|
||||
if result[:result] != 'ok'
|
||||
render json: result
|
||||
return
|
||||
end
|
||||
|
||||
# update account
|
||||
if channel_id
|
||||
channel = Channel.find(channel_id)
|
||||
channel.update_attributes(
|
||||
options: {
|
||||
inbound: params[:inbound],
|
||||
outbound: params[:outbound],
|
||||
},
|
||||
last_log_in: '',
|
||||
last_log_out: '',
|
||||
status_in: nil,
|
||||
status_out: nil,
|
||||
)
|
||||
render json: {
|
||||
result: 'ok',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# create new account
|
||||
channel = Channel.create(
|
||||
area: 'Email::Account',
|
||||
options: {
|
||||
inbound: params[:inbound],
|
||||
outbound: params[:outbound],
|
||||
},
|
||||
active: true,
|
||||
group_id: Group.first.id,
|
||||
)
|
||||
|
||||
# remember address && set channel for email address
|
||||
address = EmailAddress.find_by(email: email)
|
||||
|
||||
# if we are on initial setup, use already exisiting dummy email address
|
||||
if Channel.count == 1
|
||||
address = EmailAddress.first
|
||||
end
|
||||
|
||||
if address
|
||||
address.update_attributes(
|
||||
realname: params[:meta][:realname],
|
||||
email: email,
|
||||
active: true,
|
||||
channel_id: channel.id,
|
||||
)
|
||||
else
|
||||
address = EmailAddress.create(
|
||||
realname: params[:meta][:realname],
|
||||
email: email,
|
||||
active: true,
|
||||
channel_id: channel.id,
|
||||
)
|
||||
end
|
||||
|
||||
render json: {
|
||||
result: 'ok',
|
||||
}
|
||||
end
|
||||
|
||||
def email_notification
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
adapter = params[:adapter].downcase
|
||||
|
||||
email = Setting.get('notification_sender')
|
||||
|
||||
# connection test
|
||||
result = EmailHelper::Probe.outbound(params, email)
|
||||
|
||||
# save settings
|
||||
if result[:result] == 'ok'
|
||||
|
||||
# validate adapter
|
||||
if adapter !~ /^(smtp|sendmail)$/
|
||||
render json: {
|
||||
result: 'failed',
|
||||
message: "Unknown adapter '#{adapter}'",
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
Channel.where(area: 'Email::Notification').each {|channel|
|
||||
active = false
|
||||
if adapter =~ /^#{channel.options[:outbound][:adapter]}$/i
|
||||
active = true
|
||||
channel.options = {
|
||||
outbound: {
|
||||
adapter: adapter,
|
||||
options: params[:options],
|
||||
},
|
||||
}
|
||||
end
|
||||
channel.active = active
|
||||
channel.save
|
||||
}
|
||||
end
|
||||
render json: result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def email_account_duplicate?(result, channel_id = nil)
|
||||
Channel.where(area: 'Email::Account').each {|channel|
|
||||
next if !channel.options
|
||||
next if !channel.options[:inbound]
|
||||
next if !channel.options[:inbound][:adapter]
|
||||
next if channel.options[:inbound][:adapter] != result[:setting][:inbound][:adapter]
|
||||
next if channel.options[:inbound][:options][:host] != result[:setting][:inbound][:options][:host]
|
||||
next if channel.options[:inbound][:options][:user] != result[:setting][:inbound][:options][:user]
|
||||
next if channel.id.to_s == channel_id.to_s
|
||||
render json: {
|
||||
result: 'duplicate',
|
||||
message: 'Account already exists!',
|
||||
}
|
||||
return true
|
||||
}
|
||||
false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -188,119 +188,6 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
|
|||
}
|
||||
end
|
||||
|
||||
def email_probe
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# probe settings based on email and password
|
||||
render json: EmailHelper::Probe.full(
|
||||
email: params[:email],
|
||||
password: params[:password],
|
||||
)
|
||||
end
|
||||
|
||||
def email_outbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# connection test
|
||||
render json: EmailHelper::Probe.outbound(params, params[:email])
|
||||
end
|
||||
|
||||
def email_inbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# connection test
|
||||
render json: EmailHelper::Probe.inbound(params)
|
||||
end
|
||||
|
||||
def email_verify
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||
|
||||
# send verify email to inbox
|
||||
if !params[:subject]
|
||||
subject = '#' + rand(99_999_999_999).to_s
|
||||
else
|
||||
subject = params[:subject]
|
||||
end
|
||||
|
||||
result = EmailHelper::Verify.email(
|
||||
outbound: params[:outbound],
|
||||
inbound: params[:inbound],
|
||||
sender: params[:meta][:email],
|
||||
subject: subject,
|
||||
)
|
||||
|
||||
# check delivery for 30 sek.
|
||||
if result[:result] != 'ok'
|
||||
render json: result
|
||||
return
|
||||
end
|
||||
|
||||
# remember address
|
||||
address = EmailAddress.where( email: params[:meta][:email] ).first
|
||||
if !address
|
||||
address = EmailAddress.first
|
||||
end
|
||||
if address
|
||||
address.update_attributes(
|
||||
realname: params[:meta][:realname],
|
||||
email: params[:meta][:email],
|
||||
active: 1,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
else
|
||||
EmailAddress.create(
|
||||
realname: params[:meta][:realname],
|
||||
email: params[:meta][:email],
|
||||
active: 1,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
end
|
||||
|
||||
# store mailbox
|
||||
Channel.create(
|
||||
area: 'Email::Inbound',
|
||||
adapter: params[:inbound][:adapter],
|
||||
options: params[:inbound][:options],
|
||||
group_id: 1,
|
||||
active: 1,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
# save settings
|
||||
if params[:outbound][:adapter] =~ /^smtp$/i
|
||||
smtp = Channel.where( adapter: 'SMTP', area: 'Email::Outbound' ).first
|
||||
smtp.options = params[:outbound][:options]
|
||||
smtp.active = true
|
||||
smtp.save!
|
||||
sendmail = Channel.where( adapter: 'Sendmail' ).first
|
||||
sendmail.active = false
|
||||
sendmail.save!
|
||||
else
|
||||
sendmail = Channel.where( adapter: 'Sendmail', area: 'Email::Outbound' ).first
|
||||
sendmail.options = {}
|
||||
sendmail.active = true
|
||||
sendmail.save!
|
||||
smtp = Channel.where( adapter: 'SMTP' ).first
|
||||
smtp.active = false
|
||||
smtp.save
|
||||
end
|
||||
|
||||
render json: {
|
||||
result: 'ok',
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auto_wizard_enabled_response
|
||||
|
|
|
@ -3,24 +3,107 @@
|
|||
class Channel < ApplicationModel
|
||||
store :options
|
||||
|
||||
def self.fetch
|
||||
channels = Channel.where( 'active = ? AND area LIKE ?', true, '%::Inbound' )
|
||||
channels.each { |channel|
|
||||
begin
|
||||
# we need to require each channel backend individually otherwise we get a
|
||||
# 'warning: toplevel constant Twitter referenced by Channel::Twitter' error e.g.
|
||||
# so we have to convert the channel name to the filename via Rails String.underscore
|
||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
||||
require "channel/#{channel[:adapter].to_filename}"
|
||||
=begin
|
||||
|
||||
channel_object = Object.const_get("Channel::#{channel[:adapter].to_classname}")
|
||||
channel_instance = channel_object.new
|
||||
channel_instance.fetch(channel)
|
||||
rescue => e
|
||||
logger.error "Can't use Channel::#{channel[:adapter].to_classname}"
|
||||
logger.error e.inspect
|
||||
logger.error e.backtrace
|
||||
end
|
||||
}
|
||||
fetch all accounts
|
||||
|
||||
Channel.fetch
|
||||
|
||||
=end
|
||||
|
||||
def self.fetch
|
||||
channels = Channel.where('active = ? AND area LIKE ?', true, '%::Account')
|
||||
channels.each(&:fetch)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
fetch one account
|
||||
|
||||
channel = Channel.where(area: 'Email::Account').first
|
||||
channel.fetch
|
||||
|
||||
=end
|
||||
|
||||
def fetch
|
||||
|
||||
adapter = options[:adapter]
|
||||
adapter_options = options
|
||||
if options[:options]
|
||||
adapter_options = options[:options]
|
||||
elsif options[:inbound] && options[:inbound][:adapter]
|
||||
adapter = options[:inbound][:adapter]
|
||||
adapter_options = options[:inbound][:options]
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
# we need to require each channel backend individually otherwise we get a
|
||||
# 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g.
|
||||
# so we have to convert the channel name to the filename via Rails String.underscore
|
||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
||||
require "channel/driver/#{adapter.to_filename}"
|
||||
|
||||
driver_class = Object.const_get("Channel::Driver::#{adapter.to_classname}")
|
||||
driver_instance = driver_class.new
|
||||
driver_instance.fetch(adapter_options, self)
|
||||
self.status_in = 'ok'
|
||||
self.last_log_in = ''
|
||||
save
|
||||
rescue => e
|
||||
error = "Can't use Channel::Driver::#{adapter.to_classname}: #{e.inspect}"
|
||||
logger.error error
|
||||
logger.error e.backtrace
|
||||
self.status_in = 'error'
|
||||
self.last_log_in = error
|
||||
save
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
send via account
|
||||
|
||||
channel = Channel.where(area: 'Email::Account').first
|
||||
channel.deliver(mail_params, notification)
|
||||
|
||||
=end
|
||||
|
||||
def deliver(mail_params, notification = false)
|
||||
|
||||
adapter = options[:adapter]
|
||||
adapter_options = options
|
||||
if options[:options]
|
||||
adapter_options = options[:options]
|
||||
elsif options[:outbound] && options[:outbound][:adapter]
|
||||
adapter = options[:outbound][:adapter]
|
||||
adapter_options = options[:outbound][:options]
|
||||
end
|
||||
|
||||
begin
|
||||
|
||||
# we need to require each channel backend individually otherwise we get a
|
||||
# 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g.
|
||||
# so we have to convert the channel name to the filename via Rails String.underscore
|
||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
||||
require "channel/driver/#{adapter.to_filename}"
|
||||
|
||||
driver_class = Object.const_get("Channel::Driver::#{adapter.to_classname}")
|
||||
driver_instance = driver_class.new
|
||||
driver_instance.send(adapter_options, mail_params, notification)
|
||||
self.status_out = 'ok'
|
||||
self.last_log_out = ''
|
||||
save
|
||||
rescue => e
|
||||
error = "Can't use Channel::Driver::#{adapter.to_classname}: #{e.inspect}"
|
||||
logger.error error
|
||||
logger.error e.backtrace
|
||||
self.status_out = 'error'
|
||||
self.last_log_out = error
|
||||
save
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
4
app/models/channel/driver.rb
Normal file
4
app/models/channel/driver.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class Channel
|
||||
class Driver
|
||||
end
|
||||
end
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
require 'facebook'
|
||||
|
||||
class Channel::Facebook
|
||||
class Channel::Driver::Facebook
|
||||
|
||||
def fetch (channel)
|
||||
def fetch (adapter_options, channel)
|
||||
|
||||
@channel = channel
|
||||
@facebook = Facebook.new( @channel[:options] )
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
require 'net/imap'
|
||||
|
||||
class Channel::Imap < Channel::EmailParser
|
||||
class Channel::Driver::Imap < Channel::EmailParser
|
||||
|
||||
def fetch (channel, check_type = '', verify_string = '')
|
||||
def fetch (options, channel, check_type = '', verify_string = '')
|
||||
ssl = true
|
||||
port = 993
|
||||
if channel[:options].key?(:ssl) && channel[:options][:ssl].to_s == 'false'
|
||||
if options.key?(:ssl) && options[:ssl].to_s == 'false'
|
||||
ssl = false
|
||||
port = 143
|
||||
end
|
||||
|
||||
Rails.logger.info "fetching imap (#{channel[:options][:host]}/#{channel[:options][:user]} port=#{port},ssl=#{ssl})"
|
||||
Rails.logger.info "fetching imap (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})"
|
||||
|
||||
# on check, reduce open_timeout to have faster probing
|
||||
timeout = 12
|
||||
|
@ -22,24 +22,24 @@ class Channel::Imap < Channel::EmailParser
|
|||
|
||||
Timeout.timeout(timeout) do
|
||||
|
||||
@imap = Net::IMAP.new( channel[:options][:host], port, ssl, nil, false )
|
||||
@imap = Net::IMAP.new( options[:host], port, ssl, nil, false )
|
||||
|
||||
end
|
||||
|
||||
# try LOGIN, if not - try plain
|
||||
begin
|
||||
@imap.authenticate( 'LOGIN', channel[:options][:user], channel[:options][:password] )
|
||||
@imap.authenticate( 'LOGIN', options[:user], options[:password] )
|
||||
rescue => e
|
||||
if e.to_s !~ /(unsupported\s(authenticate|authentication)\smechanism|not\ssupported)/i
|
||||
raise e
|
||||
end
|
||||
@imap.login( channel[:options][:user], channel[:options][:password] )
|
||||
@imap.login( options[:user], options[:password] )
|
||||
end
|
||||
|
||||
if !channel[:options][:folder] || channel[:options][:folder].empty?
|
||||
if !options[:folder] || options[:folder].empty?
|
||||
@imap.select('INBOX')
|
||||
else
|
||||
@imap.select( channel[:options][:folder] )
|
||||
@imap.select( options[:folder] )
|
||||
end
|
||||
if check_type == 'check'
|
||||
Rails.logger.info 'check only mode, fetch no emails'
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Channel::MailStdin < Channel::EmailParser
|
||||
class Channel::Driver::MailStdin < Channel::EmailParser
|
||||
def initialize
|
||||
Rails.logger.info 'read main from STDIN'
|
||||
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
require 'net/pop'
|
||||
|
||||
class Channel::Pop3 < Channel::EmailParser
|
||||
class Channel::Driver::Pop3 < Channel::EmailParser
|
||||
|
||||
def fetch (channel, check_type = '', verify_string = '')
|
||||
def fetch (options, channel, check_type = '', verify_string = '')
|
||||
ssl = true
|
||||
port = 995
|
||||
if channel[:options].key?(:ssl) && channel[:options][:ssl].to_s == 'false'
|
||||
if options.key?(:ssl) && options[:ssl].to_s == 'false'
|
||||
ssl = false
|
||||
port = 110
|
||||
end
|
||||
|
||||
Rails.logger.info "fetching pop3 (#{channel[:options][:host]}/#{channel[:options][:user]} port=#{port},ssl=#{ssl})"
|
||||
Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})"
|
||||
|
||||
@pop = Net::POP3.new( channel[:options][:host], port )
|
||||
@pop = Net::POP3.new( options[:host], port )
|
||||
|
||||
# on check, reduce open_timeout to have faster probing
|
||||
if check_type == 'check'
|
||||
|
@ -25,7 +25,7 @@ class Channel::Pop3 < Channel::EmailParser
|
|||
if ssl
|
||||
@pop.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
|
||||
end
|
||||
@pop.start( channel[:options][:user], channel[:options][:password] )
|
||||
@pop.start( options[:user], options[:password] )
|
||||
if check_type == 'check'
|
||||
Rails.logger.info 'check only mode, fetch no emails'
|
||||
disconnect
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Channel::Sendmail
|
||||
def send(attr, _channel, notification = false)
|
||||
class Channel::Driver::Sendmail
|
||||
def send(_options, attr, notification = false)
|
||||
|
||||
# return if we run import mode
|
||||
return if Setting.get('import_mode')
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Channel::SMTP
|
||||
def send(attr, channel, notification = false)
|
||||
class Channel::Driver::Smtp
|
||||
def send(options, attr, notification = false)
|
||||
|
||||
# return if we run import mode
|
||||
return if Setting.get('import_mode')
|
||||
|
@ -9,11 +9,11 @@ class Channel::SMTP
|
|||
mail = Channel::EmailBuild.build(attr, notification)
|
||||
mail.delivery_method :smtp, {
|
||||
openssl_verify_mode: 'none',
|
||||
address: channel[:options][:host],
|
||||
port: channel[:options][:port] || 25,
|
||||
domain: channel[:options][:host],
|
||||
user_name: channel[:options][:user],
|
||||
password: channel[:options][:password],
|
||||
address: options[:host],
|
||||
port: options[:port] || 25,
|
||||
domain: options[:host],
|
||||
user_name: options[:user],
|
||||
password: options[:password],
|
||||
enable_starttls_auto: true,
|
||||
}
|
||||
mail.deliver
|
|
@ -1,8 +1,8 @@
|
|||
# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Channel::Twitter
|
||||
class Channel::Driver::Twitter
|
||||
|
||||
def fetch (channel)
|
||||
def fetch (adapter_options, channel)
|
||||
|
||||
@channel = channel
|
||||
@tweet = Tweet.new( @channel[:options][:auth] )
|
||||
|
@ -21,7 +21,7 @@ class Channel::Twitter
|
|||
|
||||
def send(article, _notification = false)
|
||||
|
||||
@channel = Channel.find_by( area: 'Twitter::Inbound', active: true )
|
||||
@channel = Channel.find_by( area: 'Twitter::Account', active: true )
|
||||
@tweet = Tweet.new( @channel[:options][:auth] )
|
||||
|
||||
tweet = @tweet.from_article(article)
|
|
@ -1,28 +0,0 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'net/imap'
|
||||
|
||||
module Channel::EmailSend
|
||||
def self.send(article, notification = false)
|
||||
channel = Channel.find_by( area: 'Email::Outbound', active: true )
|
||||
begin
|
||||
# we need to require the channel backend individually otherwise we get a
|
||||
# 'warning: toplevel constant Twitter referenced by Channel::Twitter' error e.g.
|
||||
# so we have to convert the channel name to the filename via Rails String.underscore
|
||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
||||
require "channel/#{channel[:adapter].underscore}"
|
||||
|
||||
channel_object = Object.const_get("Channel::#{channel[:adapter]}")
|
||||
channel_instance = channel_object.new
|
||||
|
||||
result = channel_instance.send(article, channel, notification)
|
||||
|
||||
channel_instance.disconnect
|
||||
rescue => e
|
||||
Rails.logger.error "Can't use Channel::#{channel[:adapter]}"
|
||||
Rails.logger.error e.inspect
|
||||
Rails.logger.error e.backtrace
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class EmailAddress < ApplicationModel
|
||||
has_many :groups, after_add: :cache_update, after_remove: :cache_update
|
||||
belongs_to :channel
|
||||
validates :realname, presence: true
|
||||
validates :email, presence: true
|
||||
|
||||
|
|
|
@ -11,7 +11,15 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob
|
|||
subject = ticket.subject_build( record.subject )
|
||||
|
||||
# send email
|
||||
message = Channel::EmailSend.send(
|
||||
if !ticket.group.email_address_id
|
||||
fail "Can't send email, no email address definde for group id '#{ticket.group.id}'"
|
||||
elsif !ticket.group.email_address.channel_id
|
||||
fail "Can't send email, no channel definde for email_address id '#{ticket.group.email_address_id}'"
|
||||
end
|
||||
channel = ticket.group.email_address.channel
|
||||
|
||||
# get linked channel and send
|
||||
message = channel.deliver(
|
||||
{
|
||||
message_id: record.message_id,
|
||||
in_reply_to: record.in_reply_to,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'channel/facebook'
|
||||
require 'channel/driver/facebook'
|
||||
|
||||
class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
@ -19,7 +19,7 @@ class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
|
|||
type = Ticket::Article::Type.lookup( id: record.type_id )
|
||||
return if type['name'] !~ /\Afacebook/
|
||||
|
||||
facebook = Channel::Facebook.new
|
||||
facebook = Channel::Driver::Facebook.new
|
||||
post = facebook.send({
|
||||
type: type['name'],
|
||||
to: record.to,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
||||
require 'channel/twitter'
|
||||
require 'channel/driver/twitter'
|
||||
|
||||
class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
||||
observe 'ticket::_article'
|
||||
|
@ -20,7 +20,7 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
|||
type = Ticket::Article::Type.lookup( id: record.type_id )
|
||||
return if type['name'] !~ /\Atwitter/
|
||||
|
||||
twitter = Channel::Twitter.new
|
||||
twitter = Channel::Driver::Twitter.new
|
||||
tweet = twitter.send({
|
||||
type: type['name'],
|
||||
to: record.to,
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
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
|
||||
|
||||
# channels
|
||||
match api_path + '/channels', to: 'channels#index', via: :get
|
||||
match api_path + '/channels/:id', to: 'channels#show', via: :get
|
||||
|
|
|
@ -2,13 +2,9 @@ Zammad::Application.routes.draw do
|
|||
api_path = Rails.configuration.api_path
|
||||
|
||||
# getting_started
|
||||
match api_path + '/getting_started', to: 'getting_started#index', via: :get
|
||||
match api_path + '/getting_started/auto_wizard/:token', to: 'getting_started#auto_wizard_admin', via: :get
|
||||
match api_path + '/getting_started/auto_wizard', to: 'getting_started#auto_wizard_admin', via: :get
|
||||
match api_path + '/getting_started/base', to: 'getting_started#base', via: :post
|
||||
match api_path + '/getting_started/email_probe', to: 'getting_started#email_probe', via: :post
|
||||
match api_path + '/getting_started/email_outbound', to: 'getting_started#email_outbound', via: :post
|
||||
match api_path + '/getting_started/email_inbound', to: 'getting_started#email_inbound', via: :post
|
||||
match api_path + '/getting_started/email_verify', to: 'getting_started#email_verify', via: :post
|
||||
match api_path + '/getting_started', to: 'getting_started#index', via: :get
|
||||
match api_path + '/getting_started/auto_wizard/:token', to: 'getting_started#auto_wizard_admin', via: :get
|
||||
match api_path + '/getting_started/auto_wizard', to: 'getting_started#auto_wizard_admin', via: :get
|
||||
match api_path + '/getting_started/base', to: 'getting_started#base', via: :post
|
||||
|
||||
end
|
||||
|
|
57
db/migrate/20150824000002_update_channel.rb
Normal file
57
db/migrate/20150824000002_update_channel.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
class UpdateChannel < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
add_column :email_addresses, :channel_id, :integer, null: true
|
||||
EmailAddress.reset_column_information
|
||||
|
||||
channel = Channel.find_by(area: 'Email::Inbound')
|
||||
EmailAddress.all.each {|email_address|
|
||||
email_address.channel_id = channel.id
|
||||
email_address.save
|
||||
}
|
||||
|
||||
add_column :channels, :last_log_in, :text, limit: 500.kilobytes + 1, null: true
|
||||
add_column :channels, :last_log_out, :text, limit: 500.kilobytes + 1, null: true
|
||||
add_column :channels, :status_in, :string, limit: 100, null: true
|
||||
add_column :channels, :status_out, :string, limit: 100, null: true
|
||||
Channel.reset_column_information
|
||||
|
||||
channel_outbound = Channel.find_by(area: 'Email::Outbound', active: true)
|
||||
|
||||
Channel.all.each {|channel|
|
||||
if channel.area == 'Email::Inbound'
|
||||
channel.area = 'Email::Account'
|
||||
options = {
|
||||
inbound: {
|
||||
adapter: channel.adapter.downcase,
|
||||
options: channel.options,
|
||||
},
|
||||
outbound: {
|
||||
adapter: channel_outbound.adapter.downcase,
|
||||
options: channel_outbound.options,
|
||||
},
|
||||
}
|
||||
channel.options = options
|
||||
channel.save
|
||||
elsif channel.area == 'Email::Outbound'
|
||||
channel.area = 'Email::Notification'
|
||||
options = {
|
||||
outbound: {
|
||||
adapter: channel.adapter,
|
||||
options: channel.options,
|
||||
},
|
||||
}
|
||||
channel.options = options
|
||||
channel.save
|
||||
elsif channel.area == 'Twitter::Inbound'
|
||||
channel.area = 'Twitter::Account'
|
||||
channel.options[:adapter] = channel.adapter
|
||||
channel.save
|
||||
end
|
||||
}
|
||||
|
||||
remove_column :channels, :adapter
|
||||
Channel.reset_column_information
|
||||
|
||||
end
|
||||
end
|
25
db/seeds.rb
25
db/seeds.rb
|
@ -1743,21 +1743,28 @@ Overview.create_if_not_exists(
|
|||
)
|
||||
|
||||
Channel.create_if_not_exists(
|
||||
adapter: 'SMTP',
|
||||
area: 'Email::Outbound',
|
||||
area: 'Email::Notification',
|
||||
options: {
|
||||
host: 'host.example.com',
|
||||
user: '',
|
||||
password: '',
|
||||
ssl: true,
|
||||
outbound: {
|
||||
adapter: 'smtp',
|
||||
options: {
|
||||
host: 'host.example.com',
|
||||
user: '',
|
||||
password: '',
|
||||
ssl: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
group_id: 1,
|
||||
active: false,
|
||||
)
|
||||
Channel.create_if_not_exists(
|
||||
adapter: 'Sendmail',
|
||||
area: 'Email::Outbound',
|
||||
options: {},
|
||||
area: 'Email::Notification',
|
||||
options: {
|
||||
outbound: {
|
||||
adapter: 'sendmail',
|
||||
},
|
||||
},
|
||||
active: true,
|
||||
)
|
||||
|
||||
|
|
|
@ -14,26 +14,28 @@ returns on success
|
|||
|
||||
{
|
||||
result: 'ok',
|
||||
inbound: {
|
||||
adapter: 'imap',
|
||||
options: {
|
||||
host: 'imap.gmail.com',
|
||||
port: 993,
|
||||
ssl: true,
|
||||
user: 'some@example.com',
|
||||
password: 'password',
|
||||
settings: {
|
||||
inbound: {
|
||||
adapter: 'imap',
|
||||
options: {
|
||||
host: 'imap.gmail.com',
|
||||
port: 993,
|
||||
ssl: true,
|
||||
user: 'some@example.com',
|
||||
password: 'password',
|
||||
},
|
||||
},
|
||||
},
|
||||
outbound: {
|
||||
adapter: 'smtp',
|
||||
options: {
|
||||
host: 'smtp.gmail.com',
|
||||
port: 25,
|
||||
ssl: true,
|
||||
user: 'some@example.com',
|
||||
password: 'password',
|
||||
outbound: {
|
||||
adapter: 'smtp',
|
||||
options: {
|
||||
host: 'smtp.gmail.com',
|
||||
port: 25,
|
||||
ssl: true,
|
||||
user: 'some@example.com',
|
||||
password: 'password',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
returns on fail
|
||||
|
@ -150,7 +152,7 @@ get result of inbound probe
|
|||
|
||||
result = EmailHelper::Probe.inbound(
|
||||
adapter: 'imap',
|
||||
options: {
|
||||
settings: {
|
||||
host: 'imap.gmail.com',
|
||||
port: 993,
|
||||
ssl: true,
|
||||
|
@ -184,24 +186,22 @@ returns on fail
|
|||
|
||||
def self.inbound(params)
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
result = {
|
||||
result: 'invalid',
|
||||
message: 'Invalid, need adapter!',
|
||||
}
|
||||
return result
|
||||
end
|
||||
adapter = params[:adapter].downcase
|
||||
|
||||
# connection test
|
||||
begin
|
||||
if params[:adapter] =~ /^imap$/i
|
||||
Channel::Imap.new.fetch( { options: params[:options] }, 'check' )
|
||||
elsif params[:adapter] =~ /^pop3$/i
|
||||
Channel::Pop3.new.fetch( { options: params[:options] }, 'check' )
|
||||
else
|
||||
fail "Invalid adapter '#{params[:adapter]}'"
|
||||
|
||||
# validate adapter
|
||||
if adapter !~ /^(imap|pop3)$/
|
||||
fail "Unknown adapter '#{adapter}'"
|
||||
end
|
||||
|
||||
require "channel/driver/#{adapter.to_filename}"
|
||||
|
||||
driver_class = Object.const_get("Channel::Driver::#{adapter.to_classname}")
|
||||
driver_instance = driver_class.new
|
||||
driver_instance.fetch(params[:options], nil, 'check')
|
||||
|
||||
rescue => e
|
||||
message_human = ''
|
||||
translations.each {|key, message|
|
||||
|
@ -238,7 +238,8 @@ get result of outbound probe
|
|||
password: 'password',
|
||||
}
|
||||
},
|
||||
'sender@example.com',
|
||||
'sender_and_recipient_of_test_email@example.com',
|
||||
'subject of probe email',
|
||||
)
|
||||
|
||||
returns on success
|
||||
|
@ -266,15 +267,9 @@ returns on fail
|
|||
|
||||
def self.outbound(params, email, subject = nil)
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
result = {
|
||||
result: 'invalid',
|
||||
message: 'Invalid, need adapter!',
|
||||
}
|
||||
return result
|
||||
end
|
||||
adapter = params[:adapter].downcase
|
||||
|
||||
# prepare test email
|
||||
if subject
|
||||
mail = {
|
||||
:from => email,
|
||||
|
@ -295,29 +290,29 @@ returns on fail
|
|||
# test connection
|
||||
begin
|
||||
|
||||
if params[:adapter] =~ /^smtp$/i
|
||||
# validate adapter
|
||||
if adapter !~ /^(smtp|sendmail)$/
|
||||
fail "Unknown adapter '#{adapter}'"
|
||||
end
|
||||
|
||||
# in case, fill missing params
|
||||
# set smtp defaults
|
||||
if adapter =~ /^smtp$/
|
||||
if !params[:options].key?(:port)
|
||||
params[:options][:port] = 25
|
||||
end
|
||||
if !params[:options].key?(:ssl)
|
||||
params[:options][:ssl] = true
|
||||
end
|
||||
Channel::SMTP.new.send(
|
||||
mail,
|
||||
{
|
||||
options: params[:options]
|
||||
}
|
||||
)
|
||||
elsif params[:adapter] =~ /^sendmail$/i
|
||||
Channel::Sendmail.new.send(
|
||||
mail,
|
||||
nil
|
||||
)
|
||||
else
|
||||
fail "Invalid adapter '#{params[:adapter]}'"
|
||||
end
|
||||
|
||||
require "channel/driver/#{adapter.to_filename}"
|
||||
|
||||
driver_class = Object.const_get("Channel::Driver::#{adapter.to_classname}")
|
||||
driver_instance = driver_class.new
|
||||
driver_instance.send(
|
||||
params[:options],
|
||||
mail,
|
||||
)
|
||||
rescue => e
|
||||
|
||||
# check if sending email was ok, but mailserver rejected
|
||||
|
|
|
@ -26,7 +26,7 @@ get result of inbound probe
|
|||
password: 'password',
|
||||
},
|
||||
},
|
||||
sender: 'sender@example.com',
|
||||
sender: 'sender_and_recipient_of_verify_email@example.com',
|
||||
)
|
||||
|
||||
returns on success
|
||||
|
@ -56,12 +56,13 @@ or
|
|||
def self.email(params)
|
||||
|
||||
# send verify email
|
||||
if !params[:subject]
|
||||
if !params[:subject] || params[:subject].empty?
|
||||
subject = '#' + rand(99_999_999_999).to_s
|
||||
else
|
||||
subject = params[:subject]
|
||||
end
|
||||
result = EmailHelper::Probe.outbound( params[:outbound], params[:sender], subject )
|
||||
puts "VERIFY #{subject.inspect}/#{params[:sender]}"
|
||||
result = EmailHelper::Probe.outbound(params[:outbound], params[:sender], subject)
|
||||
|
||||
# looking for verify email
|
||||
(1..5).each {
|
||||
|
@ -72,9 +73,9 @@ or
|
|||
|
||||
begin
|
||||
if params[:inbound][:adapter] =~ /^imap$/i
|
||||
found = Channel::Imap.new.fetch( { options: params[:inbound][:options] }, 'verify', subject )
|
||||
found = Channel::Driver::Imap.new.fetch(params[:inbound][:options], self, 'verify', subject)
|
||||
else
|
||||
found = Channel::Pop3.new.fetch( { options: params[:inbound][:options] }, 'verify', subject )
|
||||
found = Channel::Driver::Pop3.new.fetch(params[:inbound][:options], self, 'verify', subject)
|
||||
end
|
||||
rescue => e
|
||||
result = {
|
||||
|
|
|
@ -111,7 +111,9 @@ module NotificationFactory
|
|||
content_type = data[:content_type]
|
||||
end
|
||||
|
||||
Channel::EmailSend.send(
|
||||
# get active Email::Outbound Channel and send
|
||||
channel = Channel.find_by(area: 'Email::Notification', active: true)
|
||||
channel.deliver(
|
||||
{
|
||||
# in_reply_to: in_reply_to,
|
||||
from: sender,
|
||||
|
|
|
@ -370,6 +370,19 @@ test( "table test 2", function() {
|
|||
created_at: '2014-06-10T11:17:34.000Z',
|
||||
},
|
||||
])
|
||||
|
||||
App.Channel.configure_delete = true
|
||||
App.Channel.configure_attributes = [
|
||||
{ name: 'adapter', display: 'Type', tag: 'select', multiple: false, null: false, options: { IMAP: 'IMAP', POP3: 'POP3' } },
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: true, options: { true: 'yes', false: 'no' }, translate: true, default: true},
|
||||
{ name: 'options::folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
|
||||
{ name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, nulloption: true, relation: 'Group' },
|
||||
{ name: 'active', display: 'Active', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true },
|
||||
]
|
||||
|
||||
App.Channel.refresh( [
|
||||
{
|
||||
id: 1,
|
||||
|
|
|
@ -44,13 +44,9 @@ class AaaGettingStartedTest < TestCase
|
|||
value: 'test1234äöüß',
|
||||
)
|
||||
click( css: '.js-admin .btn--success' )
|
||||
watch_for(
|
||||
css: '.js-base h2',
|
||||
value: 'Organization',
|
||||
)
|
||||
|
||||
# getting started - base
|
||||
match(
|
||||
watch_for(
|
||||
css: '.js-base h2',
|
||||
value: 'Organization',
|
||||
)
|
||||
|
@ -76,19 +72,27 @@ class AaaGettingStartedTest < TestCase
|
|||
click(
|
||||
css: '.js-base .btn--primary',
|
||||
)
|
||||
|
||||
# getting started - email notification
|
||||
watch_for(
|
||||
css: 'body',
|
||||
value: 'channel',
|
||||
css: '.js-outbound h2',
|
||||
value: 'Email Notification',
|
||||
)
|
||||
location_check(
|
||||
url: '#getting_started/channel',
|
||||
url: '#getting_started/email_notification',
|
||||
)
|
||||
click(
|
||||
css: '.js-outbound .btn--primary',
|
||||
)
|
||||
|
||||
# getting started - create email account
|
||||
match(
|
||||
watch_for(
|
||||
css: '.js-channel h2',
|
||||
value: 'Connect Channels',
|
||||
)
|
||||
location_check(
|
||||
url: '#getting_started/channel',
|
||||
)
|
||||
click(
|
||||
css: '.js-channel .email .provider_name',
|
||||
)
|
||||
|
@ -117,14 +121,10 @@ class AaaGettingStartedTest < TestCase
|
|||
value: 'invite',
|
||||
timeout: 100,
|
||||
)
|
||||
location_check(
|
||||
url: '#getting_started/agents',
|
||||
)
|
||||
|
||||
# invite agent1
|
||||
match(
|
||||
css: 'body',
|
||||
value: 'Invite',
|
||||
location_check(
|
||||
url: '#getting_started/agents',
|
||||
)
|
||||
set(
|
||||
css: '.js-agent input[name="firstname"]',
|
||||
|
|
|
@ -20,6 +20,7 @@ class FacebookTest < ActiveSupport::TestCase
|
|||
|
||||
provider_page_name = 'Hansi Merkurs Hutfabrik'
|
||||
provider_options = {
|
||||
adapter: 'facebook',
|
||||
auth: {
|
||||
access_token: provider_key
|
||||
},
|
||||
|
@ -34,8 +35,7 @@ class FacebookTest < ActiveSupport::TestCase
|
|||
current = Channel.where( adapter: 'Facebook' )
|
||||
current.each(&:destroy)
|
||||
Channel.create(
|
||||
adapter: 'Facebook',
|
||||
area: 'Facebook::Inbound',
|
||||
area: 'Facebook::Account',
|
||||
options: provider_options,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
|
|
|
@ -28,12 +28,12 @@ class TwitterTest < ActiveSupport::TestCase
|
|||
me_bauer_token_secret = 'T8ph5afeSDjGDA9X1ZBlzEvoSiXfN266ZZUMj5UaY'
|
||||
|
||||
# add channel
|
||||
current = Channel.where( adapter: 'Twitter' )
|
||||
current = Channel.where(area: 'Twitter::Account')
|
||||
current.each(&:destroy)
|
||||
Channel.create(
|
||||
adapter: 'Twitter',
|
||||
area: 'Twitter::Inbound',
|
||||
area: 'Twitter::Account',
|
||||
options: {
|
||||
adapter: 'twitter',
|
||||
auth: {
|
||||
consumer_key: consumer_key,
|
||||
consumer_secret: consumer_secret,
|
||||
|
|
Loading…
Reference in a new issue