New version of setup wizard.
This commit is contained in:
parent
7242581723
commit
be8280c1b1
12 changed files with 1312 additions and 473 deletions
|
@ -13,7 +13,7 @@ class Index extends App.ControllerContent
|
|||
|
||||
# if not import backend exists, go ahead
|
||||
if !App.Config.get('ImportPlugins')
|
||||
@navigate 'getting_started/base'
|
||||
@navigate 'getting_started/admin'
|
||||
return
|
||||
|
||||
@fetch()
|
||||
|
@ -51,230 +51,10 @@ class Index extends App.ControllerContent
|
|||
|
||||
App.Config.set( 'getting_started', Index, 'Routes' )
|
||||
|
||||
|
||||
class Base extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
events:
|
||||
'change [name=adapter]': 'toggleAdapter'
|
||||
'submit .base': 'storeUrl'
|
||||
'submit .base-outbound': 'storeOutbound'
|
||||
'submit .base-inbound': 'storeInbound'
|
||||
'click .js-next': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
if @authenticate(true)
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Configure Base'
|
||||
|
||||
@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) =>
|
||||
|
||||
# redirect to login if master user already exists
|
||||
if @Config.get('system_init_done')
|
||||
@navigate '#login'
|
||||
return
|
||||
|
||||
# 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/base')()
|
||||
|
||||
# url
|
||||
url = window.location.origin
|
||||
configureAttributesBase = [
|
||||
{ name: 'url', display: 'System URL (where the system can be reached)', tag: 'input', null: false, placeholder: 'http://yourhost', default: url },
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-url'),
|
||||
model: { configure_attributes: configureAttributesBase, className: '' },
|
||||
)
|
||||
|
||||
# outbound
|
||||
adapters =
|
||||
sendmail: 'Local MTA (Sendmail/Postfix/Exim/...)'
|
||||
smtp: 'SMTP'
|
||||
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: '' },
|
||||
)
|
||||
|
||||
@toggleAdapter()
|
||||
|
||||
# inbound
|
||||
configureAttributesInbound = [
|
||||
{ name: 'email', display: 'Email', tag: 'input', type: 'text', limit: 200, null: false, autocapitalize: false, default: '' },
|
||||
{ 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: 'text', limit: 120, null: false, autocapitalize: false },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true},
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-inbound-settings'),
|
||||
model: { configure_attributes: configureAttributesInbound, className: '' },
|
||||
)
|
||||
|
||||
toggleAdapter: (channel_used = {}) =>
|
||||
adapter = @$('[name=adapter]').val()
|
||||
if adapter is 'smtp'
|
||||
configureAttributesOutbound = [
|
||||
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, 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: 'text', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['password']) },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , translate: true, default: (channel_used['options']&&channel_used['options']['ssl']||true) },
|
||||
{ name: 'options::port', display: 'Port', tag: 'input', type: 'text', limit: 5, null: false, class: 'span1', autocapitalize: false, default: ((channel_used['options']&&channel_used['options']['port']) || 25) },
|
||||
]
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.base-outbound-settings')
|
||||
model: { configure_attributes: configureAttributesOutbound, className: '' }
|
||||
autofocus: true
|
||||
)
|
||||
else
|
||||
@el.find('.base-outbound-settings').html('')
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
form = $(e.target).attr('data-form')
|
||||
console.log('submit', form)
|
||||
@$(".#{form}").trigger('submit')
|
||||
|
||||
showOutbound: =>
|
||||
@$('.base').addClass('hide')
|
||||
@$('.base-outbound').removeClass('hide')
|
||||
@$('.base-inbound').addClass('hide')
|
||||
@$('.wizard-controls .btn').text('Check').attr('data-form', 'base-outbound').addClass('btn--primary').removeClass('btn--danger btn--success')
|
||||
@enable( @$('.btn') )
|
||||
|
||||
showInbound: =>
|
||||
@$('.base').addClass('hide')
|
||||
@$('.base-outbound').addClass('hide')
|
||||
@$('.base-inbound').removeClass('hide')
|
||||
@$('.wizard-controls .btn').text('Check').attr('data-form', 'base-inbound').addClass('btn--primary').removeClass('btn--danger btn--success')
|
||||
@enable( @$('.btn') )
|
||||
|
||||
storeUrl: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
console.log('submit', params, e)
|
||||
@disable(e)
|
||||
|
||||
@ajax(
|
||||
id: 'base_url'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/base_url'
|
||||
data: JSON.stringify( {url:params.url} )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@$('.wizard-controls .btn').text('Done').removeClass('btn--primary btn--danger').addClass('btn--success')
|
||||
@delay( @showOutbound, 1500 )
|
||||
else
|
||||
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary btn--success')
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
storeOutbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
@disable(e)
|
||||
|
||||
@ajax(
|
||||
id: 'base_outbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/base_outbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@$('.wizard-controls .btn').text('Done').removeClass('btn--primary btn--danger').addClass('btn--success')
|
||||
@delay( @showInbound, 1500 )
|
||||
else
|
||||
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary btn--success')
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
storeInbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
@disable(e)
|
||||
|
||||
console.log('PA', params)
|
||||
|
||||
@ajax(
|
||||
id: 'base_inbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/base_inbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
if data.result is 'ok'
|
||||
@$('.wizard-controls .btn').text('Done').removeClass('btn--primary btn--danger').addClass('btn--success')
|
||||
@delay( @goToAdmin, 1500 )
|
||||
else
|
||||
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary btn--success')
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
disable: (e) =>
|
||||
@formDisable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', true)
|
||||
|
||||
enable: (e) =>
|
||||
@formEnable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', false)
|
||||
|
||||
goToAdmin: =>
|
||||
@navigate 'getting_started/admin'
|
||||
|
||||
App.Config.set( 'getting_started/base', Base, 'Routes' )
|
||||
|
||||
|
||||
class Admin extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
events:
|
||||
'submit .js-admin': 'submit'
|
||||
'submit form': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
@ -295,13 +75,10 @@ class Admin extends App.ControllerContent
|
|||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'getting_started',
|
||||
type: 'GET',
|
||||
url: @apiPath + '/getting_started',
|
||||
data: {
|
||||
# view: @view,
|
||||
}
|
||||
processData: true,
|
||||
id: 'getting_started'
|
||||
type: 'GET'
|
||||
url: @apiPath + '/getting_started'
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# redirect to login if master user already exists
|
||||
|
@ -384,29 +161,35 @@ class Admin extends App.ControllerContent
|
|||
relogin: (data, status, xhr) =>
|
||||
@log 'notice', 'relogin:success', data
|
||||
|
||||
# add notify
|
||||
App.Event.trigger 'notify:removeall'
|
||||
|
||||
@navigate 'getting_started/agents'
|
||||
@navigate 'getting_started/base'
|
||||
|
||||
App.Config.set( 'getting_started/admin', Admin, 'Routes' )
|
||||
|
||||
class Agent extends App.ControllerContent
|
||||
className: 'getstarted'
|
||||
|
||||
class Base extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
elements:
|
||||
'.logo-preview': 'logoPreview'
|
||||
|
||||
events:
|
||||
'submit .js-agent': 'submit'
|
||||
'submit form': 'submit'
|
||||
'change .js-upload': 'onLogoPick'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
return if !@authenticate()
|
||||
# redirect if we are not admin
|
||||
if !@authenticate(true)
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Invite Agents'
|
||||
@title 'Configure Base'
|
||||
|
||||
@fetch()
|
||||
|
||||
|
||||
release: =>
|
||||
@el.removeClass('fit getstarted')
|
||||
|
||||
|
@ -420,11 +203,409 @@ class Agent extends App.ControllerContent
|
|||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# redirect to login if master user already exists
|
||||
if !data.setup_done
|
||||
@navigate '#getting_started/admin'
|
||||
# check if import is active
|
||||
if data.import_mode == true
|
||||
@navigate '#import/' + data.import_backend
|
||||
return
|
||||
|
||||
# render page
|
||||
@render()
|
||||
)
|
||||
|
||||
render: ->
|
||||
|
||||
fqdn = App.Config.get('fqdn')
|
||||
http_type = App.Config.get('http_type')
|
||||
if !fqdn || fqdn is 'zammad.example.com'
|
||||
url = window.location.origin
|
||||
else
|
||||
url = "#{http_type}://#{fqdn}"
|
||||
|
||||
organization = App.Config.get('organization')
|
||||
@html App.view('getting_started/base')(
|
||||
url: url
|
||||
organization: organization
|
||||
)
|
||||
|
||||
onLogoPick: (event) =>
|
||||
reader = new FileReader()
|
||||
|
||||
reader.onload = (e) =>
|
||||
@logoPreview.attr('src', e.target.result)
|
||||
|
||||
file = event.target.files[0]
|
||||
|
||||
@hideAlerts()
|
||||
|
||||
# if no file is given, about in file upload was used
|
||||
if !file
|
||||
return
|
||||
|
||||
maxSiteInMb = 3
|
||||
if file.size && file.size > 1024 * 1024 * maxSiteInMb
|
||||
@showAlert( 'logo', App.i18n.translateInline( 'File too big, max. %s MB allowed.', maxSiteInMb ) )
|
||||
@logoPreview.attr( 'src', '' )
|
||||
return
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
params['logo'] = @logoPreview.attr('src')
|
||||
|
||||
@hideAlerts()
|
||||
@disable(e)
|
||||
|
||||
@ajax(
|
||||
id: 'getting_started_base'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/base'
|
||||
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 )
|
||||
@navigate 'getting_started/channel'
|
||||
else
|
||||
for key, value of data.messages
|
||||
@showAlert( key, value )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
hideAlerts: =>
|
||||
@$('.form-group').removeClass('has-error')
|
||||
@$('.alert').addClass('hide')
|
||||
|
||||
showAlert: (field, message) =>
|
||||
@$("[name=#{field}]").closest('.form-group').addClass('has-error')
|
||||
@$("[name=#{field}]").closest('.form-group').find('.alert').removeClass('hide').text( App.i18n.translateInline( message ) )
|
||||
|
||||
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/base', Base, 'Routes' )
|
||||
|
||||
class Channel extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# redirect if we are not admin
|
||||
if !@authenticate(true)
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Connect Channels'
|
||||
|
||||
@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/channel')(
|
||||
adapters: @adapters
|
||||
)
|
||||
|
||||
App.Config.set( 'getting_started/channel', Channel, 'Routes' )
|
||||
|
||||
|
||||
class ChannelEmail extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
events:
|
||||
'submit .js-intro': 'emailProbe'
|
||||
'submit .js-inbound': 'storeInbound'
|
||||
'change .js-outbound [name=adapter]': 'toggleAdapter'
|
||||
'submit .js-outbound': 'storeOutbound'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# redirect if we are not admin
|
||||
if !@authenticate(true)
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Email Account'
|
||||
|
||||
# store account settings
|
||||
@account =
|
||||
inbound: {}
|
||||
outbound: {}
|
||||
meta: {}
|
||||
|
||||
@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')()
|
||||
|
||||
# outbound
|
||||
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: '' },
|
||||
)
|
||||
@toggleAdapter()
|
||||
|
||||
# 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: 'text', limit: 120, null: false, autocapitalize: false },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' }, translate: true, default: true},
|
||||
]
|
||||
new App.ControllerForm(
|
||||
el: @$('.base-inbound-settings'),
|
||||
model: { configure_attributes: configureAttributesInbound, className: '' },
|
||||
)
|
||||
|
||||
toggleAdapter: (channel_used = {}) =>
|
||||
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, 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: 'text', limit: 120, null: true, autocapitalize: false, default: (channel_used['options']&&channel_used['options']['password']) },
|
||||
{ name: 'options::ssl', display: 'SSL', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , translate: true, default: (channel_used['options']&&channel_used['options']['ssl']||true) },
|
||||
{ name: 'options::port', display: 'Port', tag: 'input', type: 'text', limit: 5, null: false, class: 'span1', autocapitalize: false, default: ((channel_used['options']&&channel_used['options']['port']) || 25) },
|
||||
]
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.base-outbound-settings')
|
||||
model: { configure_attributes: configureAttributesOutbound, className: '' }
|
||||
)
|
||||
else
|
||||
@el.find('.base-outbound-settings').html('')
|
||||
|
||||
emailProbe: (e) =>
|
||||
e.preventDefault()
|
||||
params = @formParam(e.target)
|
||||
|
||||
# remember account settings
|
||||
@account.meta = params
|
||||
|
||||
@disable(e)
|
||||
@$('.js-probe .js-email').text( params.email )
|
||||
@showSlide('js-probe')
|
||||
|
||||
@ajax(
|
||||
id: 'email_probe'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/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
|
||||
@showSlide('js-inbound')
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
@showSlide('js-intro')
|
||||
)
|
||||
|
||||
showSlide: (name) =>
|
||||
@$('.setup.wizard').addClass('hide')
|
||||
@$(".setup.wizard.#{name}").removeClass('hide')
|
||||
|
||||
storeOutbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
params['email'] = @account['meta']['email']
|
||||
@disable(e)
|
||||
|
||||
@hideAlert('js-outbound')
|
||||
|
||||
@ajax(
|
||||
id: 'email_outbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/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
|
||||
@showAlert('js-outbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
storeInbound: (e) =>
|
||||
e.preventDefault()
|
||||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
@disable(e)
|
||||
|
||||
@hideAlert('js-inbound')
|
||||
|
||||
@ajax(
|
||||
id: 'email_inbound'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_inbound'
|
||||
data: JSON.stringify( params )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@showSlide('js-outbound')
|
||||
|
||||
# remember account settings
|
||||
@account.inbound = params
|
||||
else
|
||||
@showAlert('js-inbound', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
verify: (account) =>
|
||||
@showSlide('js-verify')
|
||||
|
||||
@hideAlert('js-verify')
|
||||
|
||||
@ajax(
|
||||
id: 'email_verify'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/getting_started/email_verify'
|
||||
data: JSON.stringify( account )
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@navigate 'getting_started/agents'
|
||||
else
|
||||
@showAlert('js-verify', data.message_human || data.message )
|
||||
@enable(e)
|
||||
fail: =>
|
||||
@enable(e)
|
||||
)
|
||||
|
||||
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/channel/email', ChannelEmail, 'Routes' )
|
||||
|
||||
|
||||
class Agent extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
return if !@authenticate()
|
||||
|
||||
# set title
|
||||
@title 'Invite Agents'
|
||||
|
||||
@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
|
||||
|
@ -495,4 +676,33 @@ class Agent extends App.ControllerContent
|
|||
}
|
||||
)
|
||||
|
||||
App.Config.set( 'getting_started/agents', Agent, 'Routes' )
|
||||
App.Config.set( 'getting_started/agents', Agent, 'Routes' )
|
||||
|
||||
class Channel extends App.ControllerContent
|
||||
className: 'getstarted fit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
return if !@authenticate()
|
||||
|
||||
# set title
|
||||
@title 'Setup Finished'
|
||||
|
||||
@render()
|
||||
|
||||
release: =>
|
||||
@el.removeClass('fit getstarted')
|
||||
|
||||
render: ->
|
||||
@html App.view('getting_started/finish')()
|
||||
@delay(
|
||||
=> @$('.wizard-slide').addClass('hide')
|
||||
2300
|
||||
)
|
||||
@delay(
|
||||
=> @navigate '#'
|
||||
4300
|
||||
)
|
||||
|
||||
App.Config.set( 'getting_started/finish', Channel, 'Routes' )
|
|
@ -1,14 +1,13 @@
|
|||
<div class="fullHeight flex vertical center justified getstarted fit">
|
||||
<div class="hero-unit">
|
||||
<ol class="horizontal tabs progress-tabs tabs-condensed">
|
||||
<li class="configure_channels tab u-textTruncate"><%- @T( 'Configure Base' ) %></li>
|
||||
<li class="create_admin tab u-textTruncate active"><%- @T( 'Create Admin' ) %></li>
|
||||
<li class="invite_agents tab u-textTruncate"><%- @T( 'Invite Agents' ) %></li>
|
||||
</ol>
|
||||
<div class="master-user hero-left">
|
||||
<form class="form-stacked js-admin">
|
||||
<button type="submit" class="btn btn--primary submit pull-right"><%- @T( 'Create Admin' ) %></button>
|
||||
</form>
|
||||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<form class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Administrator Account') %></h2>
|
||||
<div class="wizard-body vertical justified js-admin"></div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="subtle-link" href="#getting_started"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--success align-right"><%- @T( 'Create' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,16 +1,13 @@
|
|||
<div class="fullHeight flex vertical center justified getstarted">
|
||||
<div class="hero-unit">
|
||||
<ol class="horizontal tabs progress-tabs tabs-condensed">
|
||||
<li class="configure_channels tab u-textTruncate"><%- @T( 'Configure Base' ) %></li>
|
||||
<li class="create_admin tab u-textTruncate"><%- @T( 'Create Admin' ) %></li>
|
||||
<li class="invite_agents tab u-textTruncate active"><%- @T( 'Invite Agents' ) %></li>
|
||||
</ol>
|
||||
<div class="master-user hero-left">
|
||||
<form class="form-stacked js-agent">
|
||||
<div class="form-controls">
|
||||
<button type="submit" class="btn btn--primary submit pull-right"><%- @T( 'Send Invitation' ) %></button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<form class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Invite Colleagues') %></h2>
|
||||
<div class="wizard-body vertical justified js-agent"></div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--primary align-left" href="#getting_started/finish"><%- @T( 'Continue' ) %></a>
|
||||
<button class="btn btn--success align-right"><%- @T( 'Invite' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,31 +1,32 @@
|
|||
<div class="fullHeight flex vertical center justified">
|
||||
<div class="hero-unit">
|
||||
<ol class="horizontal tabs progress-tabs tabs-condensed">
|
||||
<li class="configure_channels tab u-textTruncate active"><%- @T( 'Configure Base' ) %></li>
|
||||
<li class="create_admin tab u-textTruncate"><%- @T( 'Create Admin' ) %></li>
|
||||
<li class="invite_agents tab u-textTruncate"><%- @T( 'Invite Agents' ) %></li>
|
||||
</ol>
|
||||
|
||||
<form class="base">
|
||||
<div class="base-url"></div>
|
||||
</form>
|
||||
|
||||
|
||||
<form class="base-outbound hide">
|
||||
<h2><%- @T('E-Mail Outbound') %></h2>
|
||||
<div class="base-outbound-type"></div>
|
||||
<div class="base-outbound-settings"></div>
|
||||
</form>
|
||||
|
||||
<form class="base-inbound hide">
|
||||
<h2><%- @T('E-Mail Inbound') %></h2>
|
||||
<div class="base-inbound-settings"></div>
|
||||
</form>
|
||||
|
||||
<div class="wizard-controls horizontal center">
|
||||
<a class="subtle-link" href="#getting_started"><%- @T('Go Back') %></a>
|
||||
<div class="btn btn--primary js-next align-right" data-form="base"><%- @T('Next') %></div>
|
||||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<form class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Organization') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Organization Name') %></label>
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<input class="form-control" name="organization" placeholder="<%- @Ti('Company Inc.') %>" value="<%= @organization %>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Logo') %></label>
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<img class="logo-preview" src="" data-placeholder="<%- @T('Your Logo') %>">
|
||||
<div class="btn btn--success fileUpload"><%- @T('Upload') %><input type="file" class="js-upload" name="logo" accept="image/*"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('System URL') %></label>
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<input type="text" class="form-control" name="url" value="<%= @url %>" placeholder="http://zammad.example.com" required>
|
||||
<p class="help-block">The URL to this installation of Zammad.</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Next' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,25 @@
|
|||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<form class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Connect Channels') %></h2>
|
||||
<div class="wizard-body vertical center">
|
||||
<p class="help-block help-block--center"><%- @T('Setup the communication channels you want to use with your Zammad.') %></p>
|
||||
<div class="wizard-buttonList vertical">
|
||||
|
||||
<% for adapter in @adapters: %>
|
||||
<div class="btn auth_provider auth_provider--wide <%= adapter.class %>">
|
||||
<div class="<%= adapter.class %> provider_icon"></div>
|
||||
<a class="provider_name" href="<%= adapter.link %>"><%- @T( adapter.name ) %></a>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="subtle-link" href="#getting_started/base"><%- @T('Go Back') %></a>
|
||||
<a class="btn align-right" href="#getting_started/finish"><%- @T( 'Skip' ) %></a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,82 @@
|
|||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
|
||||
<form class="setup wizard js-intro">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Email Account') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Full Name') %></label>
|
||||
<input type="text" class="form-control" value="" name="realname" placeholder="<%- @T('Organization Support') %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Email') %></label>
|
||||
<input type="email" class="form-control" value="" name="email" placeholder="<%- @T('support@example.com') %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- @T('Password') %></label>
|
||||
<input type="password" class="form-control" name="password" value="">
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="subtle-link" href="#getting_started/channel"><%- @T('Go Back') %></a>
|
||||
<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-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('E-Mail Inbound') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
<div class="base-inbound-settings"></div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="subtle-link" href="#getting_started/channel"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="setup wizard hide js-outbound">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('E-Mail 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 class="wizard-controls center">
|
||||
<a class="subtle-link" href="#getting_started/channel"><%- @T('Go Back') %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T( 'Continue' ) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<form class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<h2><%- @T('Setup Finished') %></h2>
|
||||
<div class="wizard-body vertical justified">
|
||||
<p class="wizard-loadingText">
|
||||
<span class="loading icon"></span> Starting Zammad
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,12 +1,12 @@
|
|||
<div class="main flex centered darkBackground">
|
||||
<div class="import wizard hero-unit">
|
||||
<div class="wizard-slide vertical" data-slide="home">
|
||||
<h2><%- @T('Welcome to %s', @C('product_name') ) %></h2>
|
||||
<div class="wizard-body flex vertical centered">
|
||||
<div class="vertical">
|
||||
<a class="btn btn--primary" href="#import"><%- @T('Import from other System') %></a>
|
||||
<a class="btn btn--success" href="#getting_started/base"><%- @T('Setup new System') %></a>
|
||||
</div>
|
||||
<div class="main flex vertical centered darkBackground">
|
||||
<img class="zammad full logo" src="<%= @C('image_path') + '/' + 'full logo on dark.svg' %>" alt="Zammad">
|
||||
<div class="setup wizard">
|
||||
<div class="wizard-slide">
|
||||
<div class="wizard-body vertical centered">
|
||||
<a class="btn btn--primary" href="#getting_started/admin"><%- @T('Setup new System') %></a>
|
||||
</div>
|
||||
<div class="wizard-aside">
|
||||
<%- @T('Or') %> <span class="u-clickable u-highlight"><a href="#import"><%- @T('migrate from another system') %></a></span>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4203,12 +4203,12 @@ label + .wizard-buttonList {
|
|||
display: block;
|
||||
background: hsl(0,0%,95%);
|
||||
width: 100%;
|
||||
height: 130px;
|
||||
height: 60px;
|
||||
margin-bottom: 10px;
|
||||
content: "";
|
||||
color: hsl(0,0%,60%);
|
||||
@extend .centered;
|
||||
|
||||
|
||||
&:after {
|
||||
content: attr(data-placeholder);
|
||||
}
|
||||
|
@ -4216,8 +4216,8 @@ label + .wizard-buttonList {
|
|||
|
||||
.setup.wizard .logo-preview:not([src=""]) {
|
||||
content: initial;
|
||||
max-width: 100%;
|
||||
max-height: 130px;
|
||||
max-width: 240px;
|
||||
max-height: 60px;
|
||||
margin: 0 auto 15px;
|
||||
background: none;
|
||||
width: auto;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'resolv'
|
||||
|
||||
class GettingStartedController < ApplicationController
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
GET /api/v1/getting_started.json
|
||||
GET /api/v1/getting_started
|
||||
|
||||
Response:
|
||||
{
|
||||
|
@ -23,7 +25,7 @@ Response:
|
|||
}
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
||||
curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
|
||||
|
||||
=end
|
||||
|
||||
|
@ -49,45 +51,634 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
}
|
||||
end
|
||||
|
||||
def base_url
|
||||
return if setup_done_response
|
||||
def base
|
||||
|
||||
# validate
|
||||
# check admin permissions
|
||||
return if deny_if_not_role('Admin')
|
||||
|
||||
# validate url
|
||||
messages = {}
|
||||
if !params[:url] ||params[:url] !~ /^(http|https):\/\/.+?$/
|
||||
messages[:url] = 'A URL looks like http://zammad.example.com'
|
||||
end
|
||||
|
||||
# validate organization
|
||||
if !params[:organization] || params[:organization].empty?
|
||||
messages[:organization] = 'Invalid!'
|
||||
end
|
||||
|
||||
# validate image
|
||||
if params[:logo] && !params[:logo].empty?
|
||||
content_type = nil
|
||||
content = nil
|
||||
|
||||
# data:image/png;base64
|
||||
if params[:logo] =~ /^data:(.+?);base64,(.+?)$/
|
||||
content_type = $1
|
||||
content = $2
|
||||
end
|
||||
|
||||
if !content_type || !content
|
||||
messages[:logo] = 'Unable to process image upload.'
|
||||
end
|
||||
end
|
||||
|
||||
if !messages.empty?
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => 'Invalid!',
|
||||
:result => 'invalid',
|
||||
:messages => messages,
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# split url in http_type and fqdn
|
||||
settings = {}
|
||||
if params[:url] =~ /^(http|https):\/\/(.+?)$/
|
||||
Setting.set('http_type', $1)
|
||||
settings[:http_type] = $1
|
||||
Setting.set('fqdn', $2)
|
||||
settings[:fqdn] = $2
|
||||
end
|
||||
|
||||
# save organization
|
||||
Setting.set('organization', params[:organization])
|
||||
settings[:organization] = params[:organization]
|
||||
|
||||
# save image
|
||||
if params[:logo] && !params[:logo].empty?
|
||||
content_type = nil
|
||||
content = nil
|
||||
|
||||
# data:image/png;base64
|
||||
if params[:logo] =~ /^data:(.+?);base64,(.+?)$/
|
||||
content_type = $1
|
||||
content = Base64.decode64($2)
|
||||
end
|
||||
Store.remove( :object => 'System::Logo', :o_id => 1 )
|
||||
Store.add(
|
||||
:object => 'System::Logo',
|
||||
:o_id => 1,
|
||||
:data => content,
|
||||
:filename => 'image',
|
||||
:preferences => {
|
||||
'Content-Type' => content_type
|
||||
},
|
||||
# :created_by_id => self.updated_by_id,
|
||||
)
|
||||
end
|
||||
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
:settings => settings,
|
||||
}
|
||||
end
|
||||
|
||||
def email_probe
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role('Admin')
|
||||
|
||||
# validation
|
||||
user = nil
|
||||
domain = nil
|
||||
if params[:email] =~ /^(.+?)@(.+?)$/
|
||||
user = $1
|
||||
domain = $2
|
||||
end
|
||||
|
||||
if !user || !domain
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
:result => 'invalid',
|
||||
:messages => {
|
||||
:email => 'Invalid email.'
|
||||
},
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# check domain based attributes
|
||||
providerMap = {
|
||||
:google => {
|
||||
:domain => 'gmail.com|googlemail.com|gmail.de',
|
||||
:inbound => {
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => 'imap.gmail.com',
|
||||
:port => '993',
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
:outbound => {
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => 'smtp.gmail.com',
|
||||
:port => '465',
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# probe based on email domain and mx
|
||||
domains = [domain]
|
||||
mail_exchangers = mxers(domain)
|
||||
if mail_exchangers && mail_exchangers[0]
|
||||
puts "MX #{mail_exchangers} - #{mail_exchangers[0][0]}"
|
||||
end
|
||||
if mail_exchangers && mail_exchangers[0] && mail_exchangers[0][0]
|
||||
domains.push mail_exchangers[0][0]
|
||||
end
|
||||
providerMap.each {|provider, settings|
|
||||
domains.each {|domain_to_check|
|
||||
if domain_to_check =~ /#{settings[:domain]}/i
|
||||
|
||||
# probe inbound
|
||||
result = email_probe_inbound( settings[:inbound] )
|
||||
if !result
|
||||
render :json => result
|
||||
return
|
||||
end
|
||||
|
||||
# probe outbound
|
||||
result = email_probe_outbound( settings[:outbound], params[:email] )
|
||||
if result[:result] != 'ok'
|
||||
render :json => result
|
||||
return
|
||||
end
|
||||
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
:account => settings,
|
||||
}
|
||||
return
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
# probe inbound
|
||||
inboundMap = []
|
||||
if mail_exchangers && mail_exchangers[0] && mail_exchangers[0][0]
|
||||
inboundMx = [
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
]
|
||||
inboundMap = inboundMap + inboundMx
|
||||
end
|
||||
inboundAuto = [
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => "imap.#{domain}",
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'imap',
|
||||
:options => {
|
||||
:host => "imap.#{domain}",
|
||||
:port => 993,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "pop.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "pop.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "pop3.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'pop3',
|
||||
:options => {
|
||||
:host => "pop3.#{domain}",
|
||||
:port => 995,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
]
|
||||
inboundMap = inboundMap + inboundAuto
|
||||
settings = {}
|
||||
success = false
|
||||
inboundMap.each {|config|
|
||||
puts "PROBE: #{config.inspect}"
|
||||
result = email_probe_inbound( config )
|
||||
puts "RESULT: #{result.inspect}"
|
||||
if !result
|
||||
success = true
|
||||
settings[:inbound] = config
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
if !success
|
||||
render :json => {
|
||||
:result => 'failed',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# probe outbound
|
||||
outboundMap = []
|
||||
if mail_exchangers && mail_exchangers[0] && mail_exchangers[0][0]
|
||||
outboundMx = [
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => mail_exchangers[0][0],
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
]
|
||||
outboundMap = outboundMap + outboundMx
|
||||
end
|
||||
outboundAuto = [
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "mail.#{domain}",
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "smtp.#{domain}",
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "smtp.#{domain}",
|
||||
:port => 25,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "smtp.#{domain}",
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => user,
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
{
|
||||
:adapter => 'smtp',
|
||||
:options => {
|
||||
:host => "smtp.#{domain}",
|
||||
:port => 465,
|
||||
:ssl => true,
|
||||
:user => params[:email],
|
||||
:password => params[:password],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
success = false
|
||||
outboundMap.each {|config|
|
||||
puts "PROBE: #{config.inspect}"
|
||||
result = email_probe_outbound( config, params[:email] )
|
||||
puts "RESULT: #{result.inspect}"
|
||||
if result[:result] == 'ok'
|
||||
success = true
|
||||
settings[:outbound] = config
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
if !success
|
||||
render :json => {
|
||||
:result => 'failed',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => 'Unable to parse url!',
|
||||
:result => 'ok',
|
||||
:setting => settings,
|
||||
}
|
||||
end
|
||||
|
||||
def base_outbound
|
||||
return if setup_done_response
|
||||
def email_outbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role('Admin')
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# connection test
|
||||
result = email_probe_outbound( params, params[:email] )
|
||||
if result[:result] != 'ok'
|
||||
render :json => result
|
||||
return
|
||||
end
|
||||
|
||||
# return result
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
}
|
||||
end
|
||||
|
||||
def email_inbound
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role('Admin')
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
# connection test
|
||||
result = email_probe_inbound( params )
|
||||
if result
|
||||
render :json => result
|
||||
return
|
||||
end
|
||||
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
}
|
||||
end
|
||||
|
||||
def email_verify
|
||||
|
||||
# check admin permissions
|
||||
return if deny_if_not_role('Admin')
|
||||
|
||||
# send verify email to inbox
|
||||
subject = '#' + rand(99999999999).to_s
|
||||
Channel::EmailSend.new.send(
|
||||
{
|
||||
:from => params[:meta][:email],
|
||||
:to => params[:meta][:email],
|
||||
:subject => "Zammad Getting started Test Email #{subject}",
|
||||
:body => '.',
|
||||
'x-zammad-ignore' => 'true',
|
||||
}
|
||||
)
|
||||
(1..5).each {|loop|
|
||||
sleep 10
|
||||
|
||||
# fetch mailbox
|
||||
found = nil
|
||||
if params[:inbound][:adapter] =~ /^imap$/i
|
||||
found = Channel::IMAP.new.fetch( { :options => params[:inbound][:options] }, 'verify', subject )
|
||||
else
|
||||
found = Channel::POP3.new.fetch( { :options => params[:inbound][:options] }, 'verify', subject )
|
||||
end
|
||||
|
||||
if found && found == 'verify ok'
|
||||
|
||||
# remember address
|
||||
address = EmailAddress.all.first
|
||||
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',
|
||||
}
|
||||
return
|
||||
end
|
||||
}
|
||||
|
||||
# check dilivery for 30 sek.
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => 'Verification Email not found in mailbox.',
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def email_probe_outbound(params, email)
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
result = {
|
||||
:result => 'invalid',
|
||||
:message => 'Invalid!',
|
||||
}
|
||||
return
|
||||
return result
|
||||
end
|
||||
|
||||
# test connection
|
||||
|
@ -101,7 +692,7 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
begin
|
||||
Channel::SMTP.new.send(
|
||||
{
|
||||
:from => 'me@example.com',
|
||||
:from => email,
|
||||
:to => 'emailtrytest@znuny.com',
|
||||
:subject => 'test',
|
||||
:body => 'test',
|
||||
|
@ -118,10 +709,10 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
}
|
||||
whiteMap.each {|key, message|
|
||||
if e.message =~ /#{Regexp.escape(key)}/i
|
||||
render :json => {
|
||||
result = {
|
||||
:result => 'ok',
|
||||
}
|
||||
return
|
||||
return result
|
||||
end
|
||||
}
|
||||
message_human = ''
|
||||
|
@ -130,75 +721,48 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
message_human = message
|
||||
end
|
||||
}
|
||||
render :json => {
|
||||
result = {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
Channel::Sendmail.new.send(
|
||||
{
|
||||
:from => 'me@example.com',
|
||||
:to => 'emailtrytest@znuny.com',
|
||||
:subject => 'test',
|
||||
:body => 'test',
|
||||
},
|
||||
nil
|
||||
)
|
||||
rescue Exception => e
|
||||
message_human = ''
|
||||
translationMap.each {|key, message|
|
||||
if e.message =~ /#{Regexp.escape(key)}/i
|
||||
message_human = message
|
||||
end
|
||||
}
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return
|
||||
return result
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# save settings
|
||||
if params[:adapter] == 'smtp'
|
||||
smtp = Channel.where( :adapter => 'SMTP', :area => 'Email::Outbound' ).first
|
||||
smtp.options = params[: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
|
||||
begin
|
||||
Channel::Sendmail.new.send(
|
||||
{
|
||||
:from => email,
|
||||
:to => 'emailtrytest@znuny.com',
|
||||
:subject => 'test',
|
||||
:body => 'test',
|
||||
},
|
||||
nil
|
||||
)
|
||||
rescue Exception => e
|
||||
message_human = ''
|
||||
translationMap.each {|key, message|
|
||||
if e.message =~ /#{Regexp.escape(key)}/i
|
||||
message_human = message
|
||||
end
|
||||
}
|
||||
result = {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return result
|
||||
end
|
||||
|
||||
# return result
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
}
|
||||
return
|
||||
end
|
||||
|
||||
def base_inbound
|
||||
return if setup_done_response
|
||||
def email_probe_inbound(params)
|
||||
|
||||
# validate params
|
||||
if !params[:adapter]
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
}
|
||||
return
|
||||
raise 'need :adapter param'
|
||||
end
|
||||
|
||||
# connection test
|
||||
|
@ -208,7 +772,7 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
'No route to host' => 'No route to host!',
|
||||
'Connection refused' => 'Connection refused!',
|
||||
}
|
||||
if params[:adapter] == 'IMAP'
|
||||
if params[:adapter] =~ /^imap$/i
|
||||
begin
|
||||
Channel::IMAP.new.fetch( { :options => params[:options] }, 'check' )
|
||||
rescue Exception => e
|
||||
|
@ -218,103 +782,42 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
|
|||
message_human = message
|
||||
end
|
||||
}
|
||||
render :json => {
|
||||
result = {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return
|
||||
end
|
||||
else
|
||||
begin
|
||||
Channel::POP3.new.fetch( { :options => params[:options] }, 'check' )
|
||||
rescue Exception => e
|
||||
message_human = ''
|
||||
translationMap.each {|key, message|
|
||||
if e.message =~ /#{Regexp.escape(key)}/i
|
||||
message_human = message
|
||||
end
|
||||
}
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return
|
||||
return result
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# send verify email to inbox
|
||||
subject = '#' + rand(99999999999).to_s
|
||||
Channel::EmailSend.new.send(
|
||||
{
|
||||
:from => params[:email],
|
||||
:to => params[:email],
|
||||
:subject => "Zammad Getting started Test Email #{subject}",
|
||||
:body => '.',
|
||||
'x-zammad-ignore' => 'true',
|
||||
}
|
||||
)
|
||||
(1..5).each {|loop|
|
||||
sleep 10
|
||||
|
||||
# fetch mailbox
|
||||
found = nil
|
||||
if params[:adapter] == 'IMAP'
|
||||
found = Channel::IMAP.new.fetch( { :options => params[:options] }, 'verify', subject )
|
||||
else
|
||||
found = Channel::POP3.new.fetch( { :options => params[:options] }, 'verify', subject )
|
||||
end
|
||||
|
||||
if found && found == 'verify ok'
|
||||
|
||||
# remember address
|
||||
address = EmailAddress.all.first
|
||||
if address
|
||||
address.update_attributes(
|
||||
:realname => 'Zammad',
|
||||
:email => params[:email],
|
||||
:active => 1,
|
||||
:updated_by_id => 1,
|
||||
:created_by_id => 1,
|
||||
)
|
||||
else
|
||||
EmailAddress.create(
|
||||
:realname => 'Zammad',
|
||||
:email => params[:email],
|
||||
:active => 1,
|
||||
:updated_by_id => 1,
|
||||
:created_by_id => 1,
|
||||
)
|
||||
begin
|
||||
Channel::POP3.new.fetch( { :options => params[:options] }, 'check' )
|
||||
rescue Exception => e
|
||||
message_human = ''
|
||||
translationMap.each {|key, message|
|
||||
if e.message =~ /#{Regexp.escape(key)}/i
|
||||
message_human = message
|
||||
end
|
||||
|
||||
# store mailbox
|
||||
Channel.create(
|
||||
:area => 'Email::Inbound',
|
||||
:adapter => params[:adapter],
|
||||
:options => params[:options],
|
||||
:group_id => 1,
|
||||
:active => 1,
|
||||
:updated_by_id => 1,
|
||||
:created_by_id => 1,
|
||||
)
|
||||
|
||||
render :json => {
|
||||
:result => 'ok',
|
||||
}
|
||||
return
|
||||
end
|
||||
}
|
||||
|
||||
# check dilivery for 30 sek.
|
||||
render :json => {
|
||||
:result => 'invalid',
|
||||
:message => 'Verification Email not found in mailbox.',
|
||||
}
|
||||
}
|
||||
result = {
|
||||
:result => 'invalid',
|
||||
:message => e.message,
|
||||
:message_human => message_human,
|
||||
}
|
||||
return result
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
private
|
||||
def mxers(domain)
|
||||
mxs = Resolv::DNS.open do |dns|
|
||||
ress = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
|
||||
ress.map { |r| [r.exchange.to_s, IPSocket::getaddress(r.exchange.to_s), r.preference] }
|
||||
end
|
||||
mxs
|
||||
end
|
||||
|
||||
def setup_done
|
||||
#return false
|
||||
|
|
|
@ -15,8 +15,15 @@ class Channel::POP3 < Channel::EmailParser
|
|||
puts "fetching pop3 (#{channel[:options][:host]}/#{channel[:options][:user]} port=#{port},ssl=#{ssl})"
|
||||
|
||||
@pop = Net::POP3.new( channel[:options][:host], port )
|
||||
|
||||
# on check, reduce open_timeout to have faster probing
|
||||
if check_type == 'check'
|
||||
@pop.open_timeout = 5
|
||||
@pop.read_timeout = 6
|
||||
end
|
||||
|
||||
if ssl
|
||||
@pop.enable_ssl
|
||||
@pop.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
|
||||
end
|
||||
@pop.start( channel[:options][:user], channel[:options][:password] )
|
||||
if check_type == 'check'
|
||||
|
|
|
@ -2,9 +2,11 @@ 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/base_url', :to => 'getting_started#base_url', :via => :post
|
||||
match api_path + '/getting_started/base_outbound', :to => 'getting_started#base_outbound', :via => :post
|
||||
match api_path + '/getting_started/base_inbound', :to => 'getting_started#base_inbound', :via => :post
|
||||
match api_path + '/getting_started', :to => 'getting_started#index', :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
|
||||
|
||||
end
|
Loading…
Reference in a new issue