Init version of new installer.

This commit is contained in:
Martin Edenhofer 2014-10-22 23:00:11 +02:00
parent 500b11c86b
commit 0de3fc7c6b
20 changed files with 1096 additions and 198 deletions

View file

@ -183,7 +183,7 @@ class App.Controller extends Spine.Controller
callback: data.callback callback: data.callback
) )
authenticate: -> authenticate: (checkOnly = false) ->
# return true if session exists # return true if session exists
return true if @Session.get() return true if @Session.get()
@ -191,6 +191,8 @@ class App.Controller extends Spine.Controller
# remember requested url # remember requested url
@Config.set( 'requested_url', window.location.hash ) @Config.set( 'requested_url', window.location.hash )
return false if checkOnly
# redirect to login # redirect to login
@navigate '#login' @navigate '#login'
return false return false

View file

@ -1,18 +1,486 @@
class Index extends App.ControllerContent class Index extends App.ControllerContent
className: 'getstarted fit' className: 'getstarted fit'
constructor: ->
super
if @authenticate(true)
@navigate '#'
# set title
@title 'Get Started'
@fetch()
release: =>
@el.removeClass('fit').removeClass('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 data.setup_done
@navigate '#login'
return
# render page
@render()
)
render: ->
@html App.view('getting_started/index')()
App.Config.set( 'getting_started', Index, 'Routes' )
class Base extends App.ControllerContent
className: 'getstarted fit'
events: events:
'submit form': 'submit', 'change [name=adapter]': 'toggleAdapter'
'click .submit': 'submit', 'submit .base': 'storeFqdn'
'submit .base-outbound': 'storeOutbound'
'submit .base-inbound': 'storeInbound'
'click .js-next': 'submit'
constructor: ->
super
if @authenticate(true)
@navigate '#'
# set title
@title 'Configure Base'
@fetch()
release: =>
@el.removeClass('fit').removeClass('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 data.setup_done
@navigate '#login'
return
# render page
@render()
)
render: ->
@html App.view('getting_started/base')()
# fqdn
configureAttributesBase = [
{ name: 'fqdn', display: 'System URL (where the system can be reached)', tag: 'input', null: false, placeholder: 'http://yourhost' },
]
new App.ControllerForm(
el: @$('.base-fqdn'),
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').removeClass('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').removeClass('btn--success')
@enable( @$('.btn') )
storeFqdn: (e) =>
e.preventDefault()
# get params
params = @formParam(e.target)
console.log('submit', params, e)
@disable(e)
@ajax(
id: 'base_fqdn'
type: 'POST'
url: @apiPath + '/getting_started/base_fqdn'
data: JSON.stringify( {fqdn:params.fqdn} )
processData: true
success: (data, status, xhr) =>
if data.result is 'ok'
@$('.wizard-controls .btn').text('Done').removeClass('btn--primary').removeClass('btn--danger').addClass('btn--success')
@delay( @showOutbound, 1500 )
else
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('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').removeClass('btn--danger').addClass('btn--success')
@delay( @showInbound, 1500 )
else
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('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').removeClass('btn--danger').addClass('btn--success')
@delay( @goToAdmin, 1500 )
else
@$('.wizard-controls .btn').text( data.message_human || data.message ).addClass('btn--danger').removeClass('btn--primary').removeClass('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'
constructor: ->
super
if @authenticate(true)
@navigate '#'
# set title
@title 'Create Admin'
@fetch()
release: =>
@el.removeClass('fit').removeClass('getstarted')
fetch: ->
# get data
@ajax(
id: 'getting_started',
type: 'GET',
url: @apiPath + '/getting_started',
data: {
# view: @view,
}
processData: true,
success: (data, status, xhr) =>
# redirect to login if master user already exists
if data.setup_done
@navigate '#login'
return
# load group collection
App.Collection.load( type: 'Group', data: data.groups )
# render page
@render()
)
render: ->
@html App.view('getting_started/admin')()
new App.ControllerForm(
el: @$('.js-admin')
model: App.User
screen: 'signup'
autofocus: true
)
submit: (e) =>
e.preventDefault()
@formDisable(e)
@params = @formParam(e.target)
@params.role_ids = [0]
user = new App.User
user.load(@params)
errors = user.validate(
screen: 'signup'
)
if errors
@log 'error new', errors
@formValidate( form: e.target, errors: errors )
@formEnable(e)
return false
# save user
user.save(
done: (r) =>
App.Auth.login(
data:
username: @params.email
password: @params.password
success: @relogin
error: =>
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent( 'Signin failed! Please contact the support team!' )
timeout: 2500
}
)
@Config.set('system_init_done', true)
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Welcome to %s!', @Config.get('product_name') )
timeout: 2500
}
fail: (data) =>
@formEnable(e)
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent( 'Can\'t create user!' )
timeout: 2500
}
)
relogin: (data, status, xhr) =>
@log 'notice', 'relogin:success', data
# add notify
App.Event.trigger 'notify:removeall'
@navigate 'getting_started/agents'
App.Config.set( 'getting_started/admin', Admin, 'Routes' )
class Agent extends App.ControllerContent
className: 'getstarted'
events:
'submit .js-agent': 'submit'
constructor: ->
super
return if !@authenticate()
# set title
@title 'Invite Agents'
@fetch()
release: =>
@el.removeClass('fit').removeClass('getstarted')
fetch: ->
# get data
@ajax(
id: 'getting_started',
type: 'GET',
url: @apiPath + '/getting_started',
data: {
# view: @view,
}
processData: true,
success: (data, status, xhr) =>
# redirect to login if master user already exists
if !data.setup_done
@navigate '#getting_started/admin'
return
# load group collection
App.Collection.load( type: 'Group', data: data.groups )
# render page
@render()
)
render: ->
@html App.view('getting_started/agent')()
new App.ControllerForm(
el: @$('.js-agent')
model: App.User
screen: 'invite_agent'
autofocus: true
)
submit: (e) =>
e.preventDefault()
@formDisable(e)
@params = @formParam(e.target)
@params.role_ids = [0]
# set invite flag
@params.invite = true
# find agent role
role = App.Role.findByAttribute( 'name', 'Agent' )
if role
@params.role_ids = role.id
user = new App.User
user.load(@params)
errors = user.validate(
screen: 'invite_agent'
)
if errors
@log 'error new', errors
@formValidate( form: e.target, errors: errors )
@formEnable(e)
return false
# save user
user.save(
done: (r) =>
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Invitation sent!' )
timeout: 3500
}
# rerender page
@render()
fail: (data) =>
@formEnable(e)
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent( 'Can\'t create user!' )
timeout: 2500
}
)
App.Config.set( 'getting_started/agents', Agent, 'Routes' )
class Import extends App.ControllerContent
className: 'getstarted fit'
constructor: -> constructor: ->
super super
# set title # set title
@title 'Get Started' @title 'Import'
@navupdate '#get_started'
@master_user = 0
@fetch() @fetch()
fetch: -> fetch: ->
@ -28,11 +496,10 @@ class Index extends App.ControllerContent
processData: true, processData: true,
success: (data, status, xhr) => success: (data, status, xhr) =>
# get meta data # redirect to login if master user already exists
@master_user = data.master_user if data.setup_done
@navigate '#login'
# load group collection return
App.Collection.load( type: 'Group', data: data.groups )
# render page # render page
@render() @render()
@ -40,113 +507,6 @@ class Index extends App.ControllerContent
render: -> render: ->
# check authentication, redirect to login if master user already exists @html App.view('getting_started/import')()
if !@master_user && !@authenticate()
@navigate '#login'
@html App.view('getting_started')( App.Config.set( 'getting_started/import', Import, 'Routes' )
master_user: @master_user
)
new App.ControllerForm(
el: @el.find('#form-master')
model: App.User
screen: 'signup'
autofocus: true
)
new App.ControllerForm(
el: @el.find('#form-agent')
model: App.User
screen: 'invite_agent'
autofocus: true
)
if !@master_user
@el.find('.agent_user').removeClass('hide')
submit: (e) ->
e.preventDefault()
@params = @formParam(e.target)
# if no login is given, use emails as fallback
if !@params.login && @params.email
@params.login = @params.email
# set invite flag
@params.invite = true
# find agent role
role = App.Role.findByAttribute( 'name', 'Agent' )
if role
@params.role_ids = role.id
else
@params.role_ids = [0]
@log 'notice', 'updateAttributes', @params
user = new App.User
user.load(@params)
errors = user.validate()
if errors
@log 'error', errors
@formValidate( form: e.target, errors: errors )
return false
# save user
user.save(
done: =>
if @master_user
@master_user = false
App.Auth.login(
data: {
username: @params.login
password: @params.password
},
success: @relogin
# error: @error,
)
@Config.set('system_init_done', true)
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Welcome to %s!', @Config.get('product_name') )
timeout: 2500
}
else
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Invitation sent!' )
timeout: 3500
}
# rerender page
@render()
fail: (data) ->
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent( 'Can\'t create user!' )
timeout: 2500
}
# @modalHide()
)
relogin: (data, status, xhr) =>
@log 'notice', 'relogin:success', data
# add notify
App.Event.trigger 'notify:removeall'
# @notify
# type: 'success',
# msg: 'Thanks for joining. Email sent to "' + @params.email + '". Please verify your email address.'
@el.find('.master_user').addClass('hide')
@el.find('.agent_user').removeClass('hide')
@el.find('.tabs .tab.active').removeClass('active')
@el.find('.tabs .invite_agents').addClass('active')
# @el.find('.master_user').fadeOut('slow', =>
# @el.find('.agent_user').fadeIn()
# )
App.Config.set( 'getting_started', Index, 'Routes' )

View file

@ -0,0 +1,152 @@
class Index extends App.ControllerContent
className: 'getstarted fit'
events:
'submit form': 'submit',
'click .submit': 'submit',
constructor: ->
super
# set title
@title 'Get Started'
@navupdate '#get_started'
@master_user = 0
@fetch()
fetch: ->
# get data
@ajax(
id: 'getting_started',
type: 'GET',
url: @apiPath + '/getting_started',
data: {
# view: @view,
}
processData: true,
success: (data, status, xhr) =>
# get meta data
@master_user = data.master_user
# load group collection
App.Collection.load( type: 'Group', data: data.groups )
# render page
@render()
)
render: ->
# check authentication, redirect to login if master user already exists
#if !@master_user && !@authenticate()
# @navigate '#login'
@html App.view('getting_started')(
master_user: @master_user
)
new App.ControllerForm(
el: @el.find('#form-master')
model: App.User
screen: 'signup'
autofocus: true
)
new App.ControllerForm(
el: @el.find('#form-agent')
model: App.User
screen: 'invite_agent'
autofocus: true
)
if !@master_user
@el.find('.agent_user').removeClass('hide')
submit: (e) ->
e.preventDefault()
@params = @formParam(e.target)
# if no login is given, use emails as fallback
if !@params.login && @params.email
@params.login = @params.email
# set invite flag
@params.invite = true
# find agent role
role = App.Role.findByAttribute( 'name', 'Agent' )
if role
@params.role_ids = role.id
else
@params.role_ids = [0]
@log 'notice', 'updateAttributes', @params
user = new App.User
user.load(@params)
errors = user.validate()
if errors
@log 'error', errors
@formValidate( form: e.target, errors: errors )
return false
# save user
user.save(
done: =>
if @master_user
@master_user = false
App.Auth.login(
data: {
username: @params.login
password: @params.password
},
success: @relogin
# error: @error,
)
@Config.set('system_init_done', true)
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Welcome to %s!', @Config.get('product_name') )
timeout: 2500
}
else
App.Event.trigger 'notify', {
type: 'success'
msg: App.i18n.translateContent( 'Invitation sent!' )
timeout: 3500
}
# rerender page
@render()
fail: (data) ->
App.Event.trigger 'notify', {
type: 'error'
msg: App.i18n.translateContent( 'Can\'t create user!' )
timeout: 2500
}
# @modalHide()
)
relogin: (data, status, xhr) =>
@log 'notice', 'relogin:success', data
# add notify
App.Event.trigger 'notify:removeall'
# @notify
# type: 'success',
# msg: 'Thanks for joining. Email sent to "' + @params.email + '". Please verify your email address.'
@el.find('.master_user').addClass('hide')
@el.find('.agent_user').removeClass('hide')
@el.find('.tabs .tab.active').removeClass('active')
@el.find('.tabs .invite_agents').addClass('active')
# @el.find('.master_user').fadeOut('slow', =>
# @el.find('.agent_user').fadeIn()
# )
App.Config.set( 'import', Index, 'Routes' )

View file

@ -22,11 +22,6 @@ class Index extends App.ControllerContent
render: -> render: ->
# set password as required
for item in App.User.configure_attributes
if item.name is 'password'
item.null = false
@html App.view('signup')() @html App.view('signup')()
new App.ControllerForm( new App.ControllerForm(
@ -53,7 +48,9 @@ class Index extends App.ControllerContent
user = new App.User user = new App.User
user.load(@params) user.load(@params)
errors = user.validate() errors = user.validate(
screen: 'signup'
)
if errors if errors
@log 'error new', errors @log 'error new', errors
@formValidate( form: e.target, errors: errors ) @formValidate( form: e.target, errors: errors )

View file

@ -1,23 +0,0 @@
<div class="fullHeight vertical center justified">
<div class="hero-unit">
<ol class="horizontal tabs progress-tabs tabs-condensed">
<li class="create_admin tab u-textTruncate active"><%- @T( 'Create Admin' ) %></li>
<li class="invite_agents tab u-textTruncate"><%- @T( 'Invite Agents' ) %></li>
<li class="configure_channels tab u-textTruncate"><%- @T( 'Configure Channels' ) %></li>
</ol>
<% if @master_user: %>
<div class="master_user hero-left">
<form class="form-stacked" id="form-master">
<button type="submit" class="btn btn--primary submit pull-right"><%- @T( 'Next Step' ) %></button>
</form>
</div>
<% end %>
<div class="agent_user hero-left hide">
<form class="form-stacked" id="form-agent">
<div class="form-controls">
<button type="submit" class="btn btn--primary submit pull-right"><%- @T( 'Send Invitation' ) %></button>
</div>
</form>
</div>
</div>
</div>

View file

@ -0,0 +1,14 @@
<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>
</div>
</div>

View file

@ -0,0 +1,16 @@
<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>
</div>
</div>

View file

@ -0,0 +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-fqdn"></div>
</form>
<form class="base-outbound hide">
<%- @T('E-Mail Outbound') %>
<div class="base-outbound-type"></div>
<div class="base-outbound-settings"></div>
</form>
<form class="base-inbound hide">
<%- @T('E-Mail Inbound') %>
<div class="base-inbound-settings"></div>
<div class="base-inbound-state"></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('Update') %></div>
</div>
</div>
</div>

View file

@ -0,0 +1,23 @@
<div class="main flex centered darkBackground">
<div class="import wizard hero-unit">
<div class="wizard-slide vertical" data-slide="home">
<h2><%- @T('Import from') %></h2>
<div class="wizard-body flex vertical justified">
<div class="import-source centered" data-source="otrs" data-target="otrs-prepare-plugin">
<img class="logo" src="<%= @C('otrs-logo.png') %>" alt="OTRS" height="37">
</div>
</div>
</div>
<div class="wizard-slide vertical hide" data-slide="otrs-prepare-plugin" data-hide="2330">
<h2>Create OTRS Migration Plugin</h2>
<div class="wizard-body flex vertical justified">
<p class="wizard-loadingText">
<span class="loading icon"></span> Personalise Migration Plugin ..
</p>
</div>
<div class="wizard-controls horizontal center">
<a class="subtle-link" data-target="home">Go Back</a>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,14 @@
<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 justified">
<div class="centered">
<a href="#getting_started/import"><%- @T('Import from other System') %></a>
|
<a href="#getting_started/base"><%- @T('Setup new System') %></a>
</div>
</div>
</div>
</div>
</div>

View file

@ -30,14 +30,10 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
def index def index
# check if first user already exists # check if first user already exists
master_user = 0 return if setup_done_response
count = User.all.count()
if count <= 2
master_user = 1
end
# if master user already exists, we need to be authenticated # if master user already exists, we need to be authenticated
if master_user == 0 if setup_done
return if !authentication_check return if !authentication_check
end end
@ -46,8 +42,287 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password}
# return result # return result
render :json => { render :json => {
:master_user => master_user, :setup_done => setup_done,
:groups => groups, :groups => groups,
} }
end end
def base_fqdn
return if setup_done_response
# validate
if !params[:fqdn] ||params[:fqdn] !~ /^(http|https):\/\/.+?$/
render :json => {
:result => 'invalid',
:message => 'Invalid!',
}
return true
end
Setting.set('fqdn', params[:fqdn])
# return result
render :json => {
:result => 'ok',
}
end
def base_outbound
return if setup_done_response
# validate params
if !params[:adapter]
render :json => {
:result => 'invalid',
:message => 'Invalid!',
}
return
end
# test connection
translationMap = {
'authentication failed' => 'Authentication failed!',
'getaddrinfo: nodename nor servname provided, or not known' => 'Hostname not found!',
'No route to host' => 'No route to host!',
'Connection refused' => 'Connection refused!',
}
if params[:adapter] == 'smtp'
begin
Channel::SMTP.new.send(
{
:from => 'me@example.com',
:to => 'emailtrytest@znuny.com',
:subject => 'test',
:body => 'test',
},
{
:options => params[:options]
}
)
rescue Exception => e
# check if sending email was ok, but mailserver rejected
whiteMap = {
'Recipient address rejected' => true,
}
whiteMap.each {|key, message|
if e.message =~ /#{Regexp.escape(key)}/i
render :json => {
:result => 'ok',
}
return
end
}
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
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
end
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
end
# return result
render :json => {
:result => 'ok',
}
end
def base_inbound
return if setup_done_response
# validate params
if !params[:adapter]
render :json => {
:result => 'invalid',
}
return
end
# connection test
translationMap = {
'authentication failed' => 'Authentication failed!',
'getaddrinfo: nodename nor servname provided, or not known' => 'Hostname not found!',
'No route to host' => 'No route to host!',
'Connection refused' => 'Connection refused!',
}
if params[:adapter] == 'IMAP'
begin
Channel::IMAP.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
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
end
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..10).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,
)
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.',
}
return
end
private
def setup_done
#return false
count = User.all.count()
done = true
if count <= 2
done = false
end
done
end
def setup_done_response
if !setup_done
return false
end
render :json => {
:setup_done => true,
}
true
end
end end

View file

@ -218,7 +218,7 @@ curl http://localhost/api/v1/users.json -v -u #{login}:#{password} -H "Content-T
data[:subject] = 'Invitation to #{config.product_name} at #{config.fqdn}' data[:subject] = 'Invitation to #{config.product_name} at #{config.fqdn}'
data[:body] = 'Hi #{user.firstname}, data[:body] = 'Hi #{user.firstname},
I (#{current_user.firstname} #{current_user.lastname}) invite you to #{config.product_name} - a customer support / ticket system platform. I (#{current_user.firstname} #{current_user.lastname}) invite you to #{config.product_name} - the customer support / ticket system platform.
Click on the following link and set your password: Click on the following link and set your password:

View file

@ -45,6 +45,6 @@ class Channel::EmailBuild
} }
end end
end end
return mail mail
end end
end end

View file

@ -0,0 +1,16 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
require 'net/imap'
class Channel::EmailSend
def send(attr, notification = false)
channel = Channel.where( :area => 'Email::Outbound', :active => true ).first
begin
c = eval 'Channel::' + channel[:adapter] + '.new'
c.send(attr, channel, notification)
rescue Exception => e
puts "can't use " + 'Channel::' + channel[:adapter]
puts e.inspect
end
end
end

View file

@ -4,7 +4,7 @@ require 'net/imap'
class Channel::IMAP < Channel::EmailParser class Channel::IMAP < Channel::EmailParser
def fetch (channel) def fetch (channel, check_type = '', verify_string = '')
ssl = false ssl = false
port = 143 port = 143
if channel[:options][:ssl].to_s == 'true' if channel[:options][:ssl].to_s == 'true'
@ -30,19 +30,39 @@ class Channel::IMAP < Channel::EmailParser
else else
@imap.select( channel[:options][:folder] ) @imap.select( channel[:options][:folder] )
end end
if check_type == 'check'
puts "check only mode, fetch no emails"
disconnect
return
elsif check_type == 'verify'
puts "verify mode, fetch no emails #{verify_string}"
end
count = 0 count = 0
count_all = @imap.search(['ALL']).count count_all = @imap.search(['ALL']).count
@imap.search(['ALL']).each do |message_id| @imap.search(['ALL']).each do |message_id|
count += 1 count += 1
puts " - message #{count.to_s}/#{count_all.to_s}" puts " - message #{count.to_s}/#{count_all.to_s}"
msg = @imap.fetch(message_id,'RFC822')[0].attr['RFC822']
# puts msg.to_s # puts msg.to_s
# check for verify message
if check_type == 'verify'
subject = @imap.fetch(message_id,'ENVELOPE')[0].attr['ENVELOPE'].subject
if subject && subject =~ /#{verify_string}/
puts " - verify email #{verify_string} found"
@imap.store(message_id, "+FLAGS", [:Deleted])
@imap.expunge()
disconnect
return 'verify ok'
end
else
# delete email from server after article was created # delete email from server after article was created
msg = @imap.fetch(message_id,'RFC822')[0].attr['RFC822']
if process(channel, msg) if process(channel, msg)
@imap.store(message_id, "+FLAGS", [:Deleted]) @imap.store(message_id, "+FLAGS", [:Deleted])
end end
end end
end
@imap.expunge() @imap.expunge()
disconnect disconnect
if count == 0 if count == 0
@ -56,15 +76,4 @@ class Channel::IMAP < Channel::EmailParser
@imap.disconnect() @imap.disconnect()
end end
end end
def send(attr, notification = false)
channel = Channel.where( :area => 'Email::Outbound', :active => true ).first
begin
c = eval 'Channel::' + channel[:adapter] + '.new'
c.send(attr, channel, notification)
rescue Exception => e
puts "can't use " + 'Channel::' + channel[:adapter]
puts e.inspect
end
end
end end

View file

@ -4,7 +4,7 @@ require 'net/pop'
class Channel::POP3 < Channel::EmailParser class Channel::POP3 < Channel::EmailParser
def fetch (channel) def fetch (channel, check_type = '')
ssl = false ssl = false
port = 110 port = 110
if channel[:options][:ssl].to_s == 'true' if channel[:options][:ssl].to_s == 'true'
@ -19,17 +19,36 @@ class Channel::POP3 < Channel::EmailParser
@pop.enable_ssl @pop.enable_ssl
end end
@pop.start( channel[:options][:user], channel[:options][:password] ) @pop.start( channel[:options][:user], channel[:options][:password] )
if check_type == 'check'
puts "check only mode, fetch no emails"
disconnect
return
elsif check_type == 'verify'
puts "verify mode, fetch no emails"
end
count = 0 count = 0
count_all = @pop.mails.size count_all = @pop.mails.size
@pop.each_mail do |m| @pop.each_mail do |m|
count += 1 count += 1
puts " - message #{count.to_s}/#{count_all.to_s}" puts " - message #{count.to_s}/#{count_all.to_s}"
# check for verify message
if check_type == 'verify'
mail = m.pop
if mail && mail =~ /#{verify_string}/
puts " - verify email #{verify_string} found"
m.delete
disconnect
return 'verify ok'
end
else
# delete email from server after article was created # delete email from server after article was created
if process(channel, m.pop) if process(channel, m.pop)
m.delete m.delete
end end
end end
end
disconnect disconnect
if count == 0 if count == 0
puts " - no message" puts " - no message"
@ -43,14 +62,4 @@ class Channel::POP3 < Channel::EmailParser
end end
end end
def send(attr, notification = false)
channel = Channel.where( :area => 'Email::Outbound', :active => true ).first
begin
c = eval 'Channel::' + channel[:adapter] + '.new'
c.send(attr, channel, notification)
rescue Exception => e
puts "can't use " + 'Channel::' + channel[:adapter]
puts e.inspect
end
end
end end

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob
subject = ticket.subject_build( record.subject ) subject = ticket.subject_build( record.subject )
# send email # send email
a = Channel::IMAP.new a = Channel::EmailSend.new
message = a.send( message = a.send(
{ {
:message_id => record.message_id, :message_id => record.message_id,

View file

@ -3,5 +3,8 @@ Zammad::Application.routes.draw do
# getting_started # getting_started
match api_path + '/getting_started', :to => 'getting_started#index', :via => :get match api_path + '/getting_started', :to => 'getting_started#index', :via => :get
match api_path + '/getting_started/base_fqdn', :to => 'getting_started#base_fqdn', :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
end end

View file

@ -402,7 +402,7 @@ class UpdateObjectManager5 < ActiveRecord::Migration
:screens => { :screens => {
:signup => { :signup => {
'-all-' => { '-all-' => {
:null => true, :null => false,
}, },
}, },
:invite_agent => {}, :invite_agent => {},

View file

@ -49,9 +49,8 @@ module NotificationFactory
def self.send(data) def self.send(data)
sender = Setting.get('notification_sender') sender = Setting.get('notification_sender')
a = Channel::IMAP.new
Rails.logger.info "NOTICE: SEND NOTIFICATION TO: #{data[:recipient][:email]}" Rails.logger.info "NOTICE: SEND NOTIFICATION TO: #{data[:recipient][:email]}"
message = a.send( Channel::EmailSend.new.send(
{ {
# :in_reply_to => self.in_reply_to, # :in_reply_to => self.in_reply_to,
:from => sender, :from => sender,