From 0de3fc7c6b586cba1f981f9c743d746ef6b434d4 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 22 Oct 2014 23:00:11 +0200 Subject: [PATCH] Init version of new installer. --- .../_application_controller.js.coffee | 4 +- .../app/controllers/getting_started.js.coffee | 598 ++++++++++++++---- .../app/controllers/import.js.coffee | 152 +++++ .../app/controllers/signup.js.coffee | 9 +- .../app/views/getting_started.jst.eco | 23 - .../app/views/getting_started/admin.jst.eco | 14 + .../app/views/getting_started/agent.jst.eco | 16 + .../app/views/getting_started/base.jst.eco | 32 + .../app/views/getting_started/import.jst.eco | 23 + .../app/views/getting_started/index.jst.eco | 14 + app/controllers/getting_started_controller.rb | 293 ++++++++- app/controllers/users_controller.rb | 2 +- app/models/channel/email_build.rb | 4 +- app/models/channel/email_send.rb | 16 + app/models/channel/imap.rb | 43 +- app/models/channel/pop3.rb | 39 +- .../communicate_email/background_job.rb | 2 +- config/routes/getting_started.rb | 5 +- .../20141009000001_update_object_manager5.rb | 2 +- lib/notification_factory.rb | 3 +- 20 files changed, 1096 insertions(+), 198 deletions(-) create mode 100644 app/assets/javascripts/app/controllers/import.js.coffee delete mode 100644 app/assets/javascripts/app/views/getting_started.jst.eco create mode 100644 app/assets/javascripts/app/views/getting_started/admin.jst.eco create mode 100644 app/assets/javascripts/app/views/getting_started/agent.jst.eco create mode 100644 app/assets/javascripts/app/views/getting_started/base.jst.eco create mode 100644 app/assets/javascripts/app/views/getting_started/import.jst.eco create mode 100644 app/assets/javascripts/app/views/getting_started/index.jst.eco create mode 100644 app/models/channel/email_send.rb diff --git a/app/assets/javascripts/app/controllers/_application_controller.js.coffee b/app/assets/javascripts/app/controllers/_application_controller.js.coffee index f7bf3f4d3..864e81a3c 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.js.coffee @@ -183,7 +183,7 @@ class App.Controller extends Spine.Controller callback: data.callback ) - authenticate: -> + authenticate: (checkOnly = false) -> # return true if session exists return true if @Session.get() @@ -191,6 +191,8 @@ class App.Controller extends Spine.Controller # remember requested url @Config.set( 'requested_url', window.location.hash ) + return false if checkOnly + # redirect to login @navigate '#login' return false diff --git a/app/assets/javascripts/app/controllers/getting_started.js.coffee b/app/assets/javascripts/app/controllers/getting_started.js.coffee index 4851f9990..fd3882b82 100644 --- a/app/assets/javascripts/app/controllers/getting_started.js.coffee +++ b/app/assets/javascripts/app/controllers/getting_started.js.coffee @@ -1,18 +1,486 @@ class Index extends App.ControllerContent 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: - 'submit form': 'submit', - 'click .submit': 'submit', + 'change [name=adapter]': 'toggleAdapter' + '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: -> super # set title - @title 'Get Started' - @navupdate '#get_started' + @title 'Import' - @master_user = 0 @fetch() fetch: -> @@ -28,11 +496,10 @@ class Index extends App.ControllerContent 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 ) + # redirect to login if master user already exists + if data.setup_done + @navigate '#login' + return # render page @render() @@ -40,113 +507,6 @@ class Index extends App.ControllerContent render: -> - # check authentication, redirect to login if master user already exists - if !@master_user && !@authenticate() - @navigate '#login' + @html App.view('getting_started/import')() - @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( 'getting_started', Index, 'Routes' ) +App.Config.set( 'getting_started/import', Import, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/import.js.coffee b/app/assets/javascripts/app/controllers/import.js.coffee new file mode 100644 index 000000000..6428afda0 --- /dev/null +++ b/app/assets/javascripts/app/controllers/import.js.coffee @@ -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' ) diff --git a/app/assets/javascripts/app/controllers/signup.js.coffee b/app/assets/javascripts/app/controllers/signup.js.coffee index 47477537f..24105b24d 100644 --- a/app/assets/javascripts/app/controllers/signup.js.coffee +++ b/app/assets/javascripts/app/controllers/signup.js.coffee @@ -22,11 +22,6 @@ class Index extends App.ControllerContent render: -> - # set password as required - for item in App.User.configure_attributes - if item.name is 'password' - item.null = false - @html App.view('signup')() new App.ControllerForm( @@ -53,7 +48,9 @@ class Index extends App.ControllerContent user = new App.User user.load(@params) - errors = user.validate() + errors = user.validate( + screen: 'signup' + ) if errors @log 'error new', errors @formValidate( form: e.target, errors: errors ) diff --git a/app/assets/javascripts/app/views/getting_started.jst.eco b/app/assets/javascripts/app/views/getting_started.jst.eco deleted file mode 100644 index ce630e1aa..000000000 --- a/app/assets/javascripts/app/views/getting_started.jst.eco +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
    -
  1. <%- @T( 'Create Admin' ) %>
  2. -
  3. <%- @T( 'Invite Agents' ) %>
  4. -
  5. <%- @T( 'Configure Channels' ) %>
  6. -
