From 7d23efda7927881a69a463ded9e011b544e2ee5c Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 1 Oct 2012 20:41:08 +0200 Subject: [PATCH] Added support for signature and different sender addresses. --- Gemfile | 4 +- .../_application_controller_form.js.coffee | 16 +- .../app/controllers/_channel/email.js.coffee | 236 ++++++++++++++++-- .../javascripts/app/lib/collection.js.coffee | 6 +- .../app/models/application_model.js.coffee | 13 + .../app/models/email_address.js.coffee | 15 ++ .../javascripts/app/models/group.js.coffee | 6 +- .../app/views/channel/email_outbound.jst.eco | 2 +- app/controllers/email_addresses_controller.rb | 144 +++++++++++ app/controllers/sessions/collection_ticket.rb | 7 + app/controllers/signatures_controller.rb | 141 +++++++++++ app/models/email_address.rb | 6 + app/models/group.rb | 2 + app/models/signature.rb | 6 + app/models/ticket/article.rb | 14 +- config/routes.rb | 59 +---- config/routes/email_address.rb | 12 + config/routes/signature.rb | 13 + db/migrate/20120101000001_create_base.rb | 14 +- db/migrate/20120930160201_signature_update.rb | 21 ++ db/seeds.rb | 38 +-- 21 files changed, 643 insertions(+), 132 deletions(-) create mode 100644 app/assets/javascripts/app/models/email_address.js.coffee create mode 100644 app/controllers/email_addresses_controller.rb create mode 100644 app/controllers/signatures_controller.rb create mode 100644 app/models/email_address.rb create mode 100644 app/models/signature.rb create mode 100644 config/routes/email_address.rb create mode 100644 config/routes/signature.rb create mode 100644 db/migrate/20120930160201_signature_update.rb diff --git a/Gemfile b/Gemfile index e1ac40aa9..f2060f120 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'http://rubygems.org' -gem 'rails', '3.2.3' +gem 'rails', '3.2.8' # Bundle edge Rails instead: #gem 'rails', :git => 'git://github.com/rails/rails.git' @@ -47,7 +47,7 @@ gem 'simple-rss' # gem 'therubyracer' # e. g. for mysql you need to load mysql -# gem 'mysql2' +gem 'mysql2' # Use unicorn as the web server # gem 'unicorn' diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index e1f99e7bb..0b7abd923 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -382,19 +382,11 @@ class App.ControllerForm extends App.Controller # if active or if active doesn't exist if item.active || !( 'active' of item ) - name = '???' - if item.name - name = item.name - else if item.firstname - name = item.firstname - if item.lastname - if name - name = name + ' ' - name = name + item.lastname - - name_new = name + name_new = '?' + if item.displayName + name_new = item.displayName() if attribute.translate - name_new = Ti(name) + name_new = Ti(name_new) attribute.options.push { name: name_new, value: item.id, diff --git a/app/assets/javascripts/app/controllers/_channel/email.js.coffee b/app/assets/javascripts/app/controllers/_channel/email.js.coffee index da0e406b6..f6808b236 100644 --- a/app/assets/javascripts/app/controllers/_channel/email.js.coffee +++ b/app/assets/javascripts/app/controllers/_channel/email.js.coffee @@ -21,12 +21,14 @@ class App.ChannelEmail extends App.ControllerTabs controller: App.ChannelEmailOutbound, }, { - name: 'Sigantures', - target: 'c-signature', + name: 'Sigantures', + target: 'c-signature', + controller: App.ChannelEmailSignature, }, { - name: 'Adresses', - target: 'c-address', + name: 'Adresses', + target: 'c-address', + controller: App.ChannelEmailAddress, }, { name: 'Filter', @@ -42,6 +44,183 @@ class App.ChannelEmail extends App.ControllerTabs @render() +class App.ChannelEmailAddress extends App.Controller + events: + 'click [data-type=new]': 'new' + 'click [data-type=edit]': 'edit' + + constructor: -> + super + + App.EmailAddress.bind 'refresh change', @render + App.EmailAddress.fetch() + + render: => + data = App.EmailAddress.all() + + html = $('
') + + table = @table( + model: App.EmailAddress, + objects: data, + ) + + html.append( table ) + html.append( '' + T('New') + '' ) + @html html + + new: (e) => + e.preventDefault() + new App.ChannelEmailAddressEdit() + + edit: (e) => + e.preventDefault() + item = $(e.target).item( App.EmailAddress ) + new App.ChannelEmailAddressEdit( object: item ) + +class App.ChannelEmailAddressEdit extends App.ControllerModal + constructor: -> + super + @render(@object) + + render: (data = {}) -> + if @object + @html App.view('generic/admin/edit')( + head: 'Email-Address' + ) + @form = new App.ControllerForm( + el: @el.find('#object_edit'), + model: App.EmailAddress, + params: @object, + autofocus: true, + ) + else + @html App.view('generic/admin/new')( + head: 'Email-Address' + ) + @form = new App.ControllerForm( + el: @el.find('#object_new'), + model: App.EmailAddress, + autofocus: true, + ) + @modalShow() + + submit: (e) => + e.preventDefault() + + # get params + params = @formParam(e.target) + + object = @object || new App.EmailAddress + object.load(params) + + # validate form + errors = @form.validate( params ) + + # show errors in form + if errors + @log 'error new', errors + @formValidate( form: e.target, errors: errors ) + return false + + # save object + object.save( + success: => + @modalHide() + error: => + @log 'errors' + @modalHide() + ) + +class App.ChannelEmailSignature extends App.Controller + events: + 'click [data-type=new]': 'new' + 'click [data-type=edit]': 'edit' + + constructor: -> + super + + App.Signature.bind 'refresh change', @render + App.Signature.fetch() + + render: => + data = App.Signature.all() + + html = $('
') + + table = @table( + model: App.Signature, + objects: data, + ) + + html.append( table ) + html.append( '' + T('New') + '' ) + @html html + + new: (e) => + e.preventDefault() + new App.ChannelEmailSignatureEdit() + + edit: (e) => + e.preventDefault() + item = $(e.target).item( App.Signature ) + @log '123', item, $(e.target) + new App.ChannelEmailSignatureEdit( object: item ) + +class App.ChannelEmailSignatureEdit extends App.ControllerModal + constructor: -> + super + @render(@object) + + render: (data = {}) -> + if @object + @html App.view('generic/admin/edit')( + head: 'Signature' + ) + @form = new App.ControllerForm( + el: @el.find('#object_edit'), + model: App.Signature, + params: @object, + autofocus: true, + ) + else + @html App.view('generic/admin/new')( + head: 'Signature' + ) + @form = new App.ControllerForm( + el: @el.find('#object_new'), + model: App.Signature, + autofocus: true, + ) + @modalShow() + + submit: (e) => + e.preventDefault() + + # get params + params = @formParam(e.target) + + object = @object || new App.Signature + object.load(params) + + # validate form + errors = @form.validate( params ) + + # show errors in form + if errors + @log 'error new', errors + @formValidate( form: e.target, errors: errors ) + return false + + # save object + object.save( + success: => + @modalHide() + error: => + @log 'errors' + @modalHide() + ) + class App.ChannelEmailInbound extends App.Controller events: 'click [data-type=new]': 'new' @@ -65,13 +244,14 @@ class App.ChannelEmailInbound extends App.Controller data.push channel table = @table( + header: ['Host', 'User', 'Adapter', 'Active'], overview: ['host', 'user', 'adapter', 'active'], model: App.Channel, objects: data, ) html.append( table ) - html.append( 'new account' ) + html.append( '' + T('New') + '' ) @html html new: (e) => @@ -100,14 +280,24 @@ class App.ChannelEmailInboundEdit extends App.ControllerModal { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: false, relation: 'Group', class: 'span4', default: data['group_id'] }, { name: 'active', display: 'Active', tag: 'select', multiple: false, null: false, options: { true: 'yes', false: 'no' } , class: 'span4', default: data['active'] }, ] - @html App.view('generic/admin/new')( - head: 'New Channel' - ) - @form = new App.ControllerForm( - el: @el.find('#object_new'), - model: { configure_attributes: configure_attributes, className: '' }, - autofocus: true, - ) + if @object + @html App.view('generic/admin/edit')( + head: 'Channel' + ) + @form = new App.ControllerForm( + el: @el.find('#object_edit'), + model: { configure_attributes: configure_attributes, className: '' }, + autofocus: true, + ) + else + @html App.view('generic/admin/new')( + head: 'Channel' + ) + @form = new App.ControllerForm( + el: @el.find('#object_new'), + model: { configure_attributes: configure_attributes, className: '' }, + autofocus: true, + ) @modalShow() submit: (e) => @@ -179,15 +369,17 @@ class App.ChannelEmailOutbound extends App.Controller adapter_used = channel.adapter channel_used = channel - if adapter_used is 'Sendmail' - configure_attributes = [ - { name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , class: 'span4', default: adapter_used }, - ] - @form = new App.ControllerForm( - el: @el.find('#form-email-adapter'), - model: { configure_attributes: configure_attributes, className: '' }, - autofocus: true, - ) + configure_attributes = [ + { name: 'adapter', display: 'Send Mails via', tag: 'select', multiple: false, null: false, options: adapters , class: 'span4', default: adapter_used }, + ] + new App.ControllerForm( + el: @el.find('#form-email-adapter'), + model: { configure_attributes: configure_attributes, className: '' }, + autofocus: true, + ) + +# if adapter_used is 'Sendmail' +# # some form if adapter_used is 'SMTP' configure_attributes = [ diff --git a/app/assets/javascripts/app/lib/collection.js.coffee b/app/assets/javascripts/app/lib/collection.js.coffee index 30df82bff..d4f323562 100644 --- a/app/assets/javascripts/app/lib/collection.js.coffee +++ b/app/assets/javascripts/app/lib/collection.js.coffee @@ -78,7 +78,7 @@ class _Singleton if _.isArray( params.data ) for object in params.data - console.log( 'load ARRAY', object) +# console.log( 'load ARRAY', object) App[params.type].refresh( object, options: { clear: true } ) # remember in store if not already requested from local storage @@ -88,7 +88,7 @@ class _Singleton # if _.isObject( params.data ) for key, object of params.data - console.log( 'load OB', object) +# console.log( 'load OB', object) App[params.type].refresh( object, options: { clear: true } ) # remember in store if not already requested from local storage @@ -100,7 +100,7 @@ class _Singleton console.log( 'find', type, id ) # if App[type].exists( id ) && !callback if App[type].exists( id ) - console.log( 'find exists', type, id ) +# console.log( 'find exists', type, id ) data = App[type].find( id ) if callback callback( data ) diff --git a/app/assets/javascripts/app/models/application_model.js.coffee b/app/assets/javascripts/app/models/application_model.js.coffee index 20aca4760..c2db5ccb6 100644 --- a/app/assets/javascripts/app/models/application_model.js.coffee +++ b/app/assets/javascripts/app/models/application_model.js.coffee @@ -1,5 +1,18 @@ class App.Model extends Spine.Model + displayName: -> + return @name if @name + if @realname + return "#{@realname} <#{@email}>" + if @firstname + name = @firstname + if @lastname + if name + name = name + ' ' + name = name + @lastname + return name + return '???' + @validate: ( data = {} ) -> return if !data['model'].configure_attributes diff --git a/app/assets/javascripts/app/models/email_address.js.coffee b/app/assets/javascripts/app/models/email_address.js.coffee new file mode 100644 index 000000000..b453252be --- /dev/null +++ b/app/assets/javascripts/app/models/email_address.js.coffee @@ -0,0 +1,15 @@ +class App.EmailAddress extends App.Model + @configure 'EmailAddress', 'realname', 'email', 'note', 'active' + @extend Spine.Model.Ajax + @url: '/api/email_addresses' + + @configure_attributes = [ + { name: 'realname', display: 'Realname', tag: 'input', type: 'text', limit: 250, 'null': false, 'class': 'span4' }, + { name: 'email', display: 'Email', tag: 'input', type: 'text', limit: 250, 'null': false, 'class': 'span4' }, + { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' }, + { name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, + { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, + ] + @configure_overview = [ + 'realname', 'email' + ] diff --git a/app/assets/javascripts/app/models/group.js.coffee b/app/assets/javascripts/app/models/group.js.coffee index 0242958b3..9161cd447 100644 --- a/app/assets/javascripts/app/models/group.js.coffee +++ b/app/assets/javascripts/app/models/group.js.coffee @@ -1,13 +1,15 @@ class App.Group extends App.Model - @configure 'Group', 'name', 'assignment_timeout', 'follow_up_possible', 'follow_up_assignment', 'note', 'active' + @configure 'Group', 'name', 'assignment_timeout', 'follow_up_possible', 'follow_up_assignment', 'email_address_id', 'signature_id', 'note', 'active' @extend Spine.Model.Ajax @url: '/api/groups' @configure_attributes = [ { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' }, - { name: 'assignment_timeout', display: 'Assignment Timout', tag: 'input', note: 'Assignment timout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.', type: 'text', limit: 100, 'null': false, 'class': 'span4' }, + { name: 'assignment_timeout', display: 'Assignment Timout', tag: 'input', note: 'Assignment timout in minutes if assigned agent is not working on it. Ticket will be shown as unassigend.', type: 'text', limit: 100, 'null': true, 'class': 'span4' }, { name: 'follow_up_possible', display: 'Follow possible', tag: 'select', default: 'yes', options: { yes: 'yes', reject: 'reject follow up/do not reopen Ticket', 'new_ticket': 'do not reopen Ticket but create new Ticket' }, 'null': false, note: 'Follow up for closed ticket possible or not.', 'class': 'span4' }, { name: 'follow_up_assignment', display: 'Assign Follow Ups', tag: 'select', default: 'yes', options: { yes: 'yes', no: 'no' }, 'null': false, note: 'Assign follow up to latest agent again.', 'class': 'span4' }, + { name: 'email_address_id', display: 'Email', tag: 'select', multiple: false, null: true, relation: 'EmailAddress', nulloption: true, class: 'span4' }, + { name: 'signature_id', display: 'Signature', tag: 'select', multiple: false, null: true, relation: 'Signature', nulloption: true, class: 'span4' }, { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' }, { name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 }, { name: 'active', display: 'Active', tag: 'boolean', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' }, diff --git a/app/assets/javascripts/app/views/channel/email_outbound.jst.eco b/app/assets/javascripts/app/views/channel/email_outbound.jst.eco index 71c3d7fa7..f0a2ddb4b 100644 --- a/app/assets/javascripts/app/views/channel/email_outbound.jst.eco +++ b/app/assets/javascripts/app/views/channel/email_outbound.jst.eco @@ -1,5 +1,5 @@
-