Skip to content

Commit

Permalink
Fixes issue zammad#865 - Freshdesk import
Browse files Browse the repository at this point in the history
  • Loading branch information
thorsteneckel committed May 25, 2021
1 parent a1d17ac commit 8790e38
Show file tree
Hide file tree
Showing 96 changed files with 7,963 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .rubocop/todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Metrics/AbcSize:
- 'app/controllers/getting_started_controller.rb'
- 'app/controllers/import_otrs_controller.rb'
- 'app/controllers/import_zendesk_controller.rb'
- 'app/controllers/import_freshdesk_controller.rb'
- 'app/controllers/integration/check_mk_controller.rb'
- 'app/controllers/integration/cti_controller.rb'
- 'app/controllers/integration/idoit_controller.rb'
Expand Down Expand Up @@ -466,6 +467,7 @@ Metrics/CyclomaticComplexity:
- 'app/controllers/getting_started_controller.rb'
- 'app/controllers/import_otrs_controller.rb'
- 'app/controllers/import_zendesk_controller.rb'
- 'app/controllers/import_freshdesk_controller.rb'
- 'app/controllers/integration/check_mk_controller.rb'
- 'app/controllers/integration/smime_controller.rb'
- 'app/controllers/knowledge_base/public/categories_controller.rb'
Expand Down
194 changes: 194 additions & 0 deletions app/assets/javascripts/app/controllers/import_freshdesk.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
class ImportFreshdesk extends App.ControllerWizardFullScreen
className: 'getstarted fit'
elements:
'.input-feedback': 'urlStatus'
'[data-target=freshdesk-credentials]': 'nextEnterCredentials'
'[data-target=freshdesk-start-migration]': 'nextStartMigration'
'#freshdesk-subdomain': 'freshdeskSubdomain'
'#freshdesk-subdomain-addon': 'freshdeskSubdomainAddon'
'.freshdesk-subdomain-error': 'linkErrorMessage'
'.freshdesk-api-token-error': 'apiTokenErrorMessage'
'#freshdesk-email': 'freshdeskEmail'
'#freshdesk-api-token': 'freshdeskApiToken'
'.js-ticket-count-info': 'ticketCountInfo'
updateMigrationDisplayLoop: 0

events:
'click .js-freshdesk-credentials': 'showCredentials'
'click .js-migration-start': 'startMigration'
'keyup #freshdesk-subdomain': 'updateUrl'
'keyup #freshdesk-api-token': 'updateApiToken'

constructor: ->
super

# set title
@title 'Import'

@freshdeskDomain = '.freshdesk.com'

# redirect to login if master user already exists
if @Config.get('system_init_done')
@navigate '#login'
return

@fetch()

fetch: ->

# get data
@ajax(
id: 'getting_started'
type: 'GET'
url: "#{@apiPath}/getting_started"
processData: true
success: (data, status, xhr) =>

# check if import is active
if data.import_mode == true && data.import_backend != 'freshdesk'
@navigate "#import/#{data.import_backend}", { emptyEl: true }
return

# render page
@render()

if data.import_mode == true
@showImportState()
@updateMigration()
)

render: ->
@replaceWith App.view('import/freshdesk')(
freshdeskDomain: @freshdeskDomain
)

updateUrl: (e) =>
@urlStatus.attr('data-state', 'loading')
@freshdeskSubdomainAddon.attr('style', 'padding-right: 42px')
@linkErrorMessage.text('')

# get data
callback = =>
@ajax(
id: 'import_freshdesk_url'
type: 'POST'
url: "#{@apiPath}/import/freshdesk/url_check"
data: JSON.stringify(url: "https://#{@freshdeskSubdomain.val()}#{@freshdeskDomain}")
processData: true
success: (data, status, xhr) =>

# validate form
if data.result is 'ok'
@urlStatus.attr('data-state', 'success')
@linkErrorMessage.text('')
@nextEnterCredentials.removeClass('hide')
else
@urlStatus.attr('data-state', 'error')
@linkErrorMessage.text( data.message_human || data.message)
@nextEnterCredentials.addClass('hide')

)
@delay( callback, 700, 'import_freshdesk_url' )

updateApiToken: (e) =>
@urlStatus.attr('data-state', 'loading')
@apiTokenErrorMessage.text('')

# get data
callback = =>
@ajax(
id: 'import_freshdesk_api_token'
type: 'POST'
url: "#{@apiPath}/import/freshdesk/credentials_check"
data: JSON.stringify(token: @freshdeskApiToken.val())
processData: true
success: (data, status, xhr) =>

# validate form
if data.result is 'ok'
@urlStatus.attr('data-state', 'success')
@apiTokenErrorMessage.text('')
@nextStartMigration.removeClass('hide')
else
@urlStatus.attr('data-state', 'error')
@apiTokenErrorMessage.text(data.message_human || data.message)
@nextStartMigration.addClass('hide')

)
@delay(callback, 700, 'import_freshdesk_api_token')