- <% if @master_user: %> -
-
- -
-
- <% end %> -
-
-
- -
-
-
-
-
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/getting_started/admin.jst.eco b/app/assets/javascripts/app/views/getting_started/admin.jst.eco new file mode 100644 index 000000000..478f91905 --- /dev/null +++ b/app/assets/javascripts/app/views/getting_started/admin.jst.eco @@ -0,0 +1,14 @@ +
+
+
    +
  1. <%- @T( 'Configure Base' ) %>
  2. +
  3. <%- @T( 'Create Admin' ) %>
  4. +
  5. <%- @T( 'Invite Agents' ) %>
  6. +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/getting_started/agent.jst.eco b/app/assets/javascripts/app/views/getting_started/agent.jst.eco new file mode 100644 index 000000000..a1beb07ed --- /dev/null +++ b/app/assets/javascripts/app/views/getting_started/agent.jst.eco @@ -0,0 +1,16 @@ +
+
+
    +
  1. <%- @T( 'Configure Base' ) %>
  2. +
  3. <%- @T( 'Create Admin' ) %>
  4. +
  5. <%- @T( 'Invite Agents' ) %>
  6. +
+
+
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/getting_started/base.jst.eco b/app/assets/javascripts/app/views/getting_started/base.jst.eco new file mode 100644 index 000000000..aed068680 --- /dev/null +++ b/app/assets/javascripts/app/views/getting_started/base.jst.eco @@ -0,0 +1,32 @@ +
+
+
    +
  1. <%- @T( 'Configure Base' ) %>
  2. +
  3. <%- @T( 'Create Admin' ) %>
  4. +
  5. <%- @T( 'Invite Agents' ) %>
  6. +
+ +
+
+
+ + +
+ <%- @T('E-Mail Outbound') %> +
+
+
+ +
+ <%- @T('E-Mail Inbound') %> +
+
+
+ +
+ <%- @T('Go Back') %> +
<%- @T('Update') %>
+
+ +
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/getting_started/import.jst.eco b/app/assets/javascripts/app/views/getting_started/import.jst.eco new file mode 100644 index 000000000..f5c207081 --- /dev/null +++ b/app/assets/javascripts/app/views/getting_started/import.jst.eco @@ -0,0 +1,23 @@ +
+
+
+

<%- @T('Import from') %>

+
+
+ +
+
+
+
+

Create OTRS Migration Plugin

+
+

+ Personalise Migration Plugin .. +

+
+
+ Go Back +
+
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/getting_started/index.jst.eco b/app/assets/javascripts/app/views/getting_started/index.jst.eco new file mode 100644 index 000000000..b126910fe --- /dev/null +++ b/app/assets/javascripts/app/views/getting_started/index.jst.eco @@ -0,0 +1,14 @@ +
+
+
+

<%- @T('Welcome to %s', @C('product_name') ) %>

