From 45eb2e251db8324c81806fb4f33498c69f38d0ae Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Wed, 24 Jun 2015 19:49:01 +0200 Subject: [PATCH] Reworked iCal functionality and integration tests. --- app/controllers/ical_tickets_controller.rb | 88 ------ config/routes/ical_tickets.rb | 9 - lib/i_cal.rb | 16 ++ lib/i_cal/ticket.rb | 77 +++++- test/integration/i_cal_ticket_test.rb | 296 +++++++++++++++++++-- 5 files changed, 348 insertions(+), 138 deletions(-) delete mode 100644 app/controllers/ical_tickets_controller.rb delete mode 100644 config/routes/ical_tickets.rb diff --git a/app/controllers/ical_tickets_controller.rb b/app/controllers/ical_tickets_controller.rb deleted file mode 100644 index bd6cdff10..000000000 --- a/app/controllers/ical_tickets_controller.rb +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/ - -require 'icalendar' - -class IcalTicketsController < ApplicationController - before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) } - - # @path [GET] /ical/tickets - # - # @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events. - # - # @response_message 200 [String] iCal file ready to import in calendar applications. - # @response_message 401 Permission denied. - def all - 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 - - 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 - # - # @summary Returns an iCal file with all new and open tickets as events. - # - # @response_message 200 [String] iCal file ready to import in calendar applications. - # @response_message 401 Permission denied. - def new_open - events_data = ICal::Ticket.new_open(current_user) - - 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 - # - # @summary Returns an iCal file with all pending tickets as events. - # - # @response_message 200 [String] iCal file ready to import in calendar applications. - # @response_message 401 Permission denied. - def pending - events_data = ICal::Ticket.pending(current_user) - - 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 - # - # @summary Returns an iCal file with all escalation times for tickets as events. - # - # @response_message 200 [String] iCal file ready to import in calendar applications. - # @response_message 401 Permission denied. - def escalation - events_data = ICal::Ticket.escalation(current_user) - - ical = ICal.to_ical( events_data ) - - send_data( - ical, - filename: 'zammad_tickets_escalation.ical', - type: 'text/plain', - disposition: 'inline' - ) - end - -end diff --git a/config/routes/ical_tickets.rb b/config/routes/ical_tickets.rb deleted file mode 100644 index 38c24f043..000000000 --- a/config/routes/ical_tickets.rb +++ /dev/null @@ -1,9 +0,0 @@ -Zammad::Application.routes.draw do - api_path = Rails.configuration.api_path - - # ical ticket - 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 diff --git a/lib/i_cal.rb b/lib/i_cal.rb index 7f8be5683..6ded66b0c 100644 --- a/lib/i_cal.rb +++ b/lib/i_cal.rb @@ -2,6 +2,22 @@ module ICal + def self.preferenced(user) + + events_data = [] + + user.preferences[:ical].each { |sub_class, _sub_structure| + + sub_class_name = sub_class.to_s.capitalize + class_name = "ICal::#{sub_class_name}" + + object = Kernel.const_get( class_name ) + events_data += object.preferenced( user ) + } + + to_ical( events_data ) + end + def self.to_ical(events_data) cal = Icalendar::Calendar.new diff --git a/lib/i_cal/ticket.rb b/lib/i_cal/ticket.rb index 0363845fc..6366d76b7 100644 --- a/lib/i_cal/ticket.rb +++ b/lib/i_cal/ticket.rb @@ -2,10 +2,49 @@ module ICal::Ticket - def self.new_open(user) + def self.preferenced(user) + + events_data = [] + return events_data if !user.preferences[:ical] + return events_data if !user.preferences[:ical][:ticket] + + preferences = user.preferences[:ical][:ticket] + + [:new_open, :pending, :escalation].each { |state_type| + + next if !preferences[ state_type ] + + owner_ids = [] + if preferences[ state_type ][:own] + owner_ids = [ user.id ] + end + if preferences[ state_type ][:not_assigned] + owner_ids.push( 1 ) + end + + next if owner_ids.empty? + + if state_type == :new_open + events_data += new_open(user, owner_ids) + elsif state_type == :pending + events_data += pending(user, owner_ids) + elsif state_type == :escalation + events_data += escalation(user, owner_ids) + end + } + + events_data + end + + private + + def self.new_open(user, owner_ids) + + events_data = [] + return events_data if owner_ids.empty? condition = { - 'tickets.owner_id' => user.id, + 'tickets.owner_id' => owner_ids, 'tickets.state_id' => Ticket::State.where( state_type_id: Ticket::StateType.where( name: %w(new open), @@ -34,10 +73,13 @@ module ICal::Ticket events_data end - def self.pending(user) + def self.pending(user, owner_ids) + + events_data = [] + return events_data if owner_ids.empty? condition = { - 'tickets.owner_id' => user.id, + 'tickets.owner_id' => owner_ids, 'tickets.state_id' => Ticket::State.where( state_type_id: Ticket::StateType.where( name: [ @@ -60,9 +102,14 @@ module ICal::Ticket event_data = {} + pending_time = ticket.pending_time + if pending_time < Time.zone.today + pending_time = Time.zone.today + end + # rubocop:disable Rails/TimeZone - event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time ) - event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time ) + event_data[:dtstart] = Icalendar::Values::DateTime.new( pending_time ) + event_data[:dtend] = Icalendar::Values::DateTime.new( pending_time ) # rubocop:enable Rails/TimeZone event_data[:summary] = "#{ticket.state.name} ticket: '#{ticket.title}'" event_data[:description] = "T##{ticket.number}" @@ -73,11 +120,13 @@ module ICal::Ticket events_data end - def self.escalation(user) + def self.escalation(user, owner_ids) + + events_data = [] + return events_data if owner_ids.empty? condition = [ - 'tickets.escalation_time IS NOT NULL', - 'tickets.owner_id = ?', user.id + 'tickets.owner_id IN (?) AND tickets.escalation_time IS NOT NULL', owner_ids ] tickets = Ticket.search( @@ -85,16 +134,20 @@ module ICal::Ticket condition: condition, ) - events_data = [] tickets.each do |ticket| next if !ticket.escalation_time event_data = {} + escalation_time = ticket.escalation_time + if escalation_time < Time.zone.today + escalation_time = Time.zone.today + end + # rubocop:disable Rails/TimeZone - event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time ) - event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time ) + event_data[:dtstart] = Icalendar::Values::DateTime.new( escalation_time ) + event_data[:dtend] = Icalendar::Values::DateTime.new( escalation_time ) # rubocop:enable Rails/TimeZone event_data[:summary] = "ticket escalation: '#{ticket.title}'" event_data[:description] = "T##{ticket.number}" diff --git a/test/integration/i_cal_ticket_test.rb b/test/integration/i_cal_ticket_test.rb index 895228569..d5ef75906 100644 --- a/test/integration/i_cal_ticket_test.rb +++ b/test/integration/i_cal_ticket_test.rb @@ -1,4 +1,4 @@ -# encoding: utf-8 +## encoding: utf-8 require 'integration_test_helper' class ICalTicketTest < ActiveSupport::TestCase @@ -9,7 +9,9 @@ class ICalTicketTest < ActiveSupport::TestCase email: 'ical_testuser@example.com', updated_by_id: 1, created_by_id: 1, - ); + ) + + user_not_assigned = User.find(1) sla = Sla.create( name: 'sla 1', @@ -39,6 +41,16 @@ class ICalTicketTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, }, + { + owner: user_not_assigned, + title: 'new 2', + 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', @@ -49,6 +61,16 @@ class ICalTicketTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, }, + { + owner: user_not_assigned, + title: 'open 2', + 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', @@ -71,6 +93,28 @@ class ICalTicketTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, }, + { + owner: user_not_assigned, + title: 'pending reminder 3', + 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_not_assigned, + title: 'pending reminder 4', + 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', @@ -93,6 +137,28 @@ class ICalTicketTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, }, + { + owner: user_not_assigned, + title: 'pending close 3', + 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_not_assigned, + title: 'pending close 4', + 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', @@ -105,6 +171,18 @@ class ICalTicketTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, }, + { + owner: user_not_assigned, + title: 'escalation 2', + 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| @@ -114,58 +192,218 @@ class ICalTicketTest < ActiveSupport::TestCase test 'new_open' do - event_data = ICal::Ticket.new_open( user ) + tests = [ + { + count: 0, + name: 'none', + preferences: { + new_open: { + own: false, + not_assigned: false, + } + }, + owner_ids: [] + }, + { + count: 3, + name: 'owner', + preferences: { + new_open: { + own: true, + not_assigned: false, + } + }, + owner_ids: [user.id] + }, + { + count: 3, + name: 'not_assigned', + preferences: { + new_open: { + own: false, + not_assigned: true, + } + }, + owner_ids: [user_not_assigned.id] + }, + { + count: 6, + name: 'owner+not_assigned', + preferences: { + new_open: { + own: true, + not_assigned: true, + } + }, + owner_ids: [user.id, user_not_assigned.id] + }, + ] - assert_equal( 3, event_data.length, 'event count' ) + tests.each { |test_data| - ical = ICal.to_ical( event_data ) + user.preferences[:ical] = {} + user.preferences[:ical][:ticket] = test_data[:preferences] - event_data.each{ |event| + event_data = ICal::Ticket.new_open( user, test_data[:owner_ids] ) - contained = false - if ical =~ /#{event[:summary]}/ - contained = true - end + assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) - assert( contained, "ical contains '#{event[:summary]}'" ) + ical = ICal.preferenced( user ) + + event_data.each { |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "#{test_data[:name]} new_open ical contains '#{event[:summary]}'" ) + } } end test 'pending' do - event_data = ICal::Ticket.pending( user ) + tests = [ + { + count: 0, + name: 'none', + preferences: { + pending: { + own: false, + not_assigned: false, + } + }, + owner_ids: [] + }, + { + count: 4, + name: 'owner', + preferences: { + pending: { + own: true, + not_assigned: false, + } + }, + owner_ids: [user.id] + }, + { + count: 4, + name: 'not_assigned', + preferences: { + pending: { + own: false, + not_assigned: true, + } + }, + owner_ids: [user_not_assigned.id] + }, + { + count: 8, + name: 'owner+not_assigned', + preferences: { + pending: { + own: true, + not_assigned: true, + } + }, + owner_ids: [user.id, user_not_assigned.id] + }, + ] - assert_equal( 4, event_data.length, 'event count' ) + tests.each { |test_data| - ical = ICal.to_ical( event_data ) + user.preferences[:ical] = {} + user.preferences[:ical][:ticket] = test_data[:preferences] - event_data.each{ |event| + event_data = ICal::Ticket.pending( user, test_data[:owner_ids] ) - contained = false - if ical =~ /#{event[:summary]}/ - contained = true - end + assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) - assert( contained, "ical contains '#{event[:summary]}'" ) + ical = ICal.preferenced( user ) + + event_data.each { |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "#{test_data[:name]} pending ical contains '#{event[:summary]}'" ) + } } end test 'escalation' do - event_data = ICal::Ticket.escalation( user ) + tests = [ + { + count: 0, + name: 'none', + preferences: { + escalation: { + own: false, + not_assigned: false, + } + }, + owner_ids: [] + }, + { + count: 7, + name: 'owner', + preferences: { + escalation: { + own: true, + not_assigned: false, + } + }, + owner_ids: [user.id] + }, + { + count: 7, + name: 'not_assigned', + preferences: { + escalation: { + own: false, + not_assigned: true, + } + }, + owner_ids: [user_not_assigned.id] + }, + { + count: 12, + name: 'owner+not_assigned', + preferences: { + escalation: { + own: true, + not_assigned: true, + } + }, + owner_ids: [user.id, user_not_assigned.id] + }, + ] - assert_equal( 7, event_data.length, 'event count' ) + tests.each { |test_data| - ical = ICal.to_ical( event_data ) + user.preferences[:ical] = {} + user.preferences[:ical][:ticket] = test_data[:preferences] - event_data.each{ |event| + event_data = ICal::Ticket.escalation( user, test_data[:owner_ids] ) - contained = false - if ical =~ /#{event[:summary]}/ - contained = true - end + assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) - assert( contained, "ical contains '#{event[:summary]}'" ) + ical = ICal.preferenced( user ) + + event_data.each { |event| + + contained = false + if ical =~ /#{event[:summary]}/ + contained = true + end + + assert( contained, "#{test_data[:name]} escalation ical contains '#{event[:summary]}'" ) + } } end + end