Reworked iCal functionality and integration tests.
This commit is contained in:
parent
a98c02d582
commit
aba5be2fb8
6 changed files with 280 additions and 179 deletions
57
app/controllers/i_cal_controller.rb
Normal file
57
app/controllers/i_cal_controller.rb
Normal 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
7
config/routes/i_cal.rb
Normal 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
|
48
lib/i_cal.rb
48
lib/i_cal.rb
|
@ -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
168
lib/i_cal/i_cal_ticket.rb
Normal 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
|
|
@ -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
|
|
|
@ -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|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue