Added IMAP folder support.

This commit is contained in:
Martin Edenhofer 2016-03-10 14:41:42 +01:00
parent ee991e1423
commit ec1c9a548e
9 changed files with 71 additions and 36 deletions

View file

@ -38,7 +38,7 @@ class App.ControllerForm extends App.Controller
@form @form
showAlert: (message) => showAlert: (message) =>
@form.find('.alert').removeClass('hide').html( App.i18n.translateContent(message) ) @form.find('.alert').removeClass('hide').html(App.i18n.translateContent(message))
hideAlert: => hideAlert: =>
@form.find('.alert').addClass('hide').html() @form.find('.alert').addClass('hide').html()
@ -356,7 +356,7 @@ class App.ControllerForm extends App.Controller
hit = false hit = false
for refAttribute, refValue of attribute.shown_if for refAttribute, refValue of attribute.shown_if
if params[refAttribute] if params[refAttribute]
if _.isArray( refValue ) if _.isArray(refValue)
for item in refValue for item in refValue
if params[refAttribute].toString() is item.toString() if params[refAttribute].toString() is item.toString()
hit = true hit = true

View file

@ -702,10 +702,10 @@ class App.WizardModal extends App.Controller
@$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus() @$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus()
showAlert: (screen, message) => showAlert: (screen, message) =>
@$(".#{screen}").find('.alert').removeClass('hide').text( App.i18n.translateInline( message ) ) @$(".#{screen}").find('.alert').first().removeClass('hide').text(App.i18n.translatePlain(message))
hideAlert: (screen) => hideAlert: (screen) =>
@$(".#{screen}").find('.alert').addClass('hide') @$(".#{screen}").find('.alert').first().addClass('hide')
disable: (e) => disable: (e) =>
@formDisable(e) @formDisable(e)

View file

@ -499,6 +499,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
{ name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 120, null: false, placeholder: 'support@example.com', autocapitalize: false, autocomplete: 'off' }, { name: 'email', display: 'Email', tag: 'input', type: 'email', limit: 120, null: false, placeholder: 'support@example.com', autocapitalize: false, autocomplete: 'off' },
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true }, { name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true },
{ name: 'group_id', display: 'Destination Group', tag: 'select', null: false, relation: 'Group', nulloption: true }, { name: 'group_id', display: 'Destination Group', tag: 'select', null: false, relation: 'Group', nulloption: true },
{ name: 'folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
] ]
new App.ControllerForm( new App.ControllerForm(
el: @$('.base-settings'), el: @$('.base-settings'),
@ -528,13 +529,25 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
{ name: 'options::host', display: 'Host', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false }, { 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, autocomplete: 'off', }, { name: 'options::user', display: 'User', tag: 'input', type: 'text', limit: 120, null: false, autocapitalize: false, autocomplete: 'off', },
{ name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true }, { name: 'options::password', display: 'Password', tag: 'input', type: 'password', limit: 120, null: false, autocapitalize: false, autocomplete: 'new-password', single: true },
{ name: 'options::folder', display: 'Folder', tag: 'input', type: 'text', limit: 120, null: true, autocapitalize: false },
] ]
showHideFolder = (params, attribute, attributes, classname, form, ui) ->
return if !params
if params.adapter is 'imap'
ui.show('options::folder')
return
ui.hide('options::folder')
new App.ControllerForm( new App.ControllerForm(
el: @$('.base-inbound-settings'), el: @$('.base-inbound-settings'),
model: model:
configure_attributes: configureAttributesInbound configure_attributes: configureAttributesInbound
className: '' className: ''
params: @account.inbound params: @account.inbound
handlers: [
showHideFolder
]
) )
toggleOutboundAdapter: => toggleOutboundAdapter: =>
@ -544,6 +557,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
if @account['meta'] if @account['meta']
channel_used['options']['user'] = @account['meta']['email'] channel_used['options']['user'] = @account['meta']['email']
channel_used['options']['password'] = @account['meta']['password'] channel_used['options']['password'] = @account['meta']['password']
channel_used['options']['folder'] = @account['meta']['folder']
# show used backend # show used backend
@$('.base-outbound-settings').html('') @$('.base-outbound-settings').html('')
@ -574,14 +588,14 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
params.channel_id = @channel.id params.channel_id = @channel.id
@disable(e) @disable(e)
@$('.js-probe .js-email').text( params.email ) @$('.js-probe .js-email').text(params.email)
@showSlide('js-probe') @showSlide('js-probe')
@ajax( @ajax(
id: 'email_probe' id: 'email_probe'
type: 'POST' type: 'POST'
url: @apiPath + '/channels/email_probe' url: @apiPath + '/channels/email_probe'
data: JSON.stringify( params ) data: JSON.stringify(params)
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result is 'ok' if data.result is 'ok'
@ -589,8 +603,8 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
for key, value of data.setting for key, value of data.setting
@account[key] = value @account[key] = value
if !@channel && data.content_messages && data.content_messages > 0 if data.content_messages && data.content_messages > 0
message = App.i18n.translateContent('We have already found %s emails in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages) message = App.i18n.translateContent('We have already found %s email(s) in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages)
@$('.js-inbound-acknowledge .js-message').html(message) @$('.js-inbound-acknowledge .js-message').html(message)
@$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro') @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro')
@$('.js-inbound-acknowledge .js-next').attr('data-slide', '') @$('.js-inbound-acknowledge .js-next').attr('data-slide', '')
@ -604,12 +618,12 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
else if data.result is 'duplicate' else if data.result is 'duplicate'
@showSlide('js-intro') @showSlide('js-intro')
@showAlert('js-intro', 'Account already exists!' ) @showAlert('js-intro', 'Account already exists!')
else else
@showSlide('js-inbound') @showSlide('js-inbound')
@showAlert('js-inbound', 'Unable to detect your server settings. Manual configuration needed.' ) @showAlert('js-inbound', 'Unable to detect your server settings. Manual configuration needed.')
@$('.js-inbound [name="options::user"]').val( @account['meta']['email'] ) @$('.js-inbound [name="options::user"]').val(@account['meta']['email'])
@$('.js-inbound [name="options::password"]').val( @account['meta']['password'] ) @$('.js-inbound [name="options::password"]').val(@account['meta']['password'])
@enable(e) @enable(e)
fail: => fail: =>
@ -635,7 +649,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
id: 'email_inbound' id: 'email_inbound'
type: 'POST' type: 'POST'
url: @apiPath + '/channels/email_inbound' url: @apiPath + '/channels/email_inbound'
data: JSON.stringify( params ) data: JSON.stringify(params)
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result is 'ok' if data.result is 'ok'
@ -643,8 +657,8 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
# remember account settings # remember account settings
@account.inbound = params @account.inbound = params
if !@channel && data.content_messages && data.content_messages > 0 if data.content_messages && data.content_messages > 0
message = App.i18n.translateContent('We have already found %s emails in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages) message = App.i18n.translateContent('We have already found %s email(s) in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages)
@$('.js-inbound-acknowledge .js-message').html(message) @$('.js-inbound-acknowledge .js-message').html(message)
@$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-inbound') @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-inbound')
@$('.js-inbound-acknowledge .js-next').unbind('click.verify') @$('.js-inbound-acknowledge .js-next').unbind('click.verify')
@ -655,21 +669,21 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
# fill user / password based on inbound settings # fill user / password based on inbound settings
if !@channel if !@channel
if @account['inbound']['options'] if @account['inbound']['options']
@$('.js-outbound [name="options::host"]').val( @account['inbound']['options']['host'] ) @$('.js-outbound [name="options::host"]').val(@account['inbound']['options']['host'])
@$('.js-outbound [name="options::user"]').val( @account['inbound']['options']['user'] ) @$('.js-outbound [name="options::user"]').val(@account['inbound']['options']['user'])
@$('.js-outbound [name="options::password"]').val( @account['inbound']['options']['password'] ) @$('.js-outbound [name="options::password"]').val(@account['inbound']['options']['password'])
else else
@$('.js-outbound [name="options::user"]').val( @account['meta']['email'] ) @$('.js-outbound [name="options::user"]').val(@account['meta']['email'])
@$('.js-outbound [name="options::password"]').val( @account['meta']['password'] ) @$('.js-outbound [name="options::password"]').val(@account['meta']['password'])
else else
@showSlide('js-inbound') @showSlide('js-inbound')
@showAlert('js-inbound', data.message_human || data.message ) @showAlert('js-inbound', data.message_human || data.message)
@showInvalidField('js-inbound', data.invalid_field) @showInvalidField('js-inbound', data.invalid_field)
@enable(e) @enable(e)
fail: => fail: =>
@showSlide('js-inbound') @showSlide('js-inbound')
@showAlert('js-inbound', data.message_human || data.message ) @showAlert('js-inbound', data.message_human || data.message)
@showInvalidField('js-inbound', data.invalid_field) @showInvalidField('js-inbound', data.invalid_field)
@enable(e) @enable(e)
) )
@ -682,7 +696,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
params['email'] = @account['meta']['email'] params['email'] = @account['meta']['email']
if !params['email'] && @channel if !params['email'] && @channel
email_addresses = App.EmailAddress.search( filter: { channel_id: @channel.id } ) email_addresses = App.EmailAddress.search(filter: { channel_id: @channel.id })
if email_addresses && email_addresses[0] if email_addresses && email_addresses[0]
params['email'] = email_addresses[0].email params['email'] = email_addresses[0].email
@ -709,12 +723,12 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
@verify(@account) @verify(@account)
else else
@showSlide('js-outbound') @showSlide('js-outbound')
@showAlert('js-outbound', data.message_human || data.message ) @showAlert('js-outbound', data.message_human || data.message)
@showInvalidField('js-outbound', data.invalid_field) @showInvalidField('js-outbound', data.invalid_field)
@enable(e) @enable(e)
fail: => fail: =>
@showSlide('js-outbound') @showSlide('js-outbound')
@showAlert('js-outbound', data.message_human || data.message ) @showAlert('js-outbound', data.message_human || data.message)
@showInvalidField('js-outbound', data.invalid_field) @showInvalidField('js-outbound', data.invalid_field)
@enable(e) @enable(e)
) )
@ -732,7 +746,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
account.group_id = @channel.group_id account.group_id = @channel.group_id
if !account.email && @channel if !account.email && @channel
email_addresses = App.EmailAddress.search( filter: { channel_id: @channel.id } ) email_addresses = App.EmailAddress.search(filter: { channel_id: @channel.id })
if email_addresses && email_addresses[0] if email_addresses && email_addresses[0]
account.email = email_addresses[0].email account.email = email_addresses[0].email
@ -740,7 +754,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
id: 'email_verify' id: 'email_verify'
type: 'POST' type: 'POST'
url: @apiPath + '/channels/email_verify' url: @apiPath + '/channels/email_verify'
data: JSON.stringify( account ) data: JSON.stringify(account)
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result is 'ok' if data.result is 'ok'
@ -748,11 +762,11 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
else else
if data.source is 'inbound' || data.source is 'outbound' if data.source is 'inbound' || data.source is 'outbound'
@showSlide("js-#{data.source}") @showSlide("js-#{data.source}")
@showAlert("js-#{data.source}", data.message_human || data.message ) @showAlert("js-#{data.source}", data.message_human || data.message)
@showInvalidField("js-#{data.source}", data.invalid_field) @showInvalidField("js-#{data.source}", data.invalid_field)
else else
if count is 2 if count is 2
@showAlert('js-verify', data.message_human || data.message ) @showAlert('js-verify', data.message_human || data.message)
@delay( @delay(
=> =>
@showSlide('js-intro') @showSlide('js-intro')
@ -882,12 +896,12 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
@el.remove() @el.remove()
else else
@showSlide('js-outbound') @showSlide('js-outbound')
@showAlert('js-outbound', data.message_human || data.message ) @showAlert('js-outbound', data.message_human || data.message)
@showInvalidField('js-outbound', data.invalid_field) @showInvalidField('js-outbound', data.invalid_field)
@enable(e) @enable(e)
fail: => fail: =>
@showSlide('js-outbound') @showSlide('js-outbound')
@showAlert('js-outbound', data.message_human || data.message ) @showAlert('js-outbound', data.message_human || data.message)
@showInvalidField('js-outbound', data.invalid_field) @showInvalidField('js-outbound', data.invalid_field)
@enable(e) @enable(e)
) )

View file

@ -731,7 +731,7 @@ class ChannelEmail extends App.WizardFullScreen
@account[key] = value @account[key] = value
if data.content_messages && data.content_messages > 0 if data.content_messages && data.content_messages > 0
message = App.i18n.translateContent('We have already found %s emails in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages) message = App.i18n.translateContent('We have already found %s email(s) in your mailbox. Zammad will move it all from your mailbox into Zammad.', data.content_messages)
@$('.js-inbound-acknowledge .js-message').html(message) @$('.js-inbound-acknowledge .js-message').html(message)
@$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro') @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro')
@$('.js-inbound-acknowledge .js-next').attr('data-slide', '') @$('.js-inbound-acknowledge .js-next').attr('data-slide', '')

View file

@ -52,6 +52,9 @@
<tr> <tr>
<td><%- @T('User') %> <td><%- @T('User') %>
<td><%= channel.options.inbound.options.user %> <td><%= channel.options.inbound.options.user %>
<% if channel.options.inbound.options.folder: %>
(<%- @T('Folder') %>: <%= channel.options.inbound.options.folder %>)
<% end %>
<tr> <tr>
<td><%- @T('Host') %> <td><%- @T('Host') %>
<td><%= channel.options.inbound.options.host %> <td><%= channel.options.inbound.options.host %>