+ +
+
+
\ No newline at end of file diff --git a/app/controllers/getting_started_controller.rb b/app/controllers/getting_started_controller.rb index 49cefde62..d98fe7911 100644 --- a/app/controllers/getting_started_controller.rb +++ b/app/controllers/getting_started_controller.rb @@ -30,14 +30,10 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} def index # check if first user already exists - master_user = 0 - count = User.all.count() - if count <= 2 - master_user = 1 - end + return if setup_done_response # if master user already exists, we need to be authenticated - if master_user == 0 + if setup_done return if !authentication_check end @@ -46,8 +42,287 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} # return result render :json => { - :master_user => master_user, - :groups => groups, + :setup_done => setup_done, + :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 \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b52a7f32c..7edb13d50 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -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[: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: diff --git a/app/models/channel/email_build.rb b/app/models/channel/email_build.rb index b9870d6f7..f20f5eeab 100644 --- a/app/models/channel/email_build.rb +++ b/app/models/channel/email_build.rb @@ -45,6 +45,6 @@ class Channel::EmailBuild } end end - return mail + mail end -end +end \ No newline at end of file diff --git a/app/models/channel/email_send.rb b/app/models/channel/email_send.rb new file mode 100644 index 000000000..d73287ccb --- /dev/null +++ b/app/models/channel/email_send.rb @@ -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 diff --git a/app/models/channel/imap.rb b/app/models/channel/imap.rb index a0c7aa8e2..a8114b338 100644 --- a/app/models/channel/imap.rb +++ b/app/models/channel/imap.rb @@ -4,7 +4,7 @@ require 'net/imap' class Channel::IMAP < Channel::EmailParser - def fetch (channel) + def fetch (channel, check_type = '', verify_string = '') ssl = false port = 143 if channel[:options][:ssl].to_s == 'true' @@ -30,17 +30,37 @@ class Channel::IMAP < Channel::EmailParser else @imap.select( channel[:options][:folder] ) 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_all = @imap.search(['ALL']).count @imap.search(['ALL']).each do |message_id| count += 1 puts " - message #{count.to_s}/#{count_all.to_s}" - msg = @imap.fetch(message_id,'RFC822')[0].attr['RFC822'] # puts msg.to_s - # delete email from server after article was created - if process(channel, msg) - @imap.store(message_id, "+FLAGS", [:Deleted]) + # 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 + msg = @imap.fetch(message_id,'RFC822')[0].attr['RFC822'] + if process(channel, msg) + @imap.store(message_id, "+FLAGS", [:Deleted]) + end end end @imap.expunge() @@ -56,15 +76,4 @@ class Channel::IMAP < Channel::EmailParser @imap.disconnect() 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 \ No newline at end of file diff --git a/app/models/channel/pop3.rb b/app/models/channel/pop3.rb index 88f091160..759575959 100644 --- a/app/models/channel/pop3.rb +++ b/app/models/channel/pop3.rb @@ -4,7 +4,7 @@ require 'net/pop' class Channel::POP3 < Channel::EmailParser - def fetch (channel) + def fetch (channel, check_type = '') ssl = false port = 110 if channel[:options][:ssl].to_s == 'true' @@ -19,15 +19,34 @@ class Channel::POP3 < Channel::EmailParser @pop.enable_ssl end @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_all = @pop.mails.size @pop.each_mail do |m| count += 1 puts " - message #{count.to_s}/#{count_all.to_s}" - # delete email from server after article was created - if process(channel, m.pop) - m.delete + # 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 + if process(channel, m.pop) + m.delete + end end end disconnect @@ -43,14 +62,4 @@ class Channel::POP3 < Channel::EmailParser 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 \ No newline at end of file diff --git a/app/models/observer/ticket/article/communicate_email/background_job.rb b/app/models/observer/ticket/article/communicate_email/background_job.rb index bca380c6e..a3aebde6c 100644 --- a/app/models/observer/ticket/article/communicate_email/background_job.rb +++ b/app/models/observer/ticket/article/communicate_email/background_job.rb @@ -10,7 +10,7 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob subject = ticket.subject_build( record.subject ) # send email - a = Channel::IMAP.new + a = Channel::EmailSend.new message = a.send( { :message_id => record.message_id, diff --git a/config/routes/getting_started.rb b/config/routes/getting_started.rb index 398b61da7..520a9acaa 100644 --- a/config/routes/getting_started.rb +++ b/config/routes/getting_started.rb @@ -2,6 +2,9 @@ Zammad::Application.routes.draw do api_path = Rails.configuration.api_path # getting_started - match api_path + '/getting_started', :to => 'getting_started#index', :via => :get + match api_path + '/getting_started', :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 \ No newline at end of file diff --git a/db/migrate/20141009000001_update_object_manager5.rb b/db/migrate/20141009000001_update_object_manager5.rb index 763eb5f8b..bf0dd82c4 100644 --- a/db/migrate/20141009000001_update_object_manager5.rb +++ b/db/migrate/20141009000001_update_object_manager5.rb @@ -402,7 +402,7 @@ class UpdateObjectManager5 < ActiveRecord::Migration :screens => { :signup => { '-all-' => { - :null => true, + :null => false, }, }, :invite_agent => {}, diff --git a/lib/notification_factory.rb b/lib/notification_factory.rb index fbeb6c254..62cbb7da0 100644 --- a/lib/notification_factory.rb +++ b/lib/notification_factory.rb @@ -49,9 +49,8 @@ module NotificationFactory def self.send(data) sender = Setting.get('notification_sender') - a = Channel::IMAP.new Rails.logger.info "NOTICE: SEND NOTIFICATION TO: #{data[:recipient][:email]}" - message = a.send( + Channel::EmailSend.new.send( { # :in_reply_to => self.in_reply_to, :from => sender,