From e183dc4fa9e30121335797894456c2c55b5b3f6c Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 12:56:09 +0200 Subject: [PATCH 01/18] Added parameter to enable http_basic auth promt fallback. --- app/controllers/application_controller.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 247d5d316..ef83ebc5d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -177,9 +177,15 @@ class ApplicationController < ActionController::Base } end - def authentication_check + def authentication_check( params = { basic_auth_promt: false } ) result = authentication_check_only + # check if basic_auth fallback is possible + if params[:basic_auth_promt] && result[:auth] == false + + return request_http_basic_authentication + end + # return auth not ok if result[:auth] == false render( From 4c94c8518a8291ce600deb488945524510507e5c Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 12:56:20 +0200 Subject: [PATCH 02/18] - Removed URL based token auth for iCal feature. - Enabled http basic auth fallback auth. --- app/controllers/ical_tickets_controller.rb | 4 ++-- config/routes/ical_tickets.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb index 47993c1d5..49069fce5 100644 --- a/app/controllers/ical_tickets_controller.rb +++ b/app/controllers/ical_tickets_controller.rb @@ -3,9 +3,9 @@ require 'icalendar' class IcalTicketsController < ApplicationController - before_action { authentication_check_action_token 'iCal' } + before_action { authentication_check( { basic_auth_promt: true } ) } - # @path [GET] /ical/tickets_all/:action_token + # @path [GET] /ical/tickets/:action_token # # @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events. # diff --git a/config/routes/ical_tickets.rb b/config/routes/ical_tickets.rb index 324c30007..38c24f043 100644 --- a/config/routes/ical_tickets.rb +++ b/config/routes/ical_tickets.rb @@ -2,8 +2,8 @@ Zammad::Application.routes.draw do api_path = Rails.configuration.api_path # ical ticket - match api_path + '/ical/tickets/:action_token', to: 'ical_tickets#all', via: :get - match api_path + '/ical/tickets_new_open/:action_token', to: 'ical_tickets#new_open', via: :get - match api_path + '/ical/tickets_pending/:action_token', to: 'ical_tickets#pending', via: :get - match api_path + '/ical/tickets_escalation/:action_token', to: 'ical_tickets#escalation', via: :get + match api_path + '/ical/tickets', to: 'ical_tickets#all', via: :get + match api_path + '/ical/tickets_new_open', to: 'ical_tickets#new_open', via: :get + match api_path + '/ical/tickets_pending', to: 'ical_tickets#pending', via: :get + match api_path + '/ical/tickets_escalation', to: 'ical_tickets#escalation', via: :get end From 8549f3e9b4fc069f00b49f75d3421a6a3afd3245 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 13:19:56 +0200 Subject: [PATCH 03/18] Reworked token auth - now using the Rails framework implementation. --- app/controllers/application_controller.rb | 64 ++++++++++++++-------- app/controllers/ical_tickets_controller.rb | 2 +- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ef83ebc5d..86a7e35a6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,7 +5,6 @@ class ApplicationController < ActionController::Base helper_method :current_user, :authentication_check, - :authentication_check_action_token, :config_frontend, :role?, :model_create_render, @@ -96,7 +95,7 @@ class ApplicationController < ActionController::Base session[:user_agent] = request.env['HTTP_USER_AGENT'] end - def authentication_check_only + def authentication_check_only(auth_param) logger.debug 'authentication_check' session[:request_type] = 1 @@ -162,6 +161,43 @@ class ApplicationController < ActionController::Base end end + # check token + if auth_param[:token_action] + authenticate_with_http_token do |token, options| + logger.debug 'token auth check' + session[:request_type] = 4 + + userdata = Token.check( + action: auth_param[:token_action], + name: token, + ) + + message = '' + if !userdata + message = 'authentication failed' + end + + # return auth ok + if message == '' + + # remember user + session[:user_id] = userdata.id + + # set token user to current user + current_user_set(userdata) + return { + auth: true + } + end + + # return auth not ok + return { + auth: false, + message: message, + } + end + end + # return auth not ok (no session exists) if !session[:user_id] logger.debug 'no valid session, user_id' @@ -177,11 +213,11 @@ class ApplicationController < ActionController::Base } end - def authentication_check( params = { basic_auth_promt: false } ) - result = authentication_check_only + def authentication_check( auth_param = { basic_auth_promt: false } ) + result = authentication_check_only(auth_param) # check if basic_auth fallback is possible - if params[:basic_auth_promt] && result[:auth] == false + if auth_param[:basic_auth_promt] && result[:auth] == false return request_http_basic_authentication end @@ -201,24 +237,6 @@ class ApplicationController < ActionController::Base true end - def authentication_check_action_token(action) - - user = Token.check( - action: action, - name: params[:action_token], - ) - - if !user - logger.debug params.inspect - response_access_deny - return - end - - current_user_set( user ) - - true - end - def role?( role_name ) return false if !current_user current_user.role?( role_name ) diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb index 49069fce5..f5eabfe20 100644 --- a/app/controllers/ical_tickets_controller.rb +++ b/app/controllers/ical_tickets_controller.rb @@ -3,7 +3,7 @@ require 'icalendar' class IcalTicketsController < ApplicationController - before_action { authentication_check( { basic_auth_promt: true } ) } + before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) } # @path [GET] /ical/tickets/:action_token # From e06dfe04158eb6363ec7218e5f9dc552033bb250 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 14:13:56 +0200 Subject: [PATCH 04/18] - Fixed wrong code doc. - Improved code layout. --- app/controllers/ical_tickets_controller.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb index f5eabfe20..71a1aedba 100644 --- a/app/controllers/ical_tickets_controller.rb +++ b/app/controllers/ical_tickets_controller.rb @@ -5,7 +5,7 @@ require 'icalendar' class IcalTicketsController < ApplicationController before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) } - # @path [GET] /ical/tickets/:action_token + # @path [GET] /ical/tickets # # @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events. # @@ -14,7 +14,6 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def all - new_open_events_data = new_open_events_data_get pending_events_data = pending_events_data_get escalation_events_data = escalation_events_data_get @@ -24,7 +23,7 @@ class IcalTicketsController < ApplicationController events_data_to_ical( events_data ) end - # @path [GET] /ical/tickets_new_open/:action_token + # @path [GET] /ical/tickets_new_open # # @summary Returns an iCal file with all new and open tickets as events. # @@ -33,13 +32,12 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def new_open - events_data = new_open_events_data_get events_data_to_ical( events_data ) end - # @path [GET] /ical/tickets_pending/:action_token + # @path [GET] /ical/tickets_pending # # @summary Returns an iCal file with all pending tickets as events. # @@ -53,7 +51,7 @@ class IcalTicketsController < ApplicationController events_data_to_ical( events_data ) end - # @path [GET] /ical/ticket_escalation/:action_token + # @path [GET] /ical/ticket_escalation # # @summary Returns an iCal file with all escalation times for tickets as events. # From b38b70b4400c303c0a49b07e79ce6624cd89f342 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 14:17:09 +0200 Subject: [PATCH 05/18] Removed wrong documentation. --- app/controllers/ical_tickets_controller.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb index 71a1aedba..38f206428 100644 --- a/app/controllers/ical_tickets_controller.rb +++ b/app/controllers/ical_tickets_controller.rb @@ -9,8 +9,6 @@ class IcalTicketsController < ApplicationController # # @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events. # - # @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action. - # # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def all @@ -27,8 +25,6 @@ class IcalTicketsController < ApplicationController # # @summary Returns an iCal file with all new and open tickets as events. # - # @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action. - # # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def new_open @@ -41,8 +37,6 @@ class IcalTicketsController < ApplicationController # # @summary Returns an iCal file with all pending tickets as events. # - # @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action. - # # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def pending @@ -55,8 +49,6 @@ class IcalTicketsController < ApplicationController # # @summary Returns an iCal file with all escalation times for tickets as events. # - # @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action. - # # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def escalation From f345f9f47cef3be14997fa92b32bf3d2a2fc40d6 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 16:30:27 +0200 Subject: [PATCH 06/18] Added change event trigger. --- .../javascripts/app/lib/app_post/searchable_select.js.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/javascripts/app/lib/app_post/searchable_select.js.coffee b/app/assets/javascripts/app/lib/app_post/searchable_select.js.coffee index de10d3130..7cc58e9d6 100644 --- a/app/assets/javascripts/app/lib/app_post/searchable_select.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/searchable_select.js.coffee @@ -77,7 +77,9 @@ class App.SearchableSelect extends Spine.Controller selectItem: (event) -> @input.val event.currentTarget.textContent.trim() + @input.trigger('change') @shadowInput.val event.currentTarget.getAttribute('data-value') + @shadowInput.trigger('change') onTab: (event) -> return if not @isOpen @@ -93,7 +95,9 @@ class App.SearchableSelect extends Spine.Controller event.preventDefault() @input.val @values.filter('.is-active').text().trim() + @input.trigger('change') @shadowInput.val @values.filter('.is-active').attr('data-value') + @shadowInput.trigger('change') @toggle() filterList: (event) => From f8688478262c1bacbf2a703e0517d0b3705627bc Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 17:15:16 +0200 Subject: [PATCH 07/18] Moved iCal methods to own modules in lib. --- app/controllers/ical_tickets_controller.rb | 163 +++++---------------- lib/i_cal.rb | 24 +++ lib/i_cal/ticket.rb | 104 +++++++++++++ 3 files changed, 161 insertions(+), 130 deletions(-) create mode 100644 lib/i_cal.rb create mode 100644 lib/i_cal/ticket.rb diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb index 38f206428..bd6cdff10 100644 --- a/app/controllers/ical_tickets_controller.rb +++ b/app/controllers/ical_tickets_controller.rb @@ -12,13 +12,20 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def all - new_open_events_data = new_open_events_data_get - pending_events_data = pending_events_data_get - escalation_events_data = escalation_events_data_get + new_open_events_data = ICal::Ticket.new_open(current_user) + pending_events_data = ICal::Ticket.pending(current_user) + escalation_events_data = ICal::Ticket.escalation(current_user) events_data = new_open_events_data + pending_events_data + escalation_events_data - events_data_to_ical( events_data ) + ical = ICal.to_ical( events_data ) + + send_data( + ical, + filename: 'zammad_tickets.ical', + type: 'text/plain', + disposition: 'inline' + ) end # @path [GET] /ical/tickets_new_open @@ -28,9 +35,16 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def new_open - events_data = new_open_events_data_get + events_data = ICal::Ticket.new_open(current_user) - events_data_to_ical( events_data ) + ical = ICal.to_ical( events_data ) + + send_data( + ical, + filename: 'zammad_tickets_new_open.ical', + type: 'text/plain', + disposition: 'inline' + ) end # @path [GET] /ical/tickets_pending @@ -40,9 +54,16 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def pending - events_data = pending_events_data_get + events_data = ICal::Ticket.pending(current_user) - events_data_to_ical( events_data ) + ical = ICal.to_ical( events_data ) + + send_data( + ical, + filename: 'zammad_tickets_pending.ical', + type: 'text/plain', + disposition: 'inline' + ) end # @path [GET] /ical/ticket_escalation @@ -52,131 +73,13 @@ class IcalTicketsController < ApplicationController # @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 401 Permission denied. def escalation - events_data = escalation_events_data_get + events_data = ICal::Ticket.escalation(current_user) - events_data_to_ical( events_data ) - end - - private - - def new_open_events_data_get - - condition = { - 'tickets.owner_id' => current_user.id, - 'tickets.state_id' => Ticket::State.where( - state_type_id: Ticket::StateType.where( - name: %w(new open), - ), - ), - } - - tickets = Ticket.search( - current_user: current_user, - condition: condition, - ) - - events_data = [] - tickets.each do |ticket| - - event_data = {} - - event_data[:dtstart] = Icalendar::Values::Date.new( Time.zone.today ) - event_data[:dtend] = Icalendar::Values::Date.new( Time.zone.today ) - event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'" - event_data[:description] = "T##{ ticket.number }" - - events_data.push event_data - end - - events_data - end - - def pending_events_data_get - - condition = { - 'tickets.owner_id' => current_user.id, - 'tickets.state_id' => Ticket::State.where( - state_type_id: Ticket::StateType.where( - name: [ - 'pending reminder', - 'pending action', - ], - ), - ), - } - - tickets = Ticket.search( - current_user: current_user, - condition: condition, - ) - - events_data = [] - tickets.each do |ticket| - - event_data = {} - - # rubocop:disable Rails/TimeZone - event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time ) - event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time ) - # rubocop:enable Rails/TimeZone - event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'" - event_data[:description] = "T##{ ticket.number }" - - events_data.push event_data - end - - events_data - end - - def escalation_events_data_get - - condition = [ - 'tickets.escalation_time IS NOT NULL', - 'tickets.owner_id = ?', current_user.id - ] - - tickets = Ticket.search( - current_user: current_user, - condition: condition, - ) - - events_data = [] - tickets.each do |ticket| - - event_data = {} - - # rubocop:disable Rails/TimeZone - event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time ) - event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time ) - # rubocop:enable Rails/TimeZone - event_data[:summary] = "ticket escalation: '#{ ticket.title }'" - event_data[:description] = "T##{ ticket.number }" - - events_data.push event_data - end - - events_data - end - - def events_data_to_ical(events_data) - - cal = Icalendar::Calendar.new - - events_data.each do |event_data| - - cal.event do |e| - e.dtstart = event_data[:dtstart] - e.dtend = event_data[:dtend] - e.summary = event_data[:summary] - e.description = event_data[:description] - e.ip_class = 'PRIVATE' - end - - end + ical = ICal.to_ical( events_data ) send_data( - cal.to_ical, - filename: 'zammad.ical', + ical, + filename: 'zammad_tickets_escalation.ical', type: 'text/plain', disposition: 'inline' ) diff --git a/lib/i_cal.rb b/lib/i_cal.rb new file mode 100644 index 000000000..7f8be5683 --- /dev/null +++ b/lib/i_cal.rb @@ -0,0 +1,24 @@ +# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ + +module ICal + + def self.to_ical(events_data) + + cal = Icalendar::Calendar.new + + events_data.each do |event_data| + + cal.event do |e| + e.dtstart = event_data[:dtstart] + e.dtend = event_data[:dtend] + e.summary = event_data[:summary] + e.description = event_data[:description] + e.ip_class = 'PRIVATE' + end + + end + + cal.to_ical + end + +end diff --git a/lib/i_cal/ticket.rb b/lib/i_cal/ticket.rb new file mode 100644 index 000000000..f58537177 --- /dev/null +++ b/lib/i_cal/ticket.rb @@ -0,0 +1,104 @@ +# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ + +module ICal::Ticket + + def self.new_open(user) + + condition = { + 'tickets.owner_id' => user.id, + 'tickets.state_id' => Ticket::State.where( + state_type_id: Ticket::StateType.where( + name: %w(new open), + ), + ), + } + + tickets = Ticket.search( + current_user: user, + condition: condition, + ) + + events_data = [] + tickets.each do |ticket| + + event_data = {} + + event_data[:dtstart] = Icalendar::Values::Date.new( Time.zone.today ) + event_data[:dtend] = Icalendar::Values::Date.new( Time.zone.today ) + event_data[:summary] = "#{ticket.state.name} ticket: '#{ticket.title}'" + event_data[:description] = "T##{ticket.number}" + + events_data.push event_data + end + + events_data + end + + def self.pending(user) + + condition = { + 'tickets.owner_id' => user.id, + 'tickets.state_id' => Ticket::State.where( + state_type_id: Ticket::StateType.where( + name: [ + 'pending reminder', + 'pending action', + ], + ), + ), + } + + tickets = Ticket.search( + current_user: user, + condition: condition, + ) + + events_data = [] + tickets.each do |ticket| + + event_data = {} + + # rubocop:disable Rails/TimeZone + event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time ) + event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time ) + # rubocop:enable Rails/TimeZone + event_data[:summary] = "#{ticket.state.name} ticket: '#{ticket.title}'" + event_data[:description] = "T##{ticket.number}" + + events_data.push event_data + end + + events_data + end + + def self.escalation(user) + + condition = [ + 'tickets.escalation_time IS NOT NULL', + 'tickets.owner_id = ?', user.id + ] + + tickets = Ticket.search( + current_user: user, + condition: condition, + ) + + events_data = [] + tickets.each do |ticket| + + event_data = {} + + # rubocop:disable Rails/TimeZone + event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time ) + event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time ) + # rubocop:enable Rails/TimeZone + event_data[:summary] = "ticket escalation: '#{ticket.title}'" + event_data[:description] = "T##{ticket.number}" + + events_data.push event_data + end + + events_data + end + +end From d2306dc7fbbc2cc5471d7c27b2ee87386520499e Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Mon, 22 Jun 2015 19:45:16 +0200 Subject: [PATCH 08/18] Added integration tests for iCal feature. --- test/integration/i_cal_ticket_test.rb | 171 ++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 test/integration/i_cal_ticket_test.rb diff --git a/test/integration/i_cal_ticket_test.rb b/test/integration/i_cal_ticket_test.rb new file mode 100644 index 000000000..895228569 --- /dev/null +++ b/test/integration/i_cal_ticket_test.rb @@ -0,0 +1,171 @@ +# encoding: utf-8 +require 'integration_test_helper' + +class ICalTicketTest < ActiveSupport::TestCase + + user = User.create( + firstname: 'iCal', + lastname: 'Testuser', + email: 'ical_testuser@example.com', + updated_by_id: 1, + created_by_id: 1, + ); + + sla = Sla.create( + name: 'sla 1', + condition: {}, + data: { + 'Mon' => 'Mon', 'Tue' => 'Tue', 'Wed' => 'Wed', 'Thu' => 'Thu', 'Fri' => 'Fri', 'Sat' => 'Sat', 'Sun' => 'Sun', + 'beginning_of_workday' => '9:00', + 'end_of_workday' => '18:00', + }, + timezone: 'Europe/Berlin', + first_response_time: 10, + update_time: 10, + close_time: 10, + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + + tickets = [ + { + owner: user, + title: 'new 1', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'new' ), + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'open 1', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'open' ), + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'pending reminder 1', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'pending reminder' ), + pending_time: Time.zone.parse('1977-10-27 22:00:00 +0000'), + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'pending reminder 2', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'pending reminder' ), + pending_time: DateTime.tomorrow, + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'pending close 1', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'pending close' ), + pending_time: Time.zone.parse('1977-10-27 22:00:00 +0000'), + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'pending close 2', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'pending close' ), + pending_time: DateTime.tomorrow, + priority: Ticket::Priority.lookup( name: '2 normal' ), + updated_by_id: 1, + created_by_id: 1, + }, + { + owner: user, + title: 'escalation 1', + group: Group.lookup( name: 'Users'), + customer_id: user.id, + state: Ticket::State.lookup( name: 'open' ), + priority: Ticket::Priority.lookup( name: '2 normal' ), + created_at: '2013-03-21 09:30:00 UTC', + updated_at: '2013-03-21 09:30:00 UTC', + updated_by_id: 1, + created_by_id: 1, + }, + ] + + tickets.each { |ticket| + + Ticket.create( ticket ) + } + + test 'new_open' do + + event_data = ICal::Ticket.new_open( user ) + + assert_equal( 3, event_data.length, 'event count' ) + + ical = ICal.to_ical( event_data ) + + event_data.each{ |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "ical contains '#{event[:summary]}'" ) + } + end + + test 'pending' do + + event_data = ICal::Ticket.pending( user ) + + assert_equal( 4, event_data.length, 'event count' ) + + ical = ICal.to_ical( event_data ) + + event_data.each{ |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "ical contains '#{event[:summary]}'" ) + } + end + + test 'escalation' do + + event_data = ICal::Ticket.escalation( user ) + + assert_equal( 7, event_data.length, 'event count' ) + + ical = ICal.to_ical( event_data ) + + event_data.each{ |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "ical contains '#{event[:summary]}'" ) + } + end +end From 5d4c4db4d3011e68b0a62314fb5afd197abcd992 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 22 Jun 2015 20:41:35 +0200 Subject: [PATCH 09/18] Removed not needed debug logging. --- .../app/controllers/ticket_zoom.js.coffee | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index 8a960be21..d2da185fd 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -365,15 +365,16 @@ class App.TicketZoom extends App.Controller @autosaveLast = @taskGet() update = => #console.log('AR', @formParam( @el.find('.article-add') ) ) + currentStoreTicket = @ticket.attributes() + delete currentStoreTicket.article currentStore = - ticket: @ticket.attributes() - article: { + ticket: currentStoreTicket + article: to: '' cc: '' type: 'note' body: '' internal: '' - } currentParams = ticket: @formParam( @el.find('.edit') ) article: @formParam( @el.find('.article-add') ) @@ -390,13 +391,13 @@ class App.TicketZoom extends App.Controller # get diff of last save changedBetweenLastSave = _.isEqual(currentParams, @autosaveLast ) if !changedBetweenLastSave - console.log('model DIFF ', modelDiff) + #console.log('model DIFF ', modelDiff) @autosaveLast = clone(currentParams) @markFormDiff( modelDiff ) @taskUpdateAll( modelDiff ) - @interval( update, 3000, 'autosave' ) + @interval( update, 4000, 'autosave' ) markFormDiff: (diff = {}) => ticketForm = @$('.edit') @@ -407,7 +408,7 @@ class App.TicketZoom extends App.Controller params = {} params.ticket = @formParam( ticketForm ) params.article = @formParam( articleForm ) - console.log('markFormDiff', diff, params) + #console.log('markFormDiff', diff, params) # clear all changes if _.isEmpty(diff.ticket) && _.isEmpty(diff.article) From 79ba2dd4be246f083bcab5c96403f4a699494ae4 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 22 Jun 2015 21:08:47 +0200 Subject: [PATCH 10/18] Force to use sql backend for search. --- lib/i_cal/ticket.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/i_cal/ticket.rb b/lib/i_cal/ticket.rb index f58537177..1a18764fe 100644 --- a/lib/i_cal/ticket.rb +++ b/lib/i_cal/ticket.rb @@ -16,6 +16,7 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, + detail: true, ) events_data = [] @@ -51,6 +52,7 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, + detail: true, ) events_data = [] @@ -81,6 +83,7 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, + detail: true, ) events_data = [] From bea2a732e8cec3591ee68dd40c989d7cee552e93 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 22 Jun 2015 21:32:29 +0200 Subject: [PATCH 11/18] Improved api, removed not needed attribute. --- app/controllers/tickets_controller.rb | 9 --------- app/models/ticket/search.rb | 19 ++++++++++++++----- lib/i_cal/ticket.rb | 3 --- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb index 922ea3277..e7e0cb549 100644 --- a/app/controllers/tickets_controller.rb +++ b/app/controllers/tickets_controller.rb @@ -329,7 +329,6 @@ class TicketsController < ApplicationController query: params[:term], condition: params[:condition], current_user: current_user, - detail: params[:detail] ) assets = {} ticket_result = [] @@ -372,10 +371,8 @@ class TicketsController < ApplicationController } user_tickets_open = Ticket.search( limit: limit, - #:query => params[:term], condition: condition, current_user: current_user, - detail: true, ) user_tickets_open_ids = assets_of_tickets(user_tickets_open, assets) @@ -386,10 +383,8 @@ class TicketsController < ApplicationController } user_tickets_closed = Ticket.search( limit: limit, - #:query => params[:term], condition: condition, current_user: current_user, - detail: true, ) user_tickets_closed_ids = assets_of_tickets(user_tickets_closed, assets) @@ -438,10 +433,8 @@ class TicketsController < ApplicationController } org_tickets_open = Ticket.search( limit: limit, - #:query => params[:term], condition: condition, current_user: current_user, - detail: true, ) org_tickets_open_ids = assets_of_tickets(org_tickets_open, assets) @@ -452,10 +445,8 @@ class TicketsController < ApplicationController } org_tickets_closed = Ticket.search( limit: limit, - #:query => params[:term], condition: condition, current_user: current_user, - detail: true, ) org_tickets_closed_ids = assets_of_tickets(org_tickets_closed, assets) diff --git a/app/models/ticket/search.rb b/app/models/ticket/search.rb index 766baafa3..138406051 100644 --- a/app/models/ticket/search.rb +++ b/app/models/ticket/search.rb @@ -22,7 +22,7 @@ search tickets via search index :current_user => User.find(123), :query => 'search something', :limit => 15, - :full => 0 + :full => false, ) returns @@ -33,10 +33,19 @@ search tickets via database result = Ticket.search( :current_user => User.find(123), - :condition => '', - :detail => true, + :condition => { + 'tickets.owner_id' => user.id, + 'tickets.state_id' => Ticket::State.where( + state_type_id: Ticket::StateType.where( + name: [ + 'pending reminder', + 'pending action', + ], + ), + ), + }, :limit => 15, - :full => 0 + :full => false, ) returns @@ -57,7 +66,7 @@ returns end # try search index backend - if !params[:detail] && SearchIndexBackend.enabled? + if !params[:condition] && SearchIndexBackend.enabled? query_extention = {} query_extention['bool'] = {} query_extention['bool']['must'] = [] diff --git a/lib/i_cal/ticket.rb b/lib/i_cal/ticket.rb index 1a18764fe..f58537177 100644 --- a/lib/i_cal/ticket.rb +++ b/lib/i_cal/ticket.rb @@ -16,7 +16,6 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, - detail: true, ) events_data = [] @@ -52,7 +51,6 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, - detail: true, ) events_data = [] @@ -83,7 +81,6 @@ module ICal::Ticket tickets = Ticket.search( current_user: user, condition: condition, - detail: true, ) events_data = [] From 584022533245b6d38e83ecd81df9cc0633345023 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 23 Jun 2015 14:17:04 +0200 Subject: [PATCH 12/18] Prepared for request_type replacement. --- lib/session_helper.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/session_helper.rb b/lib/session_helper.rb index ffba462ae..f1081602e 100644 --- a/lib/session_helper.rb +++ b/lib/session_helper.rb @@ -28,11 +28,12 @@ module SessionHelper def self.cleanup_expired - # web sessions - ActiveRecord::SessionStore::Session.where('request_type = ? AND updated_at < ?', 1, Time.zone.now - 90.days ).delete_all + # delete temp. sessions + ActiveRecord::SessionStore::Session.where('request_type IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all + + # web sessions older the x days + ActiveRecord::SessionStore::Session.where('updated_at < ?', Time.zone.now - 90.days ).delete_all - # http basic auth calls - ActiveRecord::SessionStore::Session.where('request_type = ? AND updated_at < ?', 2, Time.zone.now - 2.days ).delete_all end def self.get(id) From dffadb8452d50b2cbb615b376798022e1b6a39c7 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 23 Jun 2015 14:48:15 +0200 Subject: [PATCH 13/18] Improved timing. --- test/browser_test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 4c15fe52d..8e6d974eb 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -1225,7 +1225,7 @@ wait untill text in selector disabppears if data[:state] || data[:group] || data[:body] found = nil - (1..5).each { + (1..7).each { if !found begin text = instance.find_elements( { css: '.content.active .js-reset' } )[0].text From 2aad09dab2c8e2ec7037166ba030b3af3e0b224a Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 23 Jun 2015 15:47:18 +0200 Subject: [PATCH 14/18] Improved timing. --- test/browser_test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 8e6d974eb..717062540 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -1225,7 +1225,7 @@ wait untill text in selector disabppears if data[:state] || data[:group] || data[:body] found = nil - (1..7).each { + (1..10).each { if !found begin text = instance.find_elements( { css: '.content.active .js-reset' } )[0].text From 7b87bf23afd11523f73a509456ffe6d2aba06fb1 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 23 Jun 2015 19:50:11 +0200 Subject: [PATCH 15/18] Fixed dashboard test. --- test/browser/prefereces_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/browser/prefereces_test.rb b/test/browser/prefereces_test.rb index fb4779f73..2c7ec2a07 100644 --- a/test/browser/prefereces_test.rb +++ b/test/browser/prefereces_test.rb @@ -65,7 +65,7 @@ class PreferencesTest < TestCase click( css: '#navigation a[href="#dashboard"]' ) watch_for( css: '.content.active', - value: 'Meine zugewiesenen' + value: 'Meine Statistik' ) # check language in overview @@ -179,7 +179,7 @@ class PreferencesTest < TestCase click( css: '#navigation a[href="#dashboard"]' ) watch_for( css: '.content.active', - value: 'My assig' + value: 'My Stats' ) # check language in overview @@ -305,7 +305,7 @@ class PreferencesTest < TestCase click( css: '#navigation a[href="#dashboard"]' ) watch_for( css: '.content.active', - value: 'Meine' + value: 'Meine Statistik' ) # check language in overview From c49792513eb83ed1018e8022a07d1631cdad9ae6 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Tue, 23 Jun 2015 14:27:17 +0200 Subject: [PATCH 16/18] Improved comment. --- app/models/token.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/token.rb b/app/models/token.rb index 0d65900f2..54bdb3a68 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -21,7 +21,7 @@ class Token < ActiveRecord::Base return end - # return token if valid + # return token user token.user end From e91553d164c6adc89a9db625d37e2550d36d8261 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Wed, 24 Jun 2015 10:48:48 +0200 Subject: [PATCH 17/18] - Refactored authentication_check_only. - Replaced session[:request_type] with session[:persistent]. --- app/controllers/application_controller.rb | 121 ++++++++----------- app/controllers/sessions_controller.rb | 4 + app/models/observer/session.rb | 12 +- db/migrate/20150623145511_session_changes.rb | 24 ++++ lib/session_helper.rb | 2 +- 5 files changed, 86 insertions(+), 77 deletions(-) create mode 100644 db/migrate/20150623145511_session_changes.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 86a7e35a6..9ac15fd70 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -98,122 +98,98 @@ class ApplicationController < ActionController::Base def authentication_check_only(auth_param) logger.debug 'authentication_check' - session[:request_type] = 1 #logger.debug params.inspect #logger.debug session.inspect #logger.debug cookies.inspect - # check http basic auth - authenticate_with_http_basic do |username, password| - logger.debug 'http basic auth check' - session[:request_type] = 2 + # already logged in, early exit + if session.id && session[:user_id] + userdata = User.find( session[:user_id] ) + current_user_set(userdata) - userdata = User.authenticate( username, password ) - message = '' - if !userdata - message = 'authentication failed' - end + return { + auth: true + } + end - # return auth ok - if message == '' + error_message = 'authentication failed' - # remember user - session[:user_id] = userdata.id + # check logon session + if params['logon_session'] + logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first - # set basic auth user to current user + # set logon session user to current user + if logon_session + userdata = User.find( logon_session.data[:user_id] ) current_user_set(userdata) + + session[:persistent] = true + return { auth: true } end - # return auth not ok + error_message = 'no valid session, user_id' + end + + # check sso + sso_userdata = User.sso(params) + if sso_userdata + + current_user_set(sso_userdata) + + session[:persistent] = true + return { - auth: false, - message: message, + auth: true } end - # check logon session - if params['logon_session'] - logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first - if logon_session - userdata = User.find( logon_session.data[:user_id] ) - end + # check http basic auth + authenticate_with_http_basic do |username, password| + logger.debug "http basic auth check '#{username}'" - session[:request_type] = 3 + userdata = User.authenticate( username, password ) - # set logon session user to current user + next if !userdata + + # set basic auth user to current user current_user_set(userdata) return { auth: true } end - # check sso - if !session[:user_id] - - user = User.sso(params) - - # Log the authorizing user in. - if user - session[:user_id] = user.id - end - end - # check token if auth_param[:token_action] - authenticate_with_http_token do |token, options| - logger.debug 'token auth check' - session[:request_type] = 4 + authenticate_with_http_token do |token, _options| + logger.debug "token auth check #{token}" userdata = Token.check( action: auth_param[:token_action], name: token, ) - message = '' - if !userdata - message = 'authentication failed' - end + next if !userdata - # return auth ok - if message == '' + # set token user to current user + current_user_set(userdata) - # remember user - session[:user_id] = userdata.id - - # set token user to current user - current_user_set(userdata) - return { - auth: true - } - end - - # return auth not ok return { - auth: false, - message: message, + auth: true } end end - # return auth not ok (no session exists) - if !session[:user_id] - logger.debug 'no valid session, user_id' - message = 'no valid session, user_id' - return { - auth: false, - message: message, - } - end - + logger.debug error_message { - auth: true + auth: false, + message: error_message, } end - def authentication_check( auth_param = { basic_auth_promt: false } ) + def authentication_check( auth_param = {} ) result = authentication_check_only(auth_param) # check if basic_auth fallback is possible @@ -233,6 +209,9 @@ class ApplicationController < ActionController::Base return false end + # store current user id into the session + session[:user_id] = current_user.id + # return auth ok true end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index f0d530207..079ad10d8 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -54,6 +54,10 @@ class SessionsController < ApplicationController # ) end + # sessions created via this + # controller are persistent + session[:persistent] = true + # return new session data render status: :created, json: { diff --git a/app/models/observer/session.rb b/app/models/observer/session.rb index cd051fb21..5a2f490ee 100644 --- a/app/models/observer/session.rb +++ b/app/models/observer/session.rb @@ -13,15 +13,17 @@ class Observer::Session < ActiveRecord::Observer check(record) end + # move the persistent attribute from the sub structure + # to the first level so it gets stored in the database + # column to make the cleanup lookup more performant def check(record) return if !record.data - return if record[:request_type] + return if record[:persistent] - # remember request type - return if !record.data['request_type'] + return if !record.data['persistent'] - record[:request_type] = record.data['request_type'] - record.data.delete('request_type') + record[:persistent] = record.data['persistent'] + record.data.delete('persistent') end end diff --git a/db/migrate/20150623145511_session_changes.rb b/db/migrate/20150623145511_session_changes.rb new file mode 100644 index 000000000..4fd08afd3 --- /dev/null +++ b/db/migrate/20150623145511_session_changes.rb @@ -0,0 +1,24 @@ +class SessionChanges < ActiveRecord::Migration + def up + + ActiveRecord::SessionStore::Session.delete_all + + remove_index :sessions, :request_type + remove_column :sessions, :request_type + + add_column :sessions, :persistent, :boolean, null: true + add_index :sessions, :persistent + end + + def down + + ActiveRecord::SessionStore::Session.delete_all + + remove_index :sessions, :persistent + remove_column :sessions, :persistent + + add_column :sessions, :request_type, :integer, null: true + add_index :sessions, :request_type + end + +end diff --git a/lib/session_helper.rb b/lib/session_helper.rb index f1081602e..7c74addf2 100644 --- a/lib/session_helper.rb +++ b/lib/session_helper.rb @@ -29,7 +29,7 @@ module SessionHelper def self.cleanup_expired # delete temp. sessions - ActiveRecord::SessionStore::Session.where('request_type IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all + ActiveRecord::SessionStore::Session.where('persistent IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all # web sessions older the x days ActiveRecord::SessionStore::Session.where('updated_at < ?', Time.zone.now - 90.days ).delete_all From 81539e11f6d0aed668694895dae526e8f20a457e Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Wed, 24 Jun 2015 11:54:15 +0200 Subject: [PATCH 18/18] Skip tickets with missing pending or escalation time. --- lib/i_cal/ticket.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/i_cal/ticket.rb b/lib/i_cal/ticket.rb index f58537177..0363845fc 100644 --- a/lib/i_cal/ticket.rb +++ b/lib/i_cal/ticket.rb @@ -56,6 +56,8 @@ module ICal::Ticket events_data = [] tickets.each do |ticket| + next if !ticket.pending_time + event_data = {} # rubocop:disable Rails/TimeZone @@ -86,6 +88,8 @@ module ICal::Ticket events_data = [] tickets.each do |ticket| + next if !ticket.escalation_time + event_data = {} # rubocop:disable Rails/TimeZone