Merge pull request #142 from martini/ical_tickets
iCal export and persistent tokens
This commit is contained in:
commit
6b88429eb0
7 changed files with 353 additions and 9 deletions
3
Gemfile
3
Gemfile
|
@ -105,3 +105,6 @@ gem 'prawn'
|
||||||
gem 'prawn-table'
|
gem 'prawn-table'
|
||||||
|
|
||||||
gem 'puma'
|
gem 'puma'
|
||||||
|
|
||||||
|
# ical export
|
||||||
|
gem 'icalendar'
|
||||||
|
|
|
@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
helper_method :current_user,
|
helper_method :current_user,
|
||||||
:authentication_check,
|
:authentication_check,
|
||||||
|
:authentication_check_action_token,
|
||||||
:config_frontend,
|
:config_frontend,
|
||||||
:is_role,
|
:is_role,
|
||||||
:model_create_render,
|
:model_create_render,
|
||||||
|
@ -193,6 +194,24 @@ class ApplicationController < ActionController::Base
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def authentication_check_action_token(action)
|
||||||
|
|
||||||
|
user = Token.check(
|
||||||
|
:action => action,
|
||||||
|
:name => params[:action_token],
|
||||||
|
)
|
||||||
|
|
||||||
|
if !user
|
||||||
|
puts params.inspect
|
||||||
|
response_access_deny
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
current_user_set( user )
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def is_role( role_name )
|
def is_role( role_name )
|
||||||
return false if !current_user
|
return false if !current_user
|
||||||
return true if current_user.is_role( role_name )
|
return true if current_user.is_role( role_name )
|
||||||
|
|
195
app/controllers/ical_tickets_controller.rb
Normal file
195
app/controllers/ical_tickets_controller.rb
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
require 'icalendar'
|
||||||
|
|
||||||
|
class IcalTicketsController < ApplicationController
|
||||||
|
before_filter { authentication_check_action_token 'iCal' }
|
||||||
|
|
||||||
|
# @path [GET] /ical/tickets_all/:action_token
|
||||||
|
#
|
||||||
|
# @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 500 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
|
||||||
|
|
||||||
|
events_data = new_open_events_data + pending_events_data + escalation_events_data
|
||||||
|
|
||||||
|
events_data_to_ical( events_data )
|
||||||
|
end
|
||||||
|
|
||||||
|
# @path [GET] /ical/tickets_new_open/:action_token
|
||||||
|
#
|
||||||
|
# @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 500 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
|
||||||
|
#
|
||||||
|
# @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 500 Permission denied.
|
||||||
|
def pending
|
||||||
|
events_data = pending_events_data_get
|
||||||
|
|
||||||
|
events_data_to_ical( events_data )
|
||||||
|
end
|
||||||
|
|
||||||
|
# @path [GET] /ical/ticket_escalation/:action_token
|
||||||
|
#
|
||||||
|
# @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 500 Permission denied.
|
||||||
|
def escalation
|
||||||
|
events_data = escalation_events_data_get
|
||||||
|
|
||||||
|
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 => [
|
||||||
|
'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( Date.today )
|
||||||
|
event_data[:dtend] = Icalendar::Values::Date.new( Date.today )
|
||||||
|
event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'"
|
||||||
|
event_data[:description] = "T##{ ticket.number }"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
return 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 = {}
|
||||||
|
|
||||||
|
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
||||||
|
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
||||||
|
event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'"
|
||||||
|
event_data[:description] = "T##{ ticket.number }"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
return 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 = {}
|
||||||
|
|
||||||
|
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
||||||
|
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
||||||
|
event_data[:summary] = "ticket escalation: '#{ ticket.title }'"
|
||||||
|
event_data[:description] = "T##{ ticket.number }"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
return 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
|
||||||
|
|
||||||
|
send_data(
|
||||||
|
cal.to_ical,
|
||||||
|
:filename => 'new_open.ical',
|
||||||
|
:type => 'text/plain',
|
||||||
|
:disposition => 'inline'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -12,7 +12,8 @@ class Token < ActiveRecord::Base
|
||||||
return if !token
|
return if !token
|
||||||
|
|
||||||
# check if token is still valid
|
# check if token is still valid
|
||||||
if token.created_at < 1.day.ago
|
if !token.persistent &&
|
||||||
|
token.created_at < 1.day.ago
|
||||||
|
|
||||||
# delete token
|
# delete token
|
||||||
token.delete
|
token.delete
|
||||||
|
|
9
config/routes/ical_tickets.rb
Normal file
9
config/routes/ical_tickets.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
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
|
||||||
|
end
|
8
db/migrate/20150220216145_token_persistent.rb
Normal file
8
db/migrate/20150220216145_token_persistent.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
class TokenPersistent < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :tokens, :persistent, :boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
109
test/unit/token_test.rb
Normal file
109
test/unit/token_test.rb
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TokenTest < ActiveSupport::TestCase
|
||||||
|
test 'token' do
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
|
||||||
|
# test 1
|
||||||
|
{
|
||||||
|
:test_name => 'invalid token',
|
||||||
|
:action => 'PasswordReset',
|
||||||
|
:name => '1NV4L1D',
|
||||||
|
:result => nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
# test 2
|
||||||
|
{
|
||||||
|
:test_name => 'fresh token',
|
||||||
|
:create => {
|
||||||
|
:user_id => 2,
|
||||||
|
:action => 'PasswordReset',
|
||||||
|
},
|
||||||
|
:action => 'PasswordReset',
|
||||||
|
:result => true,
|
||||||
|
:verify => {
|
||||||
|
:firstname => 'Nicole',
|
||||||
|
:lastname => 'Braun',
|
||||||
|
:email => 'nicole.braun@zammad.org',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
# test 3
|
||||||
|
{
|
||||||
|
:test_name => 'two days but not persistent',
|
||||||
|
:create => {
|
||||||
|
:user_id => 2,
|
||||||
|
:action => 'PasswordReset',
|
||||||
|
:created_at => 2.day.ago,
|
||||||
|
},
|
||||||
|
:action => 'PasswordReset',
|
||||||
|
:result => nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
:test_name => 'two days but persistent',
|
||||||
|
:create => {
|
||||||
|
:user_id => 2,
|
||||||
|
:action => 'iCal',
|
||||||
|
:created_at => 2.day.ago,
|
||||||
|
:persistent => true,
|
||||||
|
},
|
||||||
|
:action => 'iCal',
|
||||||
|
:result => true,
|
||||||
|
:verify => {
|
||||||
|
:firstname => 'Nicole',
|
||||||
|
:lastname => 'Braun',
|
||||||
|
:email => 'nicole.braun@zammad.org',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.each { |test|
|
||||||
|
|
||||||
|
if test[:create]
|
||||||
|
|
||||||
|
#puts test[:test_name] + ': creating token '+ test[:create].inspect
|
||||||
|
|
||||||
|
token = Token.create(
|
||||||
|
:action => test[:create][:action],
|
||||||
|
:user_id => test[:create][:user_id],
|
||||||
|
:created_at => test[:create][:created_at].to_s,
|
||||||
|
:persistent => test[:create][:persistent]
|
||||||
|
)
|
||||||
|
|
||||||
|
#puts test[:test_name] + ': created token ' + token.inspect
|
||||||
|
|
||||||
|
test[:name] = token.name
|
||||||
|
end
|
||||||
|
|
||||||
|
user = Token.check(
|
||||||
|
:action => test[:action],
|
||||||
|
:name => test[:name]
|
||||||
|
)
|
||||||
|
|
||||||
|
if test[:result] == true
|
||||||
|
if !user
|
||||||
|
assert( false, test[:test_name] + ': token verification failed' )
|
||||||
|
else
|
||||||
|
test[:verify].each {|key, value|
|
||||||
|
assert_equal( user[key], value, 'verify' )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
assert_equal( test[:result], user, test[:test_name] + ': failed or not existing' )
|
||||||
|
end
|
||||||
|
|
||||||
|
if test[:name]
|
||||||
|
#puts test[:test_name] + ': deleting token '+ test[:name]
|
||||||
|
|
||||||
|
token = Token.where( :name => test[:name] ).first
|
||||||
|
|
||||||
|
if token
|
||||||
|
token.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue