don't attempt to use RT::CurrentUser before RT has been initialized. very weird...
[freeside.git] / FS / FS / TicketSystem / RT_Internal.pm
1 package FS::TicketSystem::RT_Internal;
2
3 use strict;
4 use vars qw( @ISA $DEBUG $me );
5 use Data::Dumper;
6 use MIME::Entity;
7 use FS::UID qw(dbh);
8 use FS::CGI qw(popurl);
9 use FS::TicketSystem::RT_Libs;
10
11 @ISA = qw( FS::TicketSystem::RT_Libs );
12
13 $DEBUG = 0;
14 $me = '[FS::TicketSystem::RT_Internal]';
15
16 sub sql_num_customer_tickets {
17   "( select count(*) from Tickets
18                      join Links on ( Tickets.id = Links.LocalBase )
19      where ( Status = 'new' or Status = 'open' or Status = 'stalled' )
20        and Target = 'freeside://freeside/cust_main/' || custnum
21    )";
22 }
23
24 sub baseurl {
25   #my $self = shift;
26   if ( $RT::URI::freeside::URL ) {
27     $RT::URI::freeside::URL. '/rt/';
28   } else {
29     'http://you_need_to_set_RT_URI_freeside_URL_in_SiteConfig.pm/';
30   }
31 }
32
33 #mapping/genericize??
34 #ShowConfigTab ModifySelf
35 sub access_right {
36   my( $self, $session, $right ) = @_;
37
38   #return '' unless $conf->config('ticket_system');
39   return '' unless FS::Conf->new->config('ticket_system');
40
41   $session = $self->session($session);
42
43   #warn "$me access_right: CurrentUser ". $session->{'CurrentUser'}. ":\n".
44   #     ( $DEBUG>1 ? Dumper($session->{'CurrentUser'}) : '' )
45   #  if $DEBUG > 1;
46
47   $session->{'CurrentUser'}->HasRight( Right  => $right,
48                                        Object => $RT::System );
49 }
50
51 sub session {
52   my( $self, $session ) = @_;
53
54   if ( $session && $session->{'Current_User'} ) {
55     warn "$me session: using existing session and CurrentUser: \n".
56          Dumper($session->{'CurrentUser'})
57       if $DEBUG;
58  } else {
59     warn "$me session: loading session and CurrentUser\n" if $DEBUG > 1;
60     $session = $self->_web_external_auth($session);
61   }
62
63   $session;
64 }
65
66 sub init {
67   my $self = shift;
68
69   warn "$me init: loading RT libraries\n" if $DEBUG;
70   eval '
71     use lib ( "/opt/rt3/local/lib", "/opt/rt3/lib" );
72     use RT;
73     #it looks like the rest are taken care of these days in RT::InitClasses
74     #use RT::Ticket;
75     #use RT::Transactions;
76     #use RT::Users;
77     #use RT::CurrentUser;
78     #use RT::Templates;
79     #use RT::Queues;
80     #use RT::ScripActions;
81     #use RT::ScripConditions;
82     #use RT::Scrips;
83     #use RT::Groups;
84     #use RT::GroupMembers;
85     #use RT::CustomFields;
86     #use RT::CustomFieldValues;
87     #use RT::ObjectCustomFieldValues;
88
89     #for web external auth...
90     use RT::Interface::Web;
91   ';
92   die $@ if $@;
93
94   warn "$me init: loading RT config\n" if $DEBUG;
95   {
96     local $SIG{__DIE__};
97     eval 'RT::LoadConfig();';
98   }
99   die $@ if $@;
100
101   warn "$me init: initializing RT\n" if $DEBUG;
102   {
103     local $SIG{__DIE__};
104     eval 'RT::Init("NoSignalHandlers"=>1);';
105   }
106   die $@ if $@;
107
108   warn "$me init: complete" if $DEBUG;
109 }
110
111 =item create_ticket SESSION_HASHREF, OPTION => VALUE ...
112
113 Class method.  Creates a ticket.  If there is an error, returns the scalar
114 error, otherwise returns the newly created RT::Ticket object.
115
116 Accepts the following options:
117
118 =over 4
119
120 =item queue
121
122 Queue name or Id
123
124 =item subject
125
126 Ticket subject
127
128 =item requestor
129
130 Requestor email address or arrayref of addresses
131
132 =item cc
133
134 Cc: email address or arrayref of addresses
135
136 =item message
137
138 Ticket message
139
140 =item mime_type
141
142 MIME type to use for message.  Defaults to text/plain.  Specifying text/html
143 can be useful to use HTML markup in message.
144
145 =item custnum
146
147 Customer number (see L<FS::cust_main>) to associate with ticket.
148
149 =item svcnum
150
151 Service number (see L<FS::cust_svc>) to associate with ticket.  Will also
152 associate the customer who has this service (unless the service is unlinked).
153
154 =back
155
156 =cut
157
158 sub create_ticket {
159   my($self, $session, %param) = @_;
160
161   $session = $self->session($session);
162
163   my $Queue = RT::Queue->new($session->{'CurrentUser'});
164   $Queue->Load( $param{'queue'} );
165
166   my $req = ref($param{'requestor'})
167               ? $param{'requestor'}
168               : ( $param{'requestor'} ? [ $param{'requestor'} ] : [] );
169
170   my $cc = ref($param{'cc'})
171              ? $param{'cc'}
172              : ( $param{'cc'} ? [ $param{'cc'} ] : [] );
173
174   my $mimeobj = MIME::Entity->build(
175     'Data' => $param{'message'},
176     'Type' => ( $param{'mime_type'} || 'text/plain' ),
177   );
178
179   my %ticket = (
180     'Queue'     => $Queue->Id,
181     'Subject'   => $param{'subject'},
182     'Requestor' => $req,
183     'Cc'        => $cc,
184     'MIMEObj'   => $mimeobj,
185   );
186   warn Dumper(\%ticket) if $DEBUG > 1;
187
188   my $Ticket = RT::Ticket->new($session->{'CurrentUser'});
189   my( $id, $Transaction, $ErrStr );
190   {
191     local $SIG{__DIE__};
192     ( $id, $Transaction, $ErrStr ) = $Ticket->Create( %ticket );
193   }
194   return $ErrStr if $id == 0;
195
196   warn "ticket got id $id\n" if $DEBUG;
197
198   #XXX check errors adding custnum/svcnum links (put it in a transaction)...
199   # but we do already know they're good
200
201   if ( $param{'custnum'} ) {
202     my( $val, $msg ) = $Ticket->_AddLink(
203      'Type'   => 'MemberOf',
204      'Target' => 'freeside://freeside/cust_main/'. $param{'custnum'},
205     );
206   }
207
208   if ( $param{'svcnum'} ) {
209     my( $val, $msg ) = $Ticket->_AddLink(
210      'Type'   => 'MemberOf',
211      'Target' => 'freeside://freeside/cust_svc/'. $param{'svcnum'},
212     );
213   }
214
215   $Ticket;
216 }
217
218 #shameless false laziness w/RT::Interface::Web::AttemptExternalAuth
219 # to get logged into RT from afar
220 sub _web_external_auth {
221   my( $self, $session ) = @_;
222
223   my $user = $FS::CurrentUser::CurrentUser->username;
224
225   eval 'use RT::CurrentUser;';
226   die $@ if $@;
227
228   $session ||= {};
229   $session->{'CurrentUser'} = RT::CurrentUser->new();
230
231   warn "$me _web_external_auth loading RT user for $user\n"
232     if $DEBUG > 1;
233
234   $session->{'CurrentUser'}->Load($user);
235
236   if ( ! $session->{'CurrentUser'}->Id() ) {
237
238       # Create users on-the-fly
239
240       warn "can't load RT user for $user; auto-creating\n"
241         if $DEBUG;
242
243       my $UserObj = RT::User->new( RT::CurrentUser->new('RT_System') );
244
245       my ( $val, $msg ) = $UserObj->Create(
246           %{ ref($RT::AutoCreate) ? $RT::AutoCreate : {} },
247           Name  => $user,
248           Gecos => $user,
249       );
250
251       if ($val) {
252
253           # now get user specific information, to better create our user.
254           my $new_user_info
255               = RT::Interface::Web::WebExternalAutoInfo($user);
256
257           # set the attributes that have been defined.
258           # FIXME: this is a horrible kludge. I'm sure there's something cleaner
259           foreach my $attribute (
260               'Name',                  'Comments',
261               'Signature',             'EmailAddress',
262               'PagerEmailAddress',     'FreeformContactInfo',
263               'Organization',          'Disabled',
264               'Privileged',            'RealName',
265               'NickName',              'Lang',
266               'EmailEncoding',         'WebEncoding',
267               'ExternalContactInfoId', 'ContactInfoSystem',
268               'ExternalAuthId',        'Gecos',
269               'HomePhone',             'WorkPhone',
270               'MobilePhone',           'PagerPhone',
271               'Address1',              'Address2',
272               'City',                  'State',
273               'Zip',                   'Country'
274               )
275           {
276               #uhh, wrong root
277               #$m->comp( '/Elements/Callback', %ARGS,
278               #    _CallbackName => 'NewUser' );
279
280               my $method = "Set$attribute";
281               $UserObj->$method( $new_user_info->{$attribute} )
282                   if ( defined $new_user_info->{$attribute} );
283           }
284           $session->{'CurrentUser'}->Load($user);
285       }
286       else {
287
288          # we failed to successfully create the user. abort abort abort.
289           delete $session->{'CurrentUser'};
290
291           die "can't auto-create RT user"; #an error message would be nice :/
292           #$m->abort() unless $RT::WebFallbackToInternalAuth;
293           #$m->comp( '/Elements/Login', %ARGS,
294           #    Error => loc( 'Cannot create user: [_1]', $msg ) );
295       }
296   }
297
298   unless ( $session->{'CurrentUser'}->Id() ) {
299       delete $session->{'CurrentUser'};
300
301       die "can't auto-create RT user";
302       #$user = $orig_user;
303       # 
304       #if ($RT::WebExternalOnly) {
305       #    $m->comp( '/Elements/Login', %ARGS,
306       #        Error => loc('You are not an authorized user') );
307       #    $m->abort();
308       #}
309   }
310
311   $session;
312
313 }
314
315 1;
316