diff --git a/app/assets/javascripts/app/controllers/default_route.js.coffee b/app/assets/javascripts/app/controllers/default_route.js.coffee index 682a6929f..0329e319e 100644 --- a/app/assets/javascripts/app/controllers/default_route.js.coffee +++ b/app/assets/javascripts/app/controllers/default_route.js.coffee @@ -7,6 +7,11 @@ class Index extends App.Controller if window.location.pathname.substr(0,5) is '/test' return + # check if import is active + if @Config.get('import_mode') + @navigate '#import' + return + # route to getting started screen if !@Config.get('system_init_done') @navigate '#getting_started' diff --git a/app/assets/javascripts/app/controllers/getting_started.js.coffee b/app/assets/javascripts/app/controllers/getting_started.js.coffee index f2ae337e9..81b0b1700 100644 --- a/app/assets/javascripts/app/controllers/getting_started.js.coffee +++ b/app/assets/javascripts/app/controllers/getting_started.js.coffee @@ -6,10 +6,16 @@ class Index extends App.ControllerContent if @authenticate(true) @navigate '#' + return # set title @title 'Get Started' + # if not import backend exists, go ahead + if !App.Config.get('ImportPlugins') + @navigate 'getting_started/base' + return + @fetch() release: => @@ -30,6 +36,11 @@ class Index extends App.ControllerContent @navigate '#login' return + # check if import is active + if data.import_mode == true + @navigate '#import/' + data.import_backend + return + # render page @render() ) @@ -55,6 +66,7 @@ class Base extends App.ControllerContent if @authenticate(true) @navigate '#' + return # set title @title 'Configure Base' @@ -79,6 +91,11 @@ class Base extends App.ControllerContent @navigate '#login' return + # check if import is active + if data.import_mode == true + @navigate '#import/' + data.import_backend + return + # render page @render() ) @@ -263,6 +280,7 @@ class Admin extends App.ControllerContent if @authenticate(true) @navigate '#' + return # set title @title 'Create Admin' @@ -290,6 +308,11 @@ class Admin extends App.ControllerContent @navigate '#login' return + # check if import is active + if data.import_mode == true + @navigate '#import/' + data.import_backend + return + # load group collection App.Collection.load( type: 'Group', data: data.groups ) @@ -393,9 +416,6 @@ class Agent extends App.ControllerContent id: 'getting_started', type: 'GET', url: @apiPath + '/getting_started', - data: { -# view: @view, - } processData: true, success: (data, status, xhr) => @@ -404,6 +424,11 @@ class Agent extends App.ControllerContent @navigate '#getting_started/admin' return + # check if import is active + if data.import_mode == true + @navigate '#import/' + data.import_backend + return + # load group collection App.Collection.load( type: 'Group', data: data.groups ) @@ -469,44 +494,4 @@ class Agent extends App.ControllerContent } ) - -App.Config.set( 'getting_started/agents', Agent, 'Routes' ) - -class Import extends App.ControllerContent - className: 'getstarted fit' - - constructor: -> - super - - # set title - @title 'Import' - - @fetch() - - 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 - - # render page - @render() - ) - - render: -> - - @html App.view('getting_started/import')() - -App.Config.set( 'getting_started/import', Import, 'Routes' ) +App.Config.set( 'getting_started/agents', Agent, 'Routes' ) \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/import.js.coffee b/app/assets/javascripts/app/controllers/import.js.coffee index 6428afda0..fca9c66ed 100644 --- a/app/assets/javascripts/app/controllers/import.js.coffee +++ b/app/assets/javascripts/app/controllers/import.js.coffee @@ -1,18 +1,12 @@ -class Index extends App.ControllerContent +class Import extends App.ControllerContent className: 'getstarted fit' - events: - 'submit form': 'submit', - 'click .submit': 'submit', - constructor: -> super # set title - @title 'Get Started' - @navupdate '#get_started' + @title 'Import' - @master_user = 0 @fetch() fetch: -> @@ -22,17 +16,17 @@ class Index extends App.ControllerContent 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 + # 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 ) + if data.import_mode == true + @navigate '#import/' + data.import_backend + return # render page @render() @@ -40,113 +34,10 @@ class Index extends App.ControllerContent render: -> - # check authentication, redirect to login if master user already exists - #if !@master_user && !@authenticate() - # @navigate '#login' + items = App.Config.get('ImportPlugins') - @html App.view('getting_started')( - master_user: @master_user + @html App.view('import/index')( + items: items ) - 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' ) +App.Config.set( 'import', Import, 'Routes' ) \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/import_otrs.js.coffee b/app/assets/javascripts/app/controllers/import_otrs.js.coffee new file mode 100644 index 000000000..11afbd641 --- /dev/null +++ b/app/assets/javascripts/app/controllers/import_otrs.js.coffee @@ -0,0 +1,149 @@ +class Index extends App.ControllerContent + className: 'getstarted fit' + elements: + '.input-feedback': 'urlStatus' + '[data-target=otrs-start-migration]': 'nextStartMigration' + '.otrs-link-error': 'linkErrorMessage' + events: + 'click .js-otrs-link': 'showLink' + 'click .js-download': 'startDownload' + 'click .js-migration-start': 'startMigration' + 'keyup #otrs-link': 'updateUrl' + + constructor: -> + super + + # set title + @title 'Import' + + @fetch() + + 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 + + # check if import is active + if data.import_mode == true && data.import_backend != 'otrs' + @navigate '#import/' + data.import_backend + return + + # render page + @render() + + if data.import_mode == true + @showImportState() + @updateMigration() + else + showDownload = => + @$('[data-slide=otrs-prepare]').toggleClass('hide') + @$('[data-slide=otrs-plugin]').toggleClass('hide') + @delay( showDownload, 2500 ) + ) + + render: -> + @html App.view('import/otrs')() + + startDownload: (e) => + e.preventDefault() + @$('.js-otrs-link').removeClass('hide') + + showLink: (e) => + e.preventDefault() + @$('[data-slide=otrs-plugin]').toggleClass('hide') + @$('[data-slide=otrs-link]').toggleClass('hide') + + showImportState: => + @$('[data-slide=otrs-prepare]').addClass('hide') + @$('[data-slide=otrs-plugin]').addClass('hide') + @$('[data-slide=otrs-link]').addClass('hide') + @$('[data-slide=otrs-import]').removeClass('hide') + + updateUrl: (e) => + url = $(e.target).val() + @urlStatus.attr('data-state', 'loading') + @linkErrorMessage.text('') + + # get data + callback = => + @ajax( + id: 'import_otrs_url', + type: 'POST', + url: @apiPath + '/import/otrs/url_check', + data: JSON.stringify( { url:url} ) + processData: true, + success: (data, status, xhr) => + + # validate form + console.log(data) + if data.result is 'ok' + @urlStatus.attr('data-state', 'success') + @linkErrorMessage.text('') + @nextStartMigration.removeClass('hide') + else + @urlStatus.attr('data-state', 'error') + @linkErrorMessage.text( data.message_human || data.message ) + @nextStartMigration.addClass('hide') + + ) + @delay( callback, 700, 'import_otrs_url' ) + + startMigration: (e) => + e.preventDefault() + @showImportState() + @ajax( + id: 'import_start', + type: 'POST', + url: @apiPath + '/import/otrs/import_start', + processData: true, + success: (data, status, xhr) => + + # validate form + console.log(data) + if data.result is 'ok' + @delay( @updateMigration, 3000 ) + ) + + + updateMigration: => + @showImportState() + @ajax( + id: 'import_status', + type: 'GET', + url: @apiPath + '/import/otrs/import_status', + processData: true, + success: (data, status, xhr) => + + # validate form + console.log(data) + for key, item of data.data + element = @$('.js-' + key.toLowerCase() ) + element.find('.js-done').text(item.done) + element.find('.js-total').text(item.total) + element.find('progress').attr('max', item.total ) + element.find('progress').attr('value', item.done ) + if item.total is item.done + element.addClass('is-done') + else + element.removeClass('is-done') + + @delay( @updateMigration, 3000 ) + ) + +App.Config.set( 'import/otrs', Index, 'Routes' ) +App.Config.set( 'otrs', { + image: 'otrs-logo.png' + title: 'OTRS' + name: 'OTRS' + url: '#import/otrs' +}, 'ImportPlugins' ) diff --git a/app/assets/javascripts/app/views/getting_started/import.jst.eco b/app/assets/javascripts/app/views/getting_started/import.jst.eco deleted file mode 100644 index f5c207081..000000000 --- a/app/assets/javascripts/app/views/getting_started/import.jst.eco +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
-