showCredentials: (e) =>
e.preventDefault()
@urlStatus.attr('data-state', '')
@$('[data-slide=freshdesk-subdomain]').toggleClass('hide')
@$('[data-slide=freshdesk-credentials]').toggleClass('hide')

showImportState: =>
@$('[data-slide=freshdesk-subdomain]').addClass('hide')
@$('[data-slide=freshdesk-credentials]').addClass('hide')
@$('[data-slide=freshdesk-import]').removeClass('hide')

startMigration: (e) =>
e.preventDefault()
@showImportState()
@ajax(
id: 'import_start'
type: 'POST'
url: "#{@apiPath}/import/freshdesk/import_start"
processData: true
success: (data, status, xhr) =>

# validate form
if data.result is 'ok'
@delay(@updateMigration, 3000)
)

updateMigration: =>
@updateMigrationDisplayLoop += 1
@showImportState()
@ajax(
id: 'import_status'
type: 'GET'
url: "#{@apiPath}/import/freshdesk/import_status"
processData: true
success: (data, status, xhr) =>

if _.isEmpty(data.result) && @updateMigrationDisplayLoop > 16
@$('.js-error').removeClass('hide')
@$('.js-error').html(App.i18n.translateContent('Background process did not start or has not finished! Please contact your support.'))
return

if !_.isEmpty(data.result['error'])
@$('.js-error').removeClass('hide')
@$('.js-error').html(App.i18n.translateContent(data.result['error']))
else
@$('.js-error').addClass('hide')

if !_.isEmpty(data.finished_at) && _.isEmpty(data.result['error'])
window.location.reload()
return

if !_.isEmpty(data.result)
for model, stats of data.result
if stats.sum > stats.total
stats.sum = stats.total

element = @$('.js-' + model.toLowerCase() )
element.find('.js-done').text(stats.sum)
element.find('.js-total').text(stats.total)
element.find('progress').attr('max', stats.total )
element.find('progress').attr('value', stats.sum )
if stats.total <= stats.sum
element.addClass('is-done')
else
element.removeClass('is-done')
@delay(@updateMigration, 5000)
)

App.Config.set('import/freshdesk', ImportFreshdesk, 'Routes')
App.Config.set('freshdesk', {
title: 'Freshdesk'
name: 'Freshdesk'
class: 'js-freshdesk'
url: '#import/freshdesk'
}, 'ImportPlugins')
7 changes: 2 additions & 5 deletions app/assets/javascripts/app/controllers/import_zendesk.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,13 @@ class ImportZendesk extends App.ControllerWizardFullScreen
success: (data, status, xhr) =>

# validate form
console.log(data)
if data.result is 'ok'
@urlStatus.attr('data-state', 'success')
@linkErrorMessage.text('')
@nextEnterCredentials.removeClass('hide')
else
@urlStatus.attr('data-state', 'error')
@linkErrorMessage.text( data.message_human || data.message)
@linkErrorMessage.text( data.message_human || data.message)
@nextEnterCredentials.addClass('hide')

)
Expand All @@ -101,14 +100,13 @@ class ImportZendesk extends App.ControllerWizardFullScreen
success: (data, status, xhr) =>

# validate form
console.log(data)
if data.result is 'ok'
@urlStatus.attr('data-state', 'success')
@apiTokenErrorMessage.text('')
@nextStartMigration.removeClass('hide')
else
@urlStatus.attr('data-state', 'error')
@apiTokenErrorMessage.text(data.message_human || data.message)
@apiTokenErrorMessage.text(data.message_human || data.message)
@nextStartMigration.addClass('hide')

)
Expand Down Expand Up @@ -139,7 +137,6 @@ class ImportZendesk extends App.ControllerWizardFullScreen
success: (data, status, xhr) =>

# validate form
console.log(data)
if data.result is 'ok'
@delay(@updateMigration, 3000)
)
Expand Down
109 changes: 109 additions & 0 deletions app/assets/javascripts/app/views/import/freshdesk.jst.eco
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<div class="main flex vertical centered darkBackground">
<%- @Icon('full-logo', 'wizard-logo') %>
<div class="import wizard">
<div class="wizard-slide vertical" data-slide="freshdesk-subdomain">
<h2><%- @T('%s URL', 'Freshdesk') %></h2>
<div class="wizard-body flex vertical justified">
<p>
<%- @T('Enter the Subdomain of your %s system', 'Freshdesk') %>:
</p>
<div class="form-group">
<label for="freshdesk-subdomain"><%- @T('%s Subdomain', 'Freshdesk') %></label>
<div class="u-positionOrigin">
<div class="input-group">
<input type="text" id="freshdesk-subdomain" class="form-control" placeholder="example" name="freshdesk-subdomain" aria-describedby="freshdesk-subdomain-addon">
<span class="input-group-addon" id="freshdesk-subdomain-addon"><%- @freshdeskDomain %></span>
</div>
<div class="input-feedback input-feedback--no-background centered">
<div class="small loading icon"></div>
<%- @Icon('diagonal-cross', 'icon-error') %>
<%- @Icon('checkmark') %>
</div>
</div>
<div class="error freshdesk-subdomain-error"></div>
</div>
</div>
<div class="wizard-controls horizontal center">
<a class="btn btn--text btn--secondary" href="#import"><%- @T('Go Back') %></a>
<div class="btn btn--primary align-right hide js-freshdesk-credentials" data-target="freshdesk-credentials"><%- @T('Enter credentials') %></div>
</div>
</div>

