otrs_proxy 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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