Allow to delete email addresses.

This commit is contained in:
Martin Edenhofer 2015-09-11 15:44:05 +02:00
parent ceff2cc36c
commit 3ca0b26fc1
7 changed files with 292 additions and 48 deletions

View file

@ -215,18 +215,19 @@ class App.ChannelEmailSignatureEdit extends App.ControllerModal
class App.ChannelEmailAccountOverview extends App.Controller class App.ChannelEmailAccountOverview extends App.Controller
events: events:
'click [data-type="new"]': 'wizard' 'click .js-channelNew': 'wizard'
'click [data-type="delete"]': 'delete' 'click .js-channelDelete': 'delete'
'click [data-type="edit-inbound"]': 'edit_inbound' 'click .js-editInbound': 'edit_inbound'
'click [data-type="edit-outbound"]': 'edit_outbound' 'click .js-editOutbound': 'edit_outbound'
'click [data-type="email-address-new"]': 'email_address_new' 'click .js-emailAddressNew': 'email_address_new'
'click [data-type="email-address-edit"]': 'email_address_edit' 'click .js-emailAddressEdit': 'email_address_edit'
'click [data-type="edit-notification-outbound"]': 'edit_notification_outbound' 'click .js-emailAddressDelete': 'email_address_delete',
'click .js-editNotificationOutbound': 'edit_notification_outbound'
constructor: -> constructor: ->
super super
# @interval(@load, 20000) @interval(@load, 30000)
@load() #@load()
load: => load: =>
@ajax( @ajax(
@ -282,7 +283,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
edit_inbound: (e) => edit_inbound: (e) =>
e.preventDefault() e.preventDefault()
id = $(e.target).closest('tr').data('id') id = $(e.target).closest('.action').data('id')
channel = App.Channel.find(id) channel = App.Channel.find(id)
slide = 'js-inbound' slide = 'js-inbound'
new App.ChannelEmailAccountWizard( new App.ChannelEmailAccountWizard(
@ -295,7 +296,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
edit_outbound: (e) => edit_outbound: (e) =>
e.preventDefault() e.preventDefault()
id = $(e.target).closest('tr').data('id') id = $(e.target).closest('.action').data('id')
channel = App.Channel.find(id) channel = App.Channel.find(id)
slide = 'js-outbound' slide = 'js-outbound'
new App.ChannelEmailAccountWizard( new App.ChannelEmailAccountWizard(
@ -308,7 +309,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
delete: (e) => delete: (e) =>
e.preventDefault() e.preventDefault()
id = $(e.target).closest('tr').data('id') id = $(e.target).closest('.action').data('id')
item = App.Channel.find(id) item = App.Channel.find(id)
new App.ControllerGenericDestroyConfirm( new App.ControllerGenericDestroyConfirm(
item: item item: item
@ -318,7 +319,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
email_address_new: (e) => email_address_new: (e) =>
e.preventDefault() e.preventDefault()
channel_id = $(e.target).closest('tr').data('id') channel_id = $(e.target).closest('.action').data('id')
new App.ControllerGenericNew( new App.ControllerGenericNew(
pageData: pageData:
object: 'Email Address' object: 'Email Address'
@ -341,9 +342,19 @@ class App.ChannelEmailAccountOverview extends App.Controller
callback: @load callback: @load
) )
email_address_delete: (e) =>
e.preventDefault()
id = $(e.target).closest('li').data('id')
item = App.EmailAddress.find(id)
new App.ControllerGenericDestroyConfirm(
item: item
container: @el.closest('.content')
callback: @load
)
edit_notification_outbound: (e) => edit_notification_outbound: (e) =>
e.preventDefault() e.preventDefault()
id = $(e.target).closest('tr').data('id') id = $(e.target).closest('.action').data('id')
channel = App.Channel.find(id) channel = App.Channel.find(id)
slide = 'js-outbound' slide = 'js-outbound'
new App.ChannelEmailNotificationWizard( new App.ChannelEmailNotificationWizard(

View file

@ -1,24 +1,110 @@
<h2><%- @T('Email Accounts') %></h2>
<% if !_.isEmpty(@accounts_fixed): %> <% if !_.isEmpty(@accounts_fixed): %>
<h3><%- @T('Fixed email addresses') %></h3> <h2><%- @T('Fixed Email Accounts') %></h2>
<ul> <div class="action">
<% for email_address in @accounts_fixed: %> <div class="action-flow">
<li><%= email_address.realname %> &lt;<%= email_address.email %>&gt; <div class="action-block">
<% end %> <ul>
</ul> <% for email_address in @accounts_fixed: %>
<li><%= email_address.realname %> &lt;<%= email_address.email %>&gt;
<% end %>
</ul>
</div>
</div>
</div>
<% end %> <% end %>
<h2><%- @T('Email Accounts') %></h2>
<% if !_.isEmpty(@not_used_email_addresses): %> <% if !_.isEmpty(@not_used_email_addresses): %>
<h3><%- @T('Unlinked Email Addresses') %></h3> <div class="action">
<ul> <div class="action-flow">
<% for email_address in @not_used_email_addresses: %> <div class="action-block">
<li data-id="<%= email_address.id %>"><a href="" data-type="email-address-edit"><%= email_address.email %></a> <%- @T('Notice') %>: <%- @T('Unlinked Email Addresses, assign it to a channel or delete it.') %></h3>
<% end %> <ul class="list">
</ul> <% for email_address in @not_used_email_addresses: %>
<li class="list-item" data-id="<%= email_address.id %>">
<div class="list-item-name">
<a href="#" class="js-emailAddressEdit"><%= email_address.realname %> &lt;<%= email_address.email %>&gt;</a>
</div>
<div class="list-item-delete js-emailAddressDelete">
<%- @Icon('diagonal-cross') %>
</div>
<% end %>
</ul>
</div>
</div>
</div>
<% end %> <% end %>
<h3><%- @T('Linked Email Addresses') %></h3> <% if _.isEmpty(@account_channels): %>
<p><%- @T('You have no configured account right now.') %></p>
<% else: %>
<% for channel in @account_channels: %>
<div class="action" data-id="<%- channel.id %>">
<div class="action-flow" style="width: 100%;">
<div class="action-block" style="width: 50%;">
<%- @Icon('status', channel.status_in + " inline") %> <%- @T('Inbound') %>:<br>
<a class="js-editInbound" href="#">
<%- @T('User') %>: <%= channel.options.inbound.options.user %><br>
<%- @T('Host') %>: <%= channel.options.inbound.options.host %><br>
<%- @T('Protocol') %>: <%= channel.options.inbound.adapter %>
</a>
<% if !_.isEmpty(channel.last_log_in): %>
<div>
<%- @T('Notice') %>:<br>
<%= channel.last_log_in %>
</div>
<% end %>
<br>
<%- @Icon('status', channel.status_out + " inline") %> <%- @T('Outbound') %>:<br>
<a class="js-editOutbound" href="#">
<% if channel.options.outbound && channel.options.outbound.options: %>
<%- @T('User') %>: <%= channel.options.outbound.options.user %><br>
<%- @T('Host') %>: <%= channel.options.outbound.options.host %><br>
<% end %>
<%- @T('Protocol') %>: <%= channel.options.outbound.adapter %>
</a>
<% if !_.isEmpty(channel.last_log_out): %>
<div>
<%- @T('Notice') %>:<br>
<%= channel.last_log_out %>
<div>
<% end %>
</div>
<div class="action-block">
<%- @T('Email Adresses') %>:
<ul class="list">
<% if !_.isEmpty(channel.email_addresses): %>
<% for email_address in channel.email_addresses: %>
<li class="list-item" data-id="<%= email_address.id %>">
<div class="list-item-name">
<a href="" class="js-emailAddressEdit"><%= email_address.realname %> &lt;<%= email_address.email %>&gt;</a>
</div>
<% if channel.email_addresses.length > 1: %>
<div class="list-item-delete js-emailAddressDelete">
<%- @Icon('diagonal-cross') %>
</div>
<% end %>
<% end %>
<% else: %>
<li class="list-item"><%- @T('none') %>
<% end %>
</ul>
<a class="text-muted js-emailAddressNew" href="#" title="<%- @Ti('New Email Address') %>">+ <%- @T('Add Email') %></a>
</div>
</div>
<div class="action-controls">
<div class="sla-toggle btn btn--danger btn--secondary js-channelDelete"><%- @T('Delete') %></div>
</div>
</div>
<% end %>
<% end %>
<!--
<% if _.isEmpty(@account_channels): %> <% if _.isEmpty(@account_channels): %>
<p><%- @T('You have no configured account right now.') %></p> <p><%- @T('You have no configured account right now.') %></p>
<% else: %> <% else: %>
@ -37,7 +123,7 @@
<td class="noTruncate"> <td class="noTruncate">
<div class="horizontal"> <div class="horizontal">
<%- @Icon('status', channel.status_in + " inline") %> <%- @Icon('status', channel.status_in + " inline") %>
<a class="flex" href="#" data-type="edit-inbound"> <a class="flex js-editInbound" href="#">
<%= channel.options.inbound.options.user %><br> <%= channel.options.inbound.options.user %><br>
<%= channel.options.inbound.options.host %> (<%= channel.options.inbound.adapter %>) <%= channel.options.inbound.options.host %> (<%= channel.options.inbound.adapter %>)
</a> </a>
@ -46,7 +132,7 @@
<td class="noTruncate"> <td class="noTruncate">
<div class="horizontal"> <div class="horizontal">
<%- @Icon('status', channel.status_out + " inline") %> <%- @Icon('status', channel.status_out + " inline") %>
<a class="flex" href="#" data-type="edit-outbound"> <a class="flex js-editOutbound" href="#">
<% if channel.options.outbound && channel.options.outbound.options: %> <% if channel.options.outbound && channel.options.outbound.options: %>
<%= channel.options.outbound.options.user %><br> <%= channel.options.outbound.options.user %><br>
<%= channel.options.outbound.options.host %> <%= channel.options.outbound.options.host %>
@ -61,7 +147,7 @@
<% for email_address in channel.email_addresses: %> <% for email_address in channel.email_addresses: %>
<li class="list-item" data-id="<%= email_address.id %>"> <li class="list-item" data-id="<%= email_address.id %>">
<div class="list-item-name"> <div class="list-item-name">
<a href="" data-type="email-address-edit"><%= email_address.email %></a> <a href="" class="js-emailAddressEdit"><%= email_address.email %></a>
</div> </div>
<div class="list-item-delete js-delete"> <div class="list-item-delete js-delete">
<%- @Icon('diagonal-cross') %> <%- @Icon('diagonal-cross') %>
@ -71,7 +157,7 @@
<li class="list-item"><%- @T('none') %> <li class="list-item"><%- @T('none') %>
<% end %> <% end %>
</ul> </ul>
<a class="text-muted" href="#" data-type="email-address-new" title="<%- @Ti('New Email Address') %>">+ <%- @Ti('Add Email') %></a> <a class="text-muted js-emailAddressNew" href="#" title="<%- @Ti('New Email Address') %>">+ <%- @Ti('Add Email') %></a>
</td> </td>
<td class="noTruncate"> <td class="noTruncate">
<a href="#" data-type="delete" title="<%- @Ti('Delete') %>"><%- @Icon('trash') %></a> <a href="#" data-type="delete" title="<%- @Ti('Delete') %>"><%- @Icon('trash') %></a>
@ -91,12 +177,40 @@
</tbody> </tbody>
</table> </table>
<% end %> <% end %>
-->
<a data-type="new" class="btn btn--success"><%- @T('New') %></a> <a class="btn btn--success js-channelNew"><%- @T('New') %></a>
<% if !_.isEmpty(@notification_channels) && !App.Config.get('system_online_service'): %> <% if !_.isEmpty(@notification_channels) && !App.Config.get('system_online_service'): %>
<h2><%- @T('Notification Email Account') %></h2> <h2><%- @T('Email Notification') %></h2>
<% for channel in @notification_channels: %>
<div class="action" data-id="<%- channel.id %>">
<div class="action-flow">
<div class="action-block">
<%- @Icon('status', channel.status_out + " inline") %> <%- @T('Outbound') %>:<br>
<a class="js-editNotificationOutbound" href="#">
<% if channel.options.outbound && channel.options.outbound.options: %>
<%- @T('User') %>: <%= channel.options.outbound.options.user %><br>
<%- @T('Host') %>: <%= channel.options.outbound.options.host %><br>
<% end %>
<%- @T('Protocol') %>: <%= channel.options.outbound.adapter %>
</a>
<% if channel.status_in is 'error': %>
<div><%= channel.last_log_in %></div>
<% end %>
<% if channel.status_out is 'error': %>
<div><%= channel.last_log_out %></div>
<% end %>
</div>
</div>
</div>
<% end %>
<% end %>
<!--
<% if !_.isEmpty(@notification_channels) && !App.Config.get('system_online_service'): %>
<table class="table table-hover user-list"> <table class="table table-hover user-list">
<thead> <thead>
<tr> <tr>
@ -109,7 +223,7 @@
<td class="noTruncate"> <td class="noTruncate">
<div class="horizontal"> <div class="horizontal">
<%- @Icon('status', channel.status_out + " inline") %> <%- @Icon('status', channel.status_out + " inline") %>
<a class="flex" href="#" data-type="edit-notification-outbound"> <a class="flex js-editNotificationOutbound" href="#">
<% if channel.options.outbound && channel.options.outbound.options: %> <% if channel.options.outbound && channel.options.outbound.options: %>
<%= channel.options.outbound.options.user %><br> <%= channel.options.outbound.options.user %><br>
<%= channel.options.outbound.options.host %> <%= channel.options.outbound.options.host %>
@ -132,3 +246,4 @@
</tbody> </tbody>
</table> </table>
<% end %> <% end %>
-->

View file

@ -31,7 +31,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
not_used_email_address_ids = [] not_used_email_address_ids = []
accounts_fixed = [] accounts_fixed = []
assets = {} assets = {}
Channel.all.each {|channel| Channel.order(:id).each {|channel|
if system_online_service && channel.preferences && channel.preferences['online_service_disable'] if system_online_service && channel.preferences && channel.preferences['online_service_disable']
email_addresses = EmailAddress.where(channel_id: channel.id) email_addresses = EmailAddress.where(channel_id: channel.id)
email_addresses.each {|email_address| email_addresses.each {|email_address|

View file

@ -123,7 +123,7 @@ Response:
} }
Test: Test:
curl http://localhost/api/v1/email_addresses.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}' curl http://localhost/api/v1/email_addresses/#{id}.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
=end =end
@ -135,10 +135,13 @@ curl http://localhost/api/v1/email_addresses.json -v -u #{login}:#{password} -H
=begin =begin
Resource: Resource:
POST /api/v1/email_addresses/{id}.json
Response: Response:
{}
Test: Test:
curl http://localhost/api/v1/email_addresses/#{id}.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
=end =end

View file

@ -6,8 +6,9 @@ class EmailAddress < ApplicationModel
validates :realname, presence: true validates :realname, presence: true
validates :email, presence: true validates :email, presence: true
before_create :channel_check before_create :check_if_channel_exists_set_inactive
before_update :channel_check before_update :check_if_channel_exists_set_inactive
after_destroy :delete_group_reference
latest_change_support latest_change_support
@ -21,28 +22,42 @@ check and if channel not exists reset configured channels for email addresses
def self.channel_cleanup def self.channel_cleanup
EmailAddress.all.each {|email_address| EmailAddress.all.each {|email_address|
# set to active if channel exists
if email_address.channel_id && Channel.find_by(id: email_address.channel_id) if email_address.channel_id && Channel.find_by(id: email_address.channel_id)
if !email_address.active if !email_address.active
email_address.save email_address.save
end end
next next
end end
if email_address.channel_id || email_address.active
email_address.save # set in inactive if channel not longer exists
end next if !email_address.active
email_address.save
} }
end end
private private
def channel_check # set email address to inactive/active if channel exists or not
def check_if_channel_exists_set_inactive
# set to active if channel exists
if channel_id && Channel.find_by(id: channel_id) if channel_id && Channel.find_by(id: channel_id)
self.active = true self.active = true
return true return true
end end
# set in inactive if channel not longer exists
self.channel_id = nil self.channel_id = nil
self.active = false self.active = false
true true
end end
# delete group.email_address_id reference if email address get's deleted
def delete_group_reference
Group.where(email_address_id: id).each { |group|
group.email_address_id = nil
}
end
end end

View file

@ -2,9 +2,10 @@ Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path api_path = Rails.configuration.api_path
# groups # groups
match api_path + '/email_addresses', to: 'email_addresses#index', via: :get match api_path + '/email_addresses', to: 'email_addresses#index', via: :get
match api_path + '/email_addresses/:id', to: 'email_addresses#show', via: :get match api_path + '/email_addresses/:id', to: 'email_addresses#show', via: :get
match api_path + '/email_addresses', to: 'email_addresses#create', via: :post match api_path + '/email_addresses', to: 'email_addresses#create', via: :post
match api_path + '/email_addresses/:id', to: 'email_addresses#update', via: :put match api_path + '/email_addresses/:id', to: 'email_addresses#update', via: :put
match api_path + '/email_addresses/:id', to: 'email_addresses#destroy', via: :delete
end end

View file

@ -0,0 +1,99 @@
# encoding: utf-8
require 'test_helper'
class EmailAddressTest < ActiveSupport::TestCase
test 'basic tests' do
EmailAddress.delete_all
email_address1 = EmailAddress.create(
realname: 'address #1',
email: 'address1@example.com',
active: true,
updated_by_id: 1,
created_by_id: 1,
)
assert_not(email_address1.active)
email_address1.channel_id = Channel.first.id
email_address1.save
assert(email_address1.active)
end
test 'group tests' do
EmailAddress.delete_all
email_address1 = EmailAddress.create(
realname: 'address #1',
email: 'address1@example.com',
active: true,
updated_by_id: 1,
created_by_id: 1,
)
group1 = Group.create_or_update(
name: 'group email address 1',
email_address_id: email_address1.id,
active: true,
updated_by_id: 1,
created_by_id: 1,
)
assert(group1.email_address_id)
email_address1.destroy
group1 = Group.find(group1.id)
assert(group1.email_address_id)
end
test 'channel tests' do
channel1 = Channel.create(
area: 'Email::Account',
options: {},
active: true,
updated_by_id: 1,
created_by_id: 1,
)
EmailAddress.delete_all
email_address1 = EmailAddress.create(
realname: 'address #1',
email: 'address1@example.com',
active: true,
channel_id: channel1.id,
updated_by_id: 1,
created_by_id: 1,
)
email_address2 = EmailAddress.create(
realname: 'address #2',
email: 'address2@example.com',
active: true,
channel_id: channel1.id,
updated_by_id: 1,
created_by_id: 1,
)
channel1.destroy
email_address1 = EmailAddress.find(email_address1.id)
assert_not(email_address1.channel_id)
email_address2 = EmailAddress.find(email_address2.id)
assert_not(email_address2.channel_id)
channel1 = Channel.create(
area: 'Email::Account',
options: {},
active: true,
updated_by_id: 1,
created_by_id: 1,
)
email_address1 = EmailAddress.find(email_address1.id)
assert_not(email_address1.channel_id)
email_address2 = EmailAddress.find(email_address2.id)
assert_not(email_address2.channel_id)
end
end