otrs_proxy 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ html/*
3
+ pkg
4
+ *.swp
5
+ .rvmrc*
6
+ .bundle
7
+ couchdb.std*
8
+ *.*~
9
+ Gemfile.lock
10
+ spec.out
11
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in otrs_connector.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,36 @@
1
+ This gem is a bridge between the OTRS API.
2
+ You can use this to connect to the OTRS API in a more RESTful way.
3
+ This is still a work in development and only partial functionality has been added.
4
+
5
+ Items to clean up
6
+ - Finish making tickets/articles/links create/update methods more ActiveRecord like
7
+
8
+ Partially implemented
9
+ - Tickets API
10
+ - Articles API
11
+ - Links API
12
+ - ITSM ConfigItems API
13
+
14
+
15
+ To customize for your use you must have the OTRS json.pl in your OTRS cgi-bin directory.
16
+ I also added ITSMConfigItemObjects to this json as it is required for my use.
17
+ I will create an OPM package with a custom json.pl to do it the right way (instead of editing existing files directly, causing errors in the admin interface).
18
+
19
+ You need include this gem in your project and call
20
+
21
+ OtrsConnector.initialize_for_app(host, api_url, user, pass)
22
+
23
+ The username/password combo should be an existing agent in OTRS.
24
+
25
+ SIMPLE EXAMPLES:
26
+
27
+ Articles:
28
+
29
+ articles = OtrsConnector::OTRS::Ticket::Article.where(ticket_id)
30
+ article = OtrsConnector::OTRS::Ticket::Article.find(id)
31
+ article = OtrsConnector::OTRS::Ticket::Article.new(params[:article])
32
+ article.save
33
+ article.update_attributes(params[:article])
34
+ article.destroy
35
+
36
+ Source classes: https://github.com/cpuguy83/rails_otrs
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/json.pl.example ADDED
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/perl -w
2
+ # --
3
+ # bin/cgi-bin/json.pl - json handle
4
+ # Copyright (C) 2001-2010 OTRS AG, http://otrs.org/
5
+ # --
6
+ # $Id: json.pl,v 1.13 2010/09/23 17:51:02 cr Exp $
7
+ # --
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU AFFERO General Public License as published by
10
+ # the Free Software Foundation; either version 3 of the License, or
11
+ # any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Affero General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ # or see http://www.gnu.org/licenses/agpl.txt.
22
+ # --
23
+
24
+ use strict;
25
+ use warnings;
26
+
27
+ # use ../../ as lib location
28
+ use FindBin qw($Bin);
29
+ use lib "$Bin/../..";
30
+ use lib "$Bin/../../Kernel/cpan-lib";
31
+
32
+ use Kernel::Config;
33
+ use Kernel::System::Encode;
34
+ use Kernel::System::Log;
35
+ use Kernel::System::DB;
36
+ use Kernel::System::Main;
37
+ use Kernel::System::Time;
38
+ use Kernel::System::Auth;
39
+ use Kernel::System::User;
40
+ use Kernel::System::Group;
41
+ use Kernel::System::Queue;
42
+ use Kernel::System::Service;
43
+ use Kernel::System::Type;
44
+ use Kernel::System::State;
45
+ use Kernel::System::Lock;
46
+ use Kernel::System::SLA;
47
+ use Kernel::System::CustomerUser;
48
+ use Kernel::System::Ticket;
49
+ use Kernel::System::LinkObject;
50
+ use Kernel::System::JSON;
51
+ use Kernel::System::iPhone;
52
+ use Kernel::System::Web::Request;
53
+ use Kernel::System::ITSMConfigItem;
54
+ use Kernel::System::ITSMChange;
55
+ use Kernel::System::ITSMChange::ITSMWorkOrder;
56
+ use Kernel::System::ITSMChange::ITSMStateMachine;
57
+
58
+ use vars qw($VERSION);
59
+ $VERSION = qw($Revision: 1.13 $) [1];
60
+
61
+ my $Self = Core->new();
62
+ print "Content-Type: text/plain; \n";
63
+ print "\n";
64
+ print $Self->Dispatch();
65
+
66
+ package Core;
67
+
68
+ sub new {
69
+ my ( $Type, %Param ) = @_;
70
+
71
+ # allocate new hash for object
72
+ my $Self = {%Param};
73
+ bless( $Self, $Type );
74
+
75
+ return $Self;
76
+ }
77
+
78
+ sub Dispatch {
79
+ my ($Self) = @_;
80
+
81
+ # common objects
82
+ $Self->{ConfigObject} = Kernel::Config->new();
83
+ $Self->{EncodeObject} = Kernel::System::Encode->new( %{$Self} );
84
+ $Self->{LogObject} = Kernel::System::Log->new(
85
+ LogPrefix => 'OTRS-RPC',
86
+ %{$Self},
87
+ );
88
+ $Self->{MainObject} = Kernel::System::Main->new( %{$Self} );
89
+ $Self->{DBObject} = Kernel::System::DB->new( %{$Self} );
90
+ $Self->{TimeObject} = Kernel::System::Time->new( %{$Self} );
91
+ $Self->{UserObject} = Kernel::System::User->new( %{$Self} );
92
+ $Self->{GroupObject} = Kernel::System::Group->new( %{$Self} );
93
+ $Self->{QueueObject} = Kernel::System::Queue->new( %{$Self} );
94
+ $Self->{ServiceObject} = Kernel::System::Service->new( %{$Self} );
95
+ $Self->{TypeObject} = Kernel::System::Type->new( %{$Self} );
96
+ $Self->{StateObject} = Kernel::System::State->new( %{$Self} );
97
+ $Self->{LockObject} = Kernel::System::Lock->new( %{$Self} );
98
+ $Self->{SLAObject} = Kernel::System::SLA->new( %{$Self} );
99
+ $Self->{CustomerUserObject} = Kernel::System::CustomerUser->new( %{$Self} );
100
+ $Self->{TicketObject} = Kernel::System::Ticket->new( %{$Self} );
101
+ $Self->{LinkObject} = Kernel::System::LinkObject->new( %{$Self} );
102
+ $Self->{JSONObject} = Kernel::System::JSON->new( %{$Self} );
103
+ $Self->{ParamObject} = Kernel::System::Web::Request->new( %{$Self} );
104
+ $Self->{iPhoneObject} = Kernel::System::iPhone->new( %{$Self} );
105
+ $Self->{ConfigItemObject} = Kernel::System::ITSMConfigItem->new( %{$Self} );
106
+ $Self->{ChangeObject} = Kernel::System::ITSMChange->new( %{$Self} );
107
+ $Self->{WorkOrderObject} = Kernel::System::ITSMChange::ITSMWorkOrder->new( %{$Self} );
108
+ $Self->{StateMachineObject} = Kernel::System::ITSMChange::ITSMStateMachine->new( %{$Self} );
109
+
110
+ # get log filename
111
+ if ( $Self->{ConfigObject}->Get('iPhone::LogFile') ) {
112
+ $Self->{DebugLogFile} = $Self->{ConfigObject}->Get('iPhone::LogFile');
113
+ }
114
+
115
+ # set common variables
116
+ my $User = $Self->{ParamObject}->GetParam( Param => 'User' );
117
+ my $Pw = $Self->{ParamObject}->GetParam( Param => 'Password' );
118
+ my $Object = $Self->{ParamObject}->GetParam( Param => 'Object' );
119
+ my $Method = $Self->{ParamObject}->GetParam( Param => 'Method' );
120
+ my $Data = $Self->{ParamObject}->GetParam( Param => 'Data' );
121
+ my $ParamScalar = $Self->{JSONObject}->Decode( Data => $Data );
122
+
123
+ my %Param;
124
+ if ($ParamScalar) {
125
+ %Param = %{$ParamScalar};
126
+ }
127
+ $User ||= '';
128
+ $Pw ||= '';
129
+
130
+ # inbound log
131
+ if ( $Self->{ConfigObject}->Get('iPhone::DebugLog') ) {
132
+ my $Message = 'User=' . $User . '&Password=****' . '&Object=' . $Object
133
+ . '&Method=' . $Method . '&Data=' . $Data;
134
+
135
+ $Self->Log(
136
+ Direction => 'Inbound',
137
+ Message => $Message,
138
+ )
139
+ }
140
+
141
+ # agent auth
142
+ my %ParamFixed;
143
+ if (1) {
144
+ my $AuthObject = Kernel::System::Auth->new( %{$Self} );
145
+ my $UserLogin = $AuthObject->Auth( User => $User, Pw => $Pw );
146
+
147
+ if ( !$UserLogin ) {
148
+ $Self->{LogObject}->Log(
149
+ Priority => 'notice',
150
+ Message => "Auth for user $User failed!",
151
+ );
152
+ return $Self->Result();
153
+ }
154
+
155
+ # set user id
156
+ my $UserID = $Self->{UserObject}->UserLookup(
157
+ UserLogin => $UserLogin,
158
+ );
159
+ return if !$UserID;
160
+
161
+ $ParamFixed{UserID} = $UserID;
162
+ }
163
+
164
+ # system auth
165
+ else {
166
+ my $RequiredUser = $Self->{ConfigObject}->Get('SOAP::User');
167
+ my $RequiredPassword = $Self->{ConfigObject}->Get('SOAP::Password');
168
+
169
+ if (
170
+ !defined $RequiredUser
171
+ || !length $RequiredUser
172
+ || !defined $RequiredPassword || !length $RequiredPassword
173
+ )
174
+ {
175
+ $Self->{LogObject}->Log(
176
+ Priority => 'notice',
177
+ Message => 'SOAP::User or SOAP::Password is empty, SOAP access denied!',
178
+ );
179
+ return $Self->Result();
180
+ }
181
+
182
+ if ( $User ne $RequiredUser || $Pw ne $RequiredPassword ) {
183
+ $Self->{LogObject}->Log(
184
+ Priority => 'notice',
185
+ Message => "Auth for user $User failed!",
186
+ );
187
+ return $Self->Result();
188
+ }
189
+ }
190
+
191
+ if ( !$Self->{$Object} && $Object ne 'CustomObject' ) {
192
+ $Self->{LogObject}->Log(
193
+ Priority => 'error',
194
+ Message => "No such Object $Object!",
195
+ );
196
+ return $Self->Result();
197
+ }
198
+
199
+ if ( ( $Self->{$Object} && !$Self->{$Object}->can($Method) ) && !$Self->can($Method) ) {
200
+ $Self->{LogObject}->Log(
201
+ Priority => 'error',
202
+ Message => "No such method '$Method' in '$Object'!",
203
+ );
204
+ return $Self->Result();
205
+ }
206
+
207
+ if ( $Object =~ /^(DBObject|TicketObject123)$/ ) {
208
+ $Self->{LogObject}->Log(
209
+ Priority => 'error',
210
+ Message => "No access to '$Object'!",
211
+ );
212
+ return $Self->Result();
213
+ }
214
+
215
+ if ( $Object eq 'CustomObject' ) {
216
+ my @Result = $Self->{iPhoneObject}->$Method(
217
+ %Param,
218
+ %ParamFixed,
219
+ );
220
+ return $Self->Result( \@Result );
221
+ }
222
+ else {
223
+ my @Result = $Self->{$Object}->$Method(
224
+ %Param,
225
+ %ParamFixed,
226
+ );
227
+ return $Self->Result( \@Result );
228
+ }
229
+ }
230
+
231
+ sub Result {
232
+ my ( $Self, $Result ) = @_;
233
+
234
+ my %ResultProtocol;
235
+
236
+ if ($Result) {
237
+ if ( @{$Result} ) {
238
+ if ( @{$Result}[0] eq -1 ) {
239
+ $ResultProtocol{Result} = 'failed';
240
+ for my $Key (qw(error notice)) {
241
+ $ResultProtocol{Message} = $Self->{LogObject}->GetLogEntry(
242
+ Type => $Key,
243
+ What => 'Message',
244
+ );
245
+ last if $ResultProtocol{Message};
246
+ }
247
+ }
248
+
249
+ else {
250
+ $ResultProtocol{Result} = 'successful';
251
+ $ResultProtocol{Data} = $Result;
252
+ }
253
+ }
254
+
255
+ else {
256
+ $ResultProtocol{Result} = 'successful';
257
+ $ResultProtocol{Data} = $Result;
258
+ }
259
+ }
260
+
261
+ else {
262
+ $ResultProtocol{Result} = 'failed';
263
+ for my $Key (qw(error notice)) {
264
+ $ResultProtocol{Message} = $Self->{LogObject}->GetLogEntry(
265
+ Type => $Key,
266
+ What => 'Message',
267
+ );
268
+ last if $ResultProtocol{Message};
269
+ }
270
+ }
271
+
272
+ # set result to a variable for easy log output
273
+ my $JSONResult = $Self->{JSONObject}->Encode( Data => \%ResultProtocol );
274
+
275
+ # outbound log
276
+ if ( $Self->{ConfigObject}->Get('iPhone::DebugLog') ) {
277
+
278
+ $Self->Log(
279
+ Direction => 'Outbound',
280
+ Message => $JSONResult,
281
+ )
282
+ }
283
+
284
+ return $JSONResult;
285
+ }
286
+
287
+ sub Log {
288
+ my ( $Self, %Param ) = @_;
289
+
290
+ my $FH;
291
+
292
+ # open logfile
293
+ if ( !open $FH, '>>', $Self->{DebugLogFile} ) {
294
+
295
+ # print error screen
296
+ print STDERR "\n";
297
+ print STDERR " >> Can't write $Self->{LogFile}: $! <<\n";
298
+ print STDERR "\n";
299
+ return;
300
+ }
301
+
302
+ # write log file
303
+ print $FH '[' . $Self->{TimeObject}->CurrentTimestamp() . ']';
304
+ print $FH "[Debug] [$Param{Direction}] [$Param{Message}\n";
305
+
306
+ # close file handle
307
+ close $FH;
308
+ return 1;
309
+ }
310
+
311
+ 1;
@@ -0,0 +1,25 @@
1
+ module OtrsConnector
2
+ class OTRS::Change::State < OTRS::Change
3
+ @@class = 'ITSM::ChangeManagement::Change::State'
4
+
5
+ def self.all
6
+ #params = "Object=StateMachineObject&Method=StateList&Data={\"Class\":\"#{@@class}\",\"UserID\":\"1\"}"
7
+ data = { 'Class' => @@class, 'UserID' => 1 }
8
+ params = { :object => 'StateMachineObject', :method => 'StateList', :data => data }
9
+ a = connect(params).flatten
10
+ b = []
11
+ a.each do |c|
12
+ tmp = {}
13
+ c.each do |key,value|
14
+ case key
15
+ when "Key" then tmp[:id] = value
16
+ when "Value" then tmp[:name] = value
17
+ end
18
+ end
19
+ c = tmp
20
+ b << new(c)
21
+ end
22
+ b
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ module OtrsConnector
2
+ class OTRS::Change::WorkOrder < OTRS::Change
3
+
4
+ def create(attributes)
5
+ tmp = {}
6
+ attributes.each do |key,value|
7
+ tmp[key.to_s.camelize.to_sym] = value
8
+ end
9
+ attributes = tmp
10
+ attributes[:UserID] = '1'
11
+ attributes[:ChangeID] = attributes[:ChangeId]
12
+ attributes.delete(:ChangeId)
13
+ data = attributes
14
+ params = { :object => 'WorkOrderObject', :method => 'WorkOrderAdd', :data => data }
15
+ a = connect(params)
16
+ id = a.first
17
+ if id.nil?
18
+ nil
19
+ else
20
+ b = self.class.find(id)
21
+ attributes = b.attributes
22
+ attributes.each do |key,value|
23
+ instance_variable_set "@#{key.to_s}", value
24
+ end
25
+ b
26
+ end
27
+ end
28
+
29
+ def update_attributes(attributes)
30
+ tmp = {}
31
+ attributes.each do |key,value|
32
+ tmp[key.to_s.camelize] = value #Copies ruby style keys to camel case for OTRS
33
+ end
34
+ tmp['WorkOrderID'] = @work_order_id
35
+ data = tmp
36
+ params = { :object => 'WorkOrderObject', :method => 'WorkOrderUpdate', :data => data }
37
+ a = connect(params)
38
+ if a.first.nil?
39
+ nil
40
+ else
41
+ return self
42
+ end
43
+ end
44
+
45
+ def self.find(id)
46
+ data = { 'WorkOrderID' => id, 'UserID' => 1 }
47
+ params = { :object => 'WorkOrderObject', :method => 'WorkOrderGet', :data => data }
48
+ a = connect(params)
49
+ a = Hash[*a]
50
+ self.new(a.symbolize_keys)
51
+ end
52
+
53
+ def destroy
54
+ id = @change_id
55
+ if self.class.find(id)
56
+ data = { 'ChangeID' => id, 'UserID' => 1 }
57
+ params = { :object => 'WorkOrderObject', :method => 'WorkOrderDelete', :data => data }
58
+ connect(params)
59
+ "WorkOrderID #{id} deleted"
60
+ else
61
+ raise "NoSuchWorkOrderID #{id}"
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,74 @@
1
+ module OtrsConnector
2
+ class OTRS::Change < OTRS
3
+
4
+ def create(attributes)
5
+ tmp = {}
6
+ attributes.each do |key,value|
7
+ tmp[key.to_s.camelize.to_sym] = value
8
+ end
9
+ attributes = tmp
10
+ attributes[:UserID] = '1'
11
+ data = attributes
12
+ params = { :object => 'ChangeObject', :method => 'ChangeAdd', :data => data }
13
+ a = connect(params)
14
+ id = a.first
15
+ a = self.class.find(id)
16
+ attributes = a.attributes
17
+ attributes.each do |key,value|
18
+ instance_variable_set "@#{key.to_s}", value
19
+ end
20
+ end
21
+
22
+ def self.find(id)
23
+ data = { 'ChangeID' => id, 'UserID' => 1 }
24
+ params = { :object => 'ChangeObject', :method => 'ChangeGet', :data => data }
25
+ a = connect(params)
26
+ a = Hash[*a]
27
+ self.new(a.symbolize_keys)
28
+ end
29
+
30
+ def self.where(attributes)
31
+ tmp = {}
32
+ attributes.each do |key,value|
33
+ tmp[key.to_s.camelize] = value #Copies ruby style keys to camel case for OTRS
34
+ end
35
+ data = tmp
36
+ params = { :object => 'ChangeObject', :method => 'ChangeSearch', :data => data }
37
+ a = connect(params).flatten
38
+ b = []
39
+ a.each do |c|
40
+ b << find(c)
41
+ end
42
+ b
43
+ end
44
+
45
+ def update_attributes(attributes)
46
+ tmp = {}
47
+ attributes.each do |key,value|
48
+ tmp[key.to_s.camelize] = value #Copies ruby style keys to camel case for OTRS
49
+ end
50
+ tmp['ChangeID'] = @change_id
51
+ data = tmp
52
+ params = { :object => 'ChangeObject', :method => 'ChangeUpdate', :data => data }
53
+ a = connect(params)
54
+ if a.first.nil?
55
+ nil
56
+ else
57
+ return self
58
+ end
59
+ end
60
+
61
+ def destroy
62
+ id = @change_id
63
+ if self.class.find(id)
64
+ data = { 'ChangeID' => id, 'UserID' => 1 }
65
+ params = { :object => 'ChangeObject', :method => 'ChangeDelete', :data => data }
66
+ connect(params)
67
+ "ChangeID #{id} deleted"
68
+ else
69
+ raise "NoSuchChangeID #{id}"
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,25 @@
1
+ module OtrsConnector
2
+ class OTRS::ConfigItem::Definition < OTRS::ConfigItem
3
+
4
+ def initialize(attributes = {})
5
+ attributes.each do |name, value|
6
+ self.class.set_accessor(name)
7
+ send("#{name.to_sym}=", value)
8
+ end
9
+ end
10
+
11
+ def self.find(id)
12
+ data = { 'DefinitionID' => id }
13
+ params = { :object => 'ConfigItemObject', :method => 'DefinitionGet', :data => data }
14
+ a = connect(params).first
15
+ new(a)
16
+ end
17
+
18
+ def self.find_by_class_id(id)
19
+ data = { 'ClassID' => id }
20
+ params = { :object => 'ConfigItemObject', :method => 'DefinitionGet', :data => data }
21
+ a = connect(params).first
22
+ new(a)
23
+ end
24
+ end
25
+ end