<%- @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 index b126910fe..b7558ab4f 100644 --- a/app/assets/javascripts/app/views/getting_started/index.jst.eco +++ b/app/assets/javascripts/app/views/getting_started/index.jst.eco @@ -4,7 +4,7 @@

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

- <%- @T('Import from other System') %> + <%- @T('Import from other System') %> | <%- @T('Setup new System') %>
diff --git a/app/assets/javascripts/app/views/import/index.jst.eco b/app/assets/javascripts/app/views/import/index.jst.eco new file mode 100644 index 000000000..5d7ecdfd7 --- /dev/null +++ b/app/assets/javascripts/app/views/import/index.jst.eco @@ -0,0 +1,17 @@ +
+
+
+

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

+
+
+ <% for key, item of @items: %> + + <% end %> +
+
+ +
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/import/otrs.jst.eco b/app/assets/javascripts/app/views/import/otrs.jst.eco new file mode 100644 index 000000000..69aa0ce87 --- /dev/null +++ b/app/assets/javascripts/app/views/import/otrs.jst.eco @@ -0,0 +1,91 @@ +
+
+
+

<%- @T('Create OTRS Migration Plugin') %>

+
+

+ <%- @T('Personalise Migration Plugin ...') %> +

+
+ +
+
+

<%- @T('Download OTRS Migration Plugin') %>

