Reworked iCal functionality and integration tests, now CalendarSubscriptions.

This commit is contained in:
Thorsten Eckel 2015-06-26 14:00:10 +02:00
parent a8672c502a
commit 01adfa4dea
11 changed files with 297 additions and 233 deletions

View file

@ -21,20 +21,11 @@ class CalendarSubscriptions extends App.Controller
render: => render: =>
userPreferences = @Session.get('preferences') userPreferences = @Session.get('preferences')
@preferences = @preferences = App.Config.get('defaults_calendar_subscriptions_tickets')
new_open:
own: true
not_assigned: false
pending:
own: true
not_assigned: false
escalation:
own: true
not_assigned: false
if userPreferences.ical if userPreferences.calendar_subscriptions
if userPreferences.ical.ticket if userPreferences.calendar_subscriptions.tickets
_.extend(@preferences, userPreferences.ical.ticket) _.extend(@preferences, userPreferences.calendar_subscriptions.tickets)
@html App.view('profile/calendar_subscriptions') @html App.view('profile/calendar_subscriptions')
baseurl: window.location.origin baseurl: window.location.origin
@ -67,8 +58,8 @@ class CalendarSubscriptions extends App.Controller
# get data # get data
data = data =
user: user:
ical: calendar_subscriptions:
ticket: @preferences tickets: @preferences
@ajax( @ajax(
id: 'preferences' id: 'preferences'

View file

@ -8,7 +8,7 @@
<p><%= @T('See your tickets from within your favorite calendar by adding the following url to your calendar app.') %></p> <p><%= @T('See your tickets from within your favorite calendar by adding the following url to your calendar app.') %></p>
<h3><%= @T('Combined Url') %></h3> <h3><%= @T('Combined Url') %></h3>
<input class="form-control js-select" readonly value="<%= @baseurl %>/ical/tickets"> <input class="form-control js-select" readonly value="<%= @baseurl %>/calendar_subscriptions/tickets">
<h3><%= @T('Subscription Settings') %></h3> <h3><%= @T('Subscription Settings') %></h3>
<table class="settings-list"> <table class="settings-list">
@ -25,7 +25,7 @@
<td style="text-transform: capitalize"><%= @translationTable[stateType] %> <td style="text-transform: capitalize"><%= @translationTable[stateType] %>
<td><label class="inline-label"><input type="checkbox" name="<%= stateType %>/own"<%= if options.own then ' checked' %>> <%= @T('own tickets') %></label> <td><label class="inline-label"><input type="checkbox" name="<%= stateType %>/own"<%= if options.own then ' checked' %>> <%= @T('own tickets') %></label>
<td><label class="inline-label"><input type="checkbox" name="<%= stateType %>/not_assigned"<%= if options.not_assigned then ' checked' %>> <%= @T('not assigned tickets') %></label> <td><label class="inline-label"><input type="checkbox" name="<%= stateType %>/not_assigned"<%= if options.not_assigned then ' checked' %>> <%= @T('not assigned tickets') %></label>
<td><div class="btn btn--table btn--text js-showLink"><%= @T('Show') %></div><input class="form-control form-control--borderless js-select is-hidden" readonly value="<%= @baseurl %>/ical/tickets/<%= stateType %>"> <td><div class="btn btn--table btn--text js-showLink"><%= @T('Show') %></div><input class="form-control form-control--borderless js-select is-hidden" readonly value="<%= @baseurl %>/calendar_subscriptions/tickets/<%= stateType %>">
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>

View file

@ -2,18 +2,18 @@
require 'icalendar' require 'icalendar'
class ICalController < ApplicationController class CalendarSubscriptionsController < ApplicationController
before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) } before_action { authentication_check( { basic_auth_promt: true, token_action: 'CalendarSubscriptions' } ) }
# @path [GET] /ical # @path [GET] /calendar_subscriptions
# #
# @summary Returns an iCal file with all objects matching the iCal preferences of the current user as events. # @summary Returns an iCal file with all objects matching the calendar subscriptions preferences of the current user as events.
# #
# @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied. # @response_message 401 Permission denied.
def all def all
ical_object = ICal.new( current_user ) calendar_subscriptions = CalendarSubscriptions.new( current_user )
ical = ical_object.all ical = calendar_subscriptions.all
send_data( send_data(
ical, ical,
@ -27,20 +27,16 @@ class ICalController < ApplicationController
render json: { error: e.message }, status: :unprocessable_entity render json: { error: e.message }, status: :unprocessable_entity
end end
# @path [GET] /ical/:object # @path [GET] /calendar_subscriptions/:object
# @path [GET] /ical/:object/:method # @path [GET] /calendar_subscriptions/:object/:method
# #
# @summary Returns an iCal file of the given object (and method) matching the iCal preferences of the current user as events. # @summary Returns an iCal file of the given object (and method) matching the calendar subscriptions preferences of the current user as events.
# #
# @response_message 200 [String] iCal file ready to import in calendar applications. # @response_message 200 [String] iCal file ready to import in calendar applications.
# @response_message 401 Permission denied. # @response_message 401 Permission denied.
def object def object
ical_object = ICal.new( current_user ) calendar_subscriptions = CalendarSubscriptions.new( current_user )
ical = calendar_subscriptions.generic( params[:object], params[:method] )
# 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( send_data(
ical, ical,

View file

@ -0,0 +1,6 @@
Zammad::Application.routes.draw do
match '/calendar_subscriptions', to: 'calendar_subscriptions#all', via: :get
match '/calendar_subscriptions/:object', to: 'calendar_subscriptions#object', via: :get
match '/calendar_subscriptions/:object/:method', to: 'calendar_subscriptions#object', via: :get
end

View file

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

View file

@ -0,0 +1,29 @@
class DefaultsCalendarSubscriptionsTickets < ActiveRecord::Migration
def up
Setting.create_if_not_exists(
title: 'Default calendar Tickets subscriptions',
name: 'defaults_calendar_subscriptions_tickets',
area: 'Defaults::CalendarSubscriptions',
description: 'Defines the default calendar Tickets subscription settings.',
options: {},
state: {
escalation: {
own: true,
not_assigned: false,
},
new_open: {
own: true,
not_assigned: false,
},
pending: {
own: true,
not_assigned: false,
}
},
frontend: true
)
end
def down
end
end

View file

@ -1259,6 +1259,29 @@ Setting.create_if_not_exists(
frontend: false frontend: false
) )
Setting.create_if_not_exists(
title: 'Default calendar Tickets subscriptions',
name: 'defaults_calendar_subscriptions_tickets',
area: 'Defaults::CalendarSubscriptions',
description: 'Defines the default calendar Tickets subscription settings.',
options: {},
state: {
escalation: {
own: true,
not_assigned: false,
},
new_open: {
own: true,
not_assigned: false,
},
pending: {
own: true,
not_assigned: false,
}
},
frontend: true
)
email_address = EmailAddress.create_if_not_exists( email_address = EmailAddress.create_if_not_exists(
id: 1, id: 1,
realname: 'Zammad', realname: 'Zammad',

View file

@ -1,15 +1,23 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
class ICal class CalendarSubscriptions
def initialize(user) def initialize(user)
@user = user @user = user
@preferences = {} @preferences = {}
default_preferences = Setting.where( area: 'Defaults::CalendarSubscriptions' )
default_preferences.each { |calendar_subscription|
if @user.preferences[:ical] && !@user.preferences[:ical].empty? next if calendar_subscription.name !~ /\Adefaults_calendar_subscriptions_(.*)\z/
@preferences = @user.preferences[:ical]
end object_name = $1
@preferences[ object_name ] = calendar_subscription.state[:value]
}
return if !@user.preferences[:calendar_subscriptions]
return if @user.preferences[:calendar_subscriptions].empty?
@preferences = @preferences.merge( @user.preferences[:calendar_subscriptions] )
end end
def all def all
@ -34,10 +42,10 @@ class ICal
events_data = [] events_data = []
if @preferences[ object_name ] && !@preferences[ object_name ].empty? if @preferences[ object_name ] && !@preferences[ object_name ].empty?
sub_class_name = object_name.to_s.capitalize sub_class_name = object_name.to_s.capitalize
object = Object.const_get('ICal').const_get("ICal#{sub_class_name}") object = Object.const_get("CalendarSubscriptions::#{sub_class_name}")
instance = object.new( @user, @preferences[ object_name ] ) instance = object.new( @user, @preferences[ object_name ] )
method = instance.method( method_name ) method = instance.method( method_name )
events_data += method.call events_data += method.call
end end
events_data events_data
end end

View file

@ -0,0 +1,164 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
class CalendarSubscriptions::Tickets
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

View file

@ -1,168 +0,0 @@
# 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,12 +1,12 @@
## encoding: utf-8 ## encoding: utf-8
require 'integration_test_helper' require 'integration_test_helper'
class ICalTicketTest < ActiveSupport::TestCase class CalendarSubscriptionsTicketsTest < ActiveSupport::TestCase
user = User.create( user = User.create(
firstname: 'iCal', firstname: 'CalendarSubscriptions',
lastname: 'Testuser', lastname: 'Testuser',
email: 'ical_testuser@example.com', email: 'calendar_subscriptions_testuser@example.com',
updated_by_id: 1, updated_by_id: 1,
created_by_id: 1, created_by_id: 1,
) )
@ -190,6 +190,21 @@ class ICalTicketTest < ActiveSupport::TestCase
Ticket.create( ticket ) Ticket.create( ticket )
} }
defaults_disabled = {
escalation: {
own: false,
not_assigned: false,
},
new_open: {
own: false,
not_assigned: false,
},
pending: {
own: false,
not_assigned: false,
}
}
test 'new_open' do test 'new_open' do
tests = [ tests = [
@ -241,16 +256,18 @@ class ICalTicketTest < ActiveSupport::TestCase
tests.each { |test_data| tests.each { |test_data|
user.preferences[:ical] = {} preferences = defaults_disabled.merge( test_data[:preferences] )
user.preferences[:ical][:ticket] = test_data[:preferences]
ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] ) user.preferences[:calendar_subscriptions] = {}
event_data = ical_ticket.new_open user.preferences[:calendar_subscriptions][:tickets] = preferences
calendar_subscriptions_ticket = CalendarSubscriptions::Tickets.new( user, preferences )
event_data = calendar_subscriptions_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_object = ICal.new( user ) calendar_subscriptions = CalendarSubscriptions.new( user )
ical = ical_object.all ical = calendar_subscriptions.all
event_data.each { |event| event_data.each { |event|
@ -315,16 +332,18 @@ class ICalTicketTest < ActiveSupport::TestCase
tests.each { |test_data| tests.each { |test_data|
user.preferences[:ical] = {} preferences = defaults_disabled.merge( test_data[:preferences] )
user.preferences[:ical][:ticket] = test_data[:preferences]
ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] ) user.preferences[:calendar_subscriptions] = {}
event_data = ical_ticket.pending user.preferences[:calendar_subscriptions][:tickets] = preferences
calendar_subscriptions_ticket = CalendarSubscriptions::Tickets.new( user, preferences )
event_data = calendar_subscriptions_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_object = ICal.new( user ) calendar_subscriptions = CalendarSubscriptions.new( user )
ical = ical_object.all ical = calendar_subscriptions.all
event_data.each { |event| event_data.each { |event|
@ -389,16 +408,18 @@ class ICalTicketTest < ActiveSupport::TestCase
tests.each { |test_data| tests.each { |test_data|
user.preferences[:ical] = {} preferences = defaults_disabled.merge( test_data[:preferences] )
user.preferences[:ical][:ticket] = test_data[:preferences]
ical_ticket = ICal::ICalTicket.new( user, test_data[:preferences] ) user.preferences[:calendar_subscriptions] = {}
event_data = ical_ticket.escalation user.preferences[:calendar_subscriptions][:tickets] = preferences
calendar_subscriptions_ticket = CalendarSubscriptions::Tickets.new( user, preferences )
event_data = calendar_subscriptions_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_object = ICal.new( user ) calendar_subscriptions = CalendarSubscriptions.new( user )
ical = ical_object.all ical = calendar_subscriptions.all
event_data.each { |event| event_data.each { |event|