Reworked iCal functionality and integration tests.

This commit is contained in:
Thorsten Eckel 2015-06-25 16:17:57 +02:00
parent a98c02d582
commit aba5be2fb8
6 changed files with 280 additions and 179 deletions

View file

@ -0,0 +1,57 @@
# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
require 'icalendar'
class ICalController < ApplicationController
before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) }
# @path [GET] /ical
#
# @summary Returns an iCal file with all objects matching the iCal preferences of the current user as events.
#
# @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied.
def all
ical_object = ICal.new( current_user )
ical = ical_object.all
send_data(
ical,
filename: 'zammad.ical',
type: 'text/plain',
disposition: 'inline'
)
rescue => e
logger.error e.message
logger.error e.backtrace.inspect
render json: { error: e.message }, status: :unprocessable_entity
end
# @path [GET] /ical/:object
# @path [GET] /ical/:object/:method
#
# @summary Returns an iCal file of the given object (and method) matching the iCal preferences of the current user as events.
#
# @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied.
def object
ical_object = ICal.new( current_user )
# remove the last char (s/plural) from the object name
object_name = params[:object].to_s[0...-1].to_sym
ical = ical_object.generic( object_name, params[:method] )
send_data(
ical,
filename: 'zammad.ical',
type: 'text/plain',
disposition: 'inline'
)
rescue => e
logger.error e.message
logger.error e.backtrace.inspect
render json: { error: e.message }, status: :unprocessable_entity
end
end

7
config/routes/i_cal.rb Normal file
View file

@ -0,0 +1,7 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
match api_path + '/ical', to: 'i_cal#all', via: :get
match api_path + '/ical/:object', to: 'i_cal#object', via: :get
match api_path + '/ical/:object/:method', to: 'i_cal#object', via: :get
end

View file

@ -1,24 +1,48 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
module ICal class ICal
def self.preferenced(user) def initialize(user)
@user = user
@preferences = {}
if @user.preferences[:ical] && !@user.preferences[:ical].empty?
@preferences = @user.preferences[:ical]
end
end
def all
events_data = [] events_data = []
@preferences.each { |object_name, _sub_structure|
user.preferences[:ical].each { |sub_class, _sub_structure| result = generic_call( object_name )
events_data = events_data + result
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 ) to_ical( events_data )
end end
def self.to_ical(events_data) def generic(object_name, method_name = 'all')
events_data = generic_call( object_name, method_name )
to_ical( events_data )
end
def generic_call(object_name, method_name = 'all')
method_name ||= 'all'
events_data = []
if @preferences[ object_name ] && !@preferences[ object_name ].empty?
sub_class_name = object_name.to_s.capitalize
object = Object.const_get('ICal').const_get("ICal#{sub_class_name}")
instance = object.new( @user, @preferences[ object_name ] )
method = instance.method( method_name )
events_data += method.call
end
events_data
end
def to_ical(events_data)
cal = Icalendar::Calendar.new cal = Icalendar::Calendar.new

168
lib/i_cal/i_cal_ticket.rb Normal file
View file

@ -0,0 +1,168 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
class ICal
class ICalTicket
def initialize(user, preferences)
@user = user
@preferences = preferences
end
def all
events_data = []
return events_data if @preferences.empty?
events_data += new_open
events_data += pending
events_data += escalation
events_data
end
def owner_ids(method)
owner_ids = []
return owner_ids if @preferences.empty?
return owner_ids if !@preferences[ method ]
return owner_ids if @preferences[ method ].empty?
preferences = @preferences[ method ]
if preferences[:own]
owner_ids = [ @user.id ]
end
if preferences[:not_assigned]
owner_ids.push( 1 )
end
owner_ids
end
def new_open
events_data = []
owner_ids = owner_ids(:new_open)
return events_data if owner_ids.empty?
condition = {
'tickets.owner_id' => owner_ids,
'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 pending
events_data = []
owner_ids = owner_ids(:pending)
return events_data if owner_ids.empty?
condition = {
'tickets.owner_id' => owner_ids,
'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|
next if !ticket.pending_time
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( 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}"
events_data.push event_data
end
events_data
end
def escalation
events_data = []
owner_ids = owner_ids(:escalation)
return events_data if owner_ids.empty?
condition = [
'tickets.owner_id IN (?) AND tickets.escalation_time IS NOT NULL', owner_ids
]
tickets = Ticket.search(
current_user: @user,
condition: condition,
)
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( 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}"
events_data.push event_data
end
events_data
end
end
end

View file

@ -1,161 +0,0 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
module ICal::Ticket
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' => owner_ids,
'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, owner_ids)
events_data = []
return events_data if owner_ids.empty?
condition = {
'tickets.owner_id' => owner_ids,
'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|
next if !ticket.pending_time
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( 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}"
events_data.push event_data
end
events_data
end
def self.escalation(user, owner_ids)
events_data = []
return events_data if owner_ids.empty?
condition = [
'tickets.owner_id IN (?) AND tickets.escalation_time IS NOT NULL', owner_ids
]
tickets = Ticket.search(
current_user: user,
condition: condition,
)
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( 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}"
events_data.push event_data
end
events_data
end
end

View file

@ -244,11 +244,13 @@ class ICalTicketTest < ActiveSupport::TestCase
user.preferences[:ical] = {} user.preferences[:ical] = {}
user.preferences[:ical][:ticket] = test_data[:preferences] user.preferences[:ical][:ticket] = test_data[:preferences]
event_data = ICal::Ticket.new_open( user, test_data[:owner_ids] ) ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] )
event_data = ical_ticket.new_open
assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" )
ical = ICal.preferenced( user ) ical_object = ICal.new( user )
ical = ical_object.all
event_data.each { |event| event_data.each { |event|
@ -316,11 +318,13 @@ class ICalTicketTest < ActiveSupport::TestCase
user.preferences[:ical] = {} user.preferences[:ical] = {}
user.preferences[:ical][:ticket] = test_data[:preferences] user.preferences[:ical][:ticket] = test_data[:preferences]
event_data = ICal::Ticket.pending( user, test_data[:owner_ids] ) ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] )
event_data = ical_ticket.pending
assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" )
ical = ICal.preferenced( user ) ical_object = ICal.new( user )
ical = ical_object.all
event_data.each { |event| event_data.each { |event|
@ -388,11 +392,13 @@ class ICalTicketTest < ActiveSupport::TestCase
user.preferences[:ical] = {} user.preferences[:ical] = {}
user.preferences[:ical][:ticket] = test_data[:preferences] user.preferences[:ical][:ticket] = test_data[:preferences]
event_data = ICal::Ticket.escalation( user, test_data[:owner_ids] ) ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] )
event_data = ical_ticket.escalation
assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" ) assert_equal( test_data[:count], event_data.length, "#{test_data[:name]} event count" )
ical = ICal.preferenced( user ) ical_object = ICal.new( user )
ical = ical_object.all
event_data.each { |event| event_data.each { |event|