<div class="wizard-slide vertical hide" data-slide="freshdesk-credentials">
<h2><%- @T('%s credentials', 'Freshdesk') %></h2>
<div class="wizard-body flex vertical justified">
<p>
<a class="js-freshdeskUrlApiToken" href="https://support.freshdesk.com/support/solutions/articles/215517-how-to-find-your-api-key" target="_blank"><%- @T('Enter your %s API token gained from your account profile settings.', 'Freshdesk') %></a>
</p>
<p>
<%- @T('Attention: These will be your login password after the import is completed.') %>
</p>
<div class="form-group">
<label for="freshdesk-api-token"><%- @T('API token') %></label>
<div class="u-positionOrigin">
<input type="text" id="freshdesk-api-token" class="form-control" placeholder="XYZ3133723421111" name="freshdesk-api-token">
<div class="input-feedback centered">
<div class="small loading icon"></div>
<%- @Icon('diagonal-cross', 'icon-error') %>
<%- @Icon('checkmark') %>
</div>
</div>
<div class="error freshdesk-api-token-error"></div>
</div>
</div>
<div class="wizard-controls horizontal center">
<a class="btn btn--text btn--secondary" href="#import"><%- @T('Go Back') %></a>
<div class="btn btn--primary align-right hide js-migration-start" data-target="freshdesk-start-migration"><%- @T('Migrate %s Data', 'Freshdesk') %></div>
</div>
</div>

<div class="wizard-slide vertical hide" data-slide="freshdesk-import">
<h2><%- @T('%s Migration', 'Freshdesk') %></h2>
<div class="alert alert--danger hide js-error" role="alert"></div>
<div class="wizard-body flex vertical justified">
<table class="progressTable">
<tr class="js-groups">
<td><span class="js-done">-</span>/<span class="js-total">-</span>
<td><span><%- @T('Groups') %></span>
<td class="progressTable-progressCell">
<div class="horizontal center">
<div class="flex"><progress max="42" value="42"></progress></div>
<%- @Icon('checkmark') %>
</div>
</tr>
<tr class="js-organizations">
<td><span class="js-done">-</span>/<span class="js-total">-</span>
<td><span><%- @T('Organizations') %></span>
<td class="progressTable-progressCell">
<div class="horizontal center">
<div class="flex"><progress max="42" value="42"></progress></div>
<%- @Icon('checkmark') %>
</div>
</tr>
<tr class="js-users">
<td><span class="js-done">-</span>/<span class="js-total">-</span>
<td><span><%- @T('Users') %></span>
<td class="progressTable-progressCell">
<div class="horizontal center">
<div class="flex"><progress max="42" value="42"></progress></div>
<%- @Icon('checkmark') %>
</div>
</tr>
<tr class="js-tickets">
<td><span class="js-done">-</span>/<span class="js-total">-</span>
<td><span><%- @T('Tickets') %></span>
<td class="progressTable-progressCell">
<div class="horizontal center">
<div class="flex"><progress max="42" value="42"></progress></div>
<%- @Icon('checkmark') %>
</div>
</tr>
</table>
</div>
<div class="wizard-controls horizontal center">
<a href="#" class="btn btn--primary align-right hide js-finished"><%- @T('done') %></a>
</div>
</div>

</div>
</div>
4 changes: 2 additions & 2 deletions app/assets/javascripts/app/views/import/zendesk.jst.eco
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</div>
<label for="zendesk-api-token"><%- @T('API token') %></label>
<div class="u-positionOrigin">
<input type="email" id="zendesk-api-token" class="form-control" placeholder="XYZ3133723421111" name="zendesk-api-token">
<input type="text" id="zendesk-api-token" class="form-control" placeholder="XYZ3133723421111" name="zendesk-api-token">
<div class="input-feedback centered">
<div class="small loading icon"></div>
<%- @Icon('diagonal-cross', 'icon-error') %>
Expand Down Expand Up @@ -108,4 +108,4 @@
</div>

</div>
</div>
</div>
8 changes: 8 additions & 0 deletions app/assets/stylesheets/zammad.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9196,6 +9196,14 @@ label + .wizard-buttonList {
width: 52px;
border-radius: 0 5px 5px 0;
background: linear-gradient(to right, rgba(255,255,255,0), white 33%);

&--no-background {
background: none;
}
}

.input-feedback--no-background {
background: none;
}

.input-feedback .icon {
Expand Down
Loading

0 comments on commit 8790e38

Please sign in to comment.