+
+

+ <%- @T('Download and install your personalised OTRS Migration Plugin on your OTRS System') %>: +

+ <%- @T('Personal Migration Plugin') %> +
+
+ <%- @T('Go Back') %> + +
+
+
+

<%- @T('Link OTRS') %>

+
+

+ <%- @T('Enter the link provided by the plugin at the end of the installation to link the two systems') %>: +

+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ <%- @T('Go Back') %> +
<%- @T('Migrate OTRS Data') %>
+
+
+ +
+

<%- @T('OTRS Migration') %>

+
+ + + + + + + +
+ <%- @T('Configuration') %> + +
+
+
+
+
-/- + <%- @T('Users') %> + +
+
+
+
+
-/- + <%- @T('Tickets') %> + +
+
+
+
+
+
+ +
+ +
+
\ No newline at end of file diff --git a/app/controllers/getting_started_controller.rb b/app/controllers/getting_started_controller.rb index 6a6d10ba1..be3acc387 100644 --- a/app/controllers/getting_started_controller.rb +++ b/app/controllers/getting_started_controller.rb @@ -42,8 +42,10 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} # return result render :json => { - :setup_done => setup_done, - :groups => groups, + :setup_done => setup_done, + :import_mode => Setting.get('import_mode'), + :import_backend => Setting.get('import_backend'), + :groups => groups, } end @@ -201,10 +203,10 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} # connection test translationMap = { - 'authentication failed' => 'Authentication failed!', + '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!', + 'No route to host' => 'No route to host!', + 'Connection refused' => 'Connection refused!', } if params[:adapter] == 'IMAP' begin @@ -253,7 +255,7 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} 'x-zammad-ignore' => 'true', } ) - (1..10).each {|loop| + (1..5).each {|loop| sleep 10 # fetch mailbox @@ -315,7 +317,7 @@ curl http://localhost/api/v1/getting_started.json -v -u #{login}:#{password} private def setup_done - #return false + return false count = User.all.count() done = true if count <= 2 diff --git a/app/controllers/import_otrs_controller.rb b/app/controllers/import_otrs_controller.rb new file mode 100644 index 000000000..a06928828 --- /dev/null +++ b/app/controllers/import_otrs_controller.rb @@ -0,0 +1,132 @@ +# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ + +class ImportOtrsController < ApplicationController + + def url_check + return if setup_done_response + + + # validate + if !params[:url] ||params[:url] !~ /^(http|https):\/\/.+?$/ + render :json => { + :result => 'invalid', + :message => '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!', + } + + # try connecting to otrs + response = UserAgent.request(params[:url]) + if !response.success? && response.code.to_s !~ /^40.$/ + message_human = '' + translationMap.each {|key, message| + if response.error.to_s =~ /#{Regexp.escape(key)}/i + message_human = message + end + } + render :json => { + :result => 'invalid', + :message_human => message_human, + :message => response.error.to_s, + } + return + end + + message_human = 'Host found, but it seems to be no OTRS installation!' + suffixes = ['/public.pl', '/otrs/public.pl'] + suffixes.each {|suffix| + url = params[:url] + suffix + '?Action=ZammadMigrator' + # strip multible / in url + url.gsub!(/([^:])(\/+\/)/, "\\1/") + response = UserAgent.request( url ) + + Setting.set('import_otrs_endpoint', url) + Setting.set('import_mode', true) + Setting.set('import_backend', 'otrs') + if response.body =~ /zammad migrator/ + render :json => { + :url => url, + :result => 'ok', + } + return + elsif response.body =~ /(otrs\sag|otrs.com|otrs.org)/i + message_human = 'Host found, but no OTRS migrator is installed!' + end + } + + + # return result + render :json => { + :result => 'invalid', + :message_human => message_human, + } + end + + def import_start + return if setup_done_response + + # start migration + + + render :json => { + :result => 'ok', + } + end + + def import_status + return if setup_done_response + + + # start migration + + + render :json => { + :data => { + :User => { + :total => 1300, + :done => rand(1300).to_i, + }, + :Ticket => { + :total => 13000, + :done => rand(13000).to_i, + }, + :Config => { + :total => 1, + :done => rand(2).to_i + }, + }, + :result => 'in_progress', + } + 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/config/routes/getting_started.rb b/config/routes/getting_started.rb index 520a9acaa..505f5a15e 100644 --- a/config/routes/getting_started.rb +++ b/config/routes/getting_started.rb @@ -3,7 +3,7 @@ Zammad::Application.routes.draw do # getting_started 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_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 diff --git a/config/routes/import_otrs.rb b/config/routes/import_otrs.rb new file mode 100644 index 000000000..8b8c58079 --- /dev/null +++ b/config/routes/import_otrs.rb @@ -0,0 +1,9 @@ +Zammad::Application.routes.draw do + api_path = Rails.configuration.api_path + + # import otrs + match api_path + '/import/otrs/url_check', :to => 'import_otrs#url_check', :via => :post + match api_path + '/import/otrs/import_start', :to => 'import_otrs#import_start', :via => :post + match api_path + '/import/otrs/import_status', :to => 'import_otrs#import_status', :via => :get + +end \ No newline at end of file diff --git a/db/seeds.rb b/db/seeds.rb index 18e72a739..b228d867a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1115,6 +1115,15 @@ Setting.create_if_not_exists( :state => false, :frontend => true ) +Setting.create_if_not_exists( + :title => 'Import Backend', + :name => 'import_backend', + :area => 'Import::Base::Internal', + :description => 'Set backend which is used for import.', + :options => {}, + :state => '', + :frontend => true +) Setting.create_if_not_exists( :title => 'Ignore Escalation/SLA Information', :name => 'import_ignore_sla',