View file

@ -149,6 +149,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
result = EmailHelper::Probe.full( result = EmailHelper::Probe.full(
email: params[:email], email: params[:email],
password: params[:password], password: params[:password],
folder: params[:folder],
) )
# verify if user+host already exists # verify if user+host already exists

View file

@ -65,7 +65,7 @@ returns
end end
Timeout.timeout(timeout) do Timeout.timeout(timeout) do
@imap = Net::IMAP.new( options[:host], port, ssl, nil, false ) @imap = Net::IMAP.new(options[:host], port, ssl, nil, false)
end end
# try LOGIN, if not - try plain # try LOGIN, if not - try plain
@ -90,7 +90,7 @@ returns
# check mode only # check mode only
if check_type == 'check' if check_type == 'check'
Rails.logger.info 'check only mode, fetch no emails' Rails.logger.info 'check only mode, fetch no emails'
content_max_check = 5 content_max_check = 2
content_messages = 0 content_messages = 0
# check messages # check messages

View file

@ -54,7 +54,7 @@ returns
Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})" Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})"
@pop = Net::POP3.new( options[:host], port ) @pop = Net::POP3.new(options[:host], port)
#@pop.set_debug_output $stderr #@pop.set_debug_output $stderr
# on check, reduce open_timeout to have faster probing # on check, reduce open_timeout to have faster probing

View file

@ -8,6 +8,7 @@ get result of probe
result = EmailHelper::Probe.full( result = EmailHelper::Probe.full(
email: 'znuny@example.com', email: 'znuny@example.com',
password: 'somepassword', password: 'somepassword',
folder: 'some_folder', # optional im imap
) )
returns on success returns on success
@ -23,6 +24,7 @@ returns on success
ssl: true, ssl: true,
user: 'some@example.com', user: 'some@example.com',
password: 'password', password: 'password',
folder: 'some_folder', # optional im imap
}, },
}, },
outbound: { outbound: {
@ -71,6 +73,11 @@ returns on fail
next if domain_to_check !~ /#{settings[:domain]}/i next if domain_to_check !~ /#{settings[:domain]}/i
# add folder to config if needed
if !params[:folder].empty? && settings[:inbound] && settings[:inbound][:options]
settings[:inbound][:options][:folder] = params[:folder]
end
# probe inbound # probe inbound
Rails.logger.debug "INBOUND PROBE PROVIDER: #{settings[:inbound].inspect}" Rails.logger.debug "INBOUND PROBE PROVIDER: #{settings[:inbound].inspect}"
result_inbound = EmailHelper::Probe.inbound(settings[:inbound]) result_inbound = EmailHelper::Probe.inbound(settings[:inbound])
@ -103,6 +110,12 @@ returns on fail
} }
success = false success = false
inbound_map.each {|config| inbound_map.each {|config|
# add folder to config if needed
if !params[:folder].empty? && config[:options]
config[:options][:folder] = params[:folder]
end
Rails.logger.debug "INBOUND PROBE GUESS: #{config.inspect}" Rails.logger.debug "INBOUND PROBE GUESS: #{config.inspect}"
result_inbound = EmailHelper::Probe.inbound(config) result_inbound = EmailHelper::Probe.inbound(config)
Rails.logger.debug "INBOUND RESULT GUESS: #{result_inbound.inspect}" Rails.logger.debug "INBOUND RESULT GUESS: #{result_inbound.inspect}"
@ -165,6 +178,7 @@ get result of inbound probe
ssl: true, ssl: true,
user: 'some@example.com', user: 'some@example.com',
password: 'password', password: 'password',
folder: 'some_folder', # optional
} }
) )
@ -184,6 +198,7 @@ returns on fail
ssl: true, ssl: true,
user: 'some@example.com', user: 'some@example.com',
password: 'password', password: 'password',
folder: 'some_folder', # optional im imap
}, },
message: 'error message from used lib', message: 'error message from used lib',
message_human: 'translated error message, readable for humans', message_human: 'translated error message, readable for humans',
@ -365,6 +380,8 @@ returns on fail
'No route to host' => { host: true }, 'No route to host' => { host: true },
'execution expired' => { host: true }, 'execution expired' => { host: true },
'Connection refused' => { host: true }, 'Connection refused' => { host: true },
'Mailbox doesn\'t exist' => { folder: true },
'Folder doesn\'t exist' => { folder: true },
} }
end end