From 53ae52a96cd4ba6c361918a99261b1c3a2a6bd98 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 7 Oct 2013 05:38:07 +0200 Subject: [PATCH] Added switch to user feature. --- .../_application_controller.js.coffee | 4 +- .../_application_controller_generic.js.coffee | 74 +++++++++++++------ .../_application_controller_table.js.coffee | 74 ++++++++++++------- .../app/controllers/users.js.coffee | 16 ++++ .../app/views/generic/table.jst.eco | 20 +++-- app/controllers/sessions_controller.rb | 37 +++++++++- .../application_model/activity_stream_base.rb | 13 +++- config/routes/auth.rb | 15 ++-- 8 files changed, 179 insertions(+), 74 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_application_controller.js.coffee b/app/assets/javascripts/app/controllers/_application_controller.js.coffee index 8dfc6e2c5..599f240de 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.js.coffee @@ -143,8 +143,8 @@ class App.Controller extends Spine.Controller ticketTableAttributes: (attributes) => all_attributes = [ - { name: 'number', link: true, title: 'title' }, - { name: 'title', link: true, title: 'title' }, + { name: 'number', type: 'link', title: 'title', dataType: 'edit' }, + { name: 'title', type: 'link', title: 'title', dataType: 'edit' }, { name: 'customer', class: 'user-popover', data: { id: true } }, { name: 'ticket_state', translate: true, title: true }, { name: 'ticket_priority', translate: true, title: true }, diff --git a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee index e51b9a2b5..342596e93 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee @@ -60,11 +60,11 @@ class App.ControllerGenericEdit extends App.ControllerModal @html App.view('generic/admin/edit')( head: @pageData.object ) new App.ControllerForm( - el: @el.find('#object_edit'), - model: App[ @genericObject ], - params: @item, - required: @required, - autofocus: true, + el: @el.find('#object_edit') + model: App[ @genericObject ] + params: @item + required: @required + autofocus: true ) @modalShow() @@ -96,7 +96,7 @@ class App.ControllerGenericEdit extends App.ControllerModal ui.modalHide() ) -class App.ControllerGenericIndex extends App.ControllerContent +class App.ControllerGenericIndex extends App.Controller events: 'click [data-type=edit]': 'edit' 'click [data-type=destroy]': 'destroy' @@ -143,25 +143,53 @@ class App.ControllerGenericIndex extends App.ControllerContent ) @html App.view('generic/admin/index')( - head: @pageData.objects, - notes: @pageData.notes, - buttons: @pageData.buttons, - menus: @pageData.menus, + head: @pageData.objects + notes: @pageData.notes + buttons: @pageData.buttons + menus: @pageData.menus ) + # append additional col. link switch to + overview = _.clone( App[ @genericObject ].configure_overview ) + attributes = _.clone( App[ @genericObject ].configure_attributes ) + if @pageData.addCol + for item in @pageData.addCol.overview + overview.push item + for item in @pageData.addCol.attributes + attributes.push item + # append content table new App.ControllerTable( - el: @el.find('.table-overview'), - model: App[ @genericObject ], - objects: objects, + el: @el.find('.table-overview') + model: App[ @genericObject ] + objects: objects + overview: overview + attributes: attributes + ) + + binds = {} + for item in attributes + if item.dataType + if !binds[item.dataType] + callback = item.callback || @edit + @el.on( 'click', "[data-type=#{item.dataType}]", callback ) + binds[item.dataType] = true + + custom: (e) => + e.preventDefault() + item = $(e.target).item( App[ @genericObject ] ) + new App.ControllerGenericEdit( + id: item.id + pageData: @pageData + genericObject: @genericObject ) edit: (e) => e.preventDefault() item = $(e.target).item( App[ @genericObject ] ) new App.ControllerGenericEdit( - id: item.id, - pageData: @pageData, + id: item.id + pageData: @pageData genericObject: @genericObject ) @@ -174,7 +202,7 @@ class App.ControllerGenericIndex extends App.ControllerContent new: (e) -> e.preventDefault() new App.ControllerGenericNew( - pageData: @pageData, + pageData: @pageData genericObject: @genericObject ) @@ -191,8 +219,8 @@ class DestroyConfirm extends App.ControllerModal button: 'Yes' ) @modalShow( - backdrop: true, - keyboard: true, + backdrop: true + keyboard: true ) submit: (e) => @@ -233,10 +261,10 @@ class App.ControllerLevel2 extends App.ControllerContent @navupdate @page.nav @html App.view('generic/admin_level2/index')( - page: @page, - menus: @menu, - type: @type, - target: @target, + page: @page + menus: @menu + type: @type + target: @target ) if !@target @@ -269,7 +297,7 @@ class App.ControllerTabs extends App.Controller render: -> @html App.view('generic/tabs')( - tabs: @tabs, + tabs: @tabs ) @el.find('.nav-tabs li:first').addClass('active') diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee index 3c1c9ff48..2f3e2ae15 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_table.js.coffee @@ -10,34 +10,34 @@ class App.ControllerTable extends App.Controller ### new App.ControllerTable( - header: ['Host', 'User', 'Adapter', 'Active'], - overview: ['host', 'user', 'adapter', 'active'], - model: App.Channel, - objects: data, - checkbox: false, - radio: false, + header: ['Host', 'User', 'Adapter', 'Active'] + overview: ['host', 'user', 'adapter', 'active'] + model: App.Channel + objects: data + checkbox: false + radio: false ) new App.ControllerTable( overview_extended: [ - { name: 'number', link: true }, - { name: 'title', link: true }, - { name: 'customer', class: 'user-popover', data: { id: true } }, - { name: 'ticket_state', translate: true }, - { name: 'ticket_priority', translate: true }, + { name: 'number', link: true } + { name: 'title', link: true } + { name: 'customer', class: 'user-popover', data: { id: true } } + { name: 'ticket_state', translate: true } + { name: 'ticket_priority', translate: true } { name: 'group' }, - { name: 'owner', class: 'user-popover', data: { id: true } }, - { name: 'created_at', callback: @frontendTime }, - { name: 'last_contact', callback: @frontendTime }, - { name: 'last_contact_agent', callback: @frontendTime }, - { name: 'last_contact_customer', callback: @frontendTime }, - { name: 'first_response', callback: @frontendTime }, - { name: 'close_time', callback: @frontendTime }, + { name: 'owner', class: 'user-popover', data: { id: true } } + { name: 'created_at', callback: @frontendTime } + { name: 'last_contact', callback: @frontendTime } + { name: 'last_contact_agent', callback: @frontendTime } + { name: 'last_contact_customer', callback: @frontendTime } + { name: 'first_response', callback: @frontendTime } + { name: 'close_time', callback: @frontendTime } ], - model: App.Ticket, - objects: tickets, - checkbox: false, - radio: false, + model: App.Ticket + objects: tickets + checkbox: false + radio: false ) ### @@ -53,7 +53,7 @@ class App.ControllerTable extends App.Controller table = '

-' + App.i18n.translateContent( 'none' ) + '-

' return $(table) - # define normal header + # define table header if header header_new = [] for key in header @@ -64,21 +64,39 @@ class App.ControllerTable extends App.Controller else if !data.overview_extended header = [] for row in overview + found = false if attributes for attribute in attributes if row is attribute.name + found = true header.push attribute else rowWithoutId = row + '_id' if rowWithoutId is attribute.name - header.push attribute + found = true + header.push attribute + if !found + header.push { + name: row + display: row + } + # collect data of col. types dataTypesForCols = [] for row in overview - dataTypesForCols.push { - name: row - link: true - } + if attributes + for attribute in attributes + if row is attribute.name + dataTypesAttribute = _.clone(attribute) + dataTypesAttribute['type'] = 'link' + if !dataTypesAttribute['dataType'] + dataTypesAttribute['dataType'] = 'edit' + dataTypesForCols.push dataTypesAttribute + else + dataTypesForCols.push { + name: row + link: true + } # extended table format if data.overview_extended diff --git a/app/assets/javascripts/app/controllers/users.js.coffee b/app/assets/javascripts/app/controllers/users.js.coffee index aff0e623c..78ddcccdc 100644 --- a/app/assets/javascripts/app/controllers/users.js.coffee +++ b/app/assets/javascripts/app/controllers/users.js.coffee @@ -24,6 +24,22 @@ class Index extends App.Controller # { name: 'List', 'data-type': '', class: 'active' }, { name: 'New User', 'data-type': 'new', class: 'primary' } ] + addCol: + overview: ['switch_to'] + attributes: [ + { + name: 'switch_to' + display: 'Switch to' + type: 'link' + class: 'glyphicon glyphicon-user' + readonly: 1 + dataType: 'switch_to' + callback: (e) -> + e.preventDefault() + user_id = $(e.target).parent().parent().data('id') + window.location = App.Config.get('api_path') + '/sessions/switch/' + user_id + } + ] ) App.Config.set( 'User', { prio: 1000, name: 'Users', parent: '#manage', target: '#manage/users', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) diff --git a/app/assets/javascripts/app/views/generic/table.jst.eco b/app/assets/javascripts/app/views/generic/table.jst.eco index d37027b98..4bd2a3a0b 100644 --- a/app/assets/javascripts/app/views/generic/table.jst.eco +++ b/app/assets/javascripts/app/views/generic/table.jst.eco @@ -32,10 +32,10 @@ <% position++ %> <% if @checkbox: %> - + <% end %> <% if @radio: %> - + <% end %> <% for row in @overview: %> <% displayName = @P( object[row.name], row ) %> @@ -46,18 +46,22 @@ <% displayNameTitle = @P( object[row.title], row ) %> <% end %> <% end %> - title="<%= displayNameTitle %>"<% end %>> - <% if row.link: %><% else: %>class="<%= row.class %>"<% end %> <% if row.data && row.data.id: %>data-id="<%= object[row.name].id %>"<% end %>><% end %> - <% if row.translate || row.callback: %><%- displayName %><% else: %><%= displayName %><% end %> - <% if row.link: %><% else: %><% end %> - + title="<%= displayNameTitle %>"<% end %>> + <% if row.type is 'link': %> + class="<%= row.class %>"<% end %>> + <% else: %> + class="<%= row.class %>"<% end %> <% if row.data && row.data.id: %>data-id="<%= object[row.name].id %>"<% end %>> + <% end %> + <% if row.translate || row.callback: %><%- displayName %><% else: %><%= displayName %><% end %> + <% if row.type is 'link': %><% else: %><% end %> + <% end %> <% if @destroy: %> - x + x <% end %> diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 5050bd377..27e355a03 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -28,7 +28,7 @@ class SessionsController < ApplicationController current_user_set(user) # log new session - user.activity_stream_log( 'session started', user.id ) + user.activity_stream_log( 'session started', user.id, true ) # auto population of default collections default_collection = SessionHelper::default_collections(user) @@ -131,7 +131,7 @@ class SessionsController < ApplicationController current_user_set(authorization.user) # log new session - user.activity_stream_log( 'session started', authorization.user.id ) + user.activity_stream_log( 'session started', authorization.user.id, true ) # remember last login date authorization.user.update_last_login @@ -150,7 +150,7 @@ class SessionsController < ApplicationController current_user_set(user) # log new session - user.activity_stream_log( 'session started', user.id ) + user.activity_stream_log( 'session started', user.id, true ) # remember last login date user.update_last_login @@ -160,6 +160,37 @@ class SessionsController < ApplicationController redirect_to '/#' end + # "switch" to user + def switch_to_user + return if deny_if_not_role('Admin') + + # check user + if !params[:id] + render( + :json => { :message => 'no user given' }, + :status => :not_found + ) + return false + end + + user = User.lookup( :id => params[:id] ) + if !user + render( + :json => {}, + :status => :not_found + ) + return false + end + + # log new session + user.activity_stream_log( 'switch to', current_user.id, true ) + + # set session user + current_user_set(user) + + redirect_to '/#' + end + def list return if deny_if_not_role('Admin') sessions = ActiveRecord::SessionStore::Session.order('updated_at DESC').limit(10000) diff --git a/app/models/application_model/activity_stream_base.rb b/app/models/application_model/activity_stream_base.rb index 8e7aaefe6..6f40308e2 100644 --- a/app/models/application_model/activity_stream_base.rb +++ b/app/models/application_model/activity_stream_base.rb @@ -9,21 +9,28 @@ log activity for this object article = Ticket::Article.find(123) result = article.activity_stream_log( 'created', user_id ) + # force log + result = article.activity_stream_log( 'created', user_id, true ) + returns result = true # false =end - def activity_stream_log (type, user_id) - role = self.class.activity_stream_support_config[:role] + def activity_stream_log (type, user_id, force = false) + role = self.class.activity_stream_support_config[:role] + updated_at = self.updated_at + if force + updated_at = Time.new + end ActivityStream.add( :o_id => self['id'], :type => type, :object => self.class.name, :group_id => self['group_id'], :role => role, - :created_at => self.updated_at, + :created_at => updated_at, :created_by_id => user_id, ) end diff --git a/config/routes/auth.rb b/config/routes/auth.rb index e8098fbb3..5acc2ecf3 100644 --- a/config/routes/auth.rb +++ b/config/routes/auth.rb @@ -2,17 +2,18 @@ Zammad::Application.routes.draw do api_path = Rails.configuration.api_path # omniauth - match '/auth/:provider/callback', :to => 'sessions#create_omniauth',:via => [:post, :get, :puts, :delete] + match '/auth/:provider/callback', :to => 'sessions#create_omniauth',:via => [:post, :get, :puts, :delete] # sso - match '/auth/sso', :to => 'sessions#create_sso', :via => [:post, :get] + match '/auth/sso', :to => 'sessions#create_sso', :via => [:post, :get] # sessions - match api_path + '/signin', :to => 'sessions#create', :via => :post - match api_path + '/signshow', :to => 'sessions#show', :via => :get - match api_path + '/signout', :to => 'sessions#destroy', :via => [:get, :delete] + match api_path + '/signin', :to => 'sessions#create', :via => :post + match api_path + '/signshow', :to => 'sessions#show', :via => :get + match api_path + '/signout', :to => 'sessions#destroy', :via => [:get, :delete] - match api_path + '/sessions', :to => 'sessions#list', :via => :get - match api_path + '/sessions/:id', :to => 'sessions#delete', :via => :delete + match api_path + '/sessions/switch/:id', :to => 'sessions#switch_to_user', :via => :get + match api_path + '/sessions', :to => 'sessions#list', :via => :get + match api_path + '/sessions/:id', :to => 'sessions#delete', :via => :delete end \ No newline at end of file