fix self-service fallout from RT 3.8, RT#6640
[freeside.git] / FS / FS / Mason.pm
1 package FS::Mason;
2
3 use strict;
4 use vars qw( @ISA @EXPORT_OK $addl_handler_use );
5 use Exporter;
6 use File::Slurp qw( slurp );
7 use HTML::Mason 1.27; #http://www.masonhq.com/?ApacheModPerl2Redirect
8 use HTML::Mason::Interp;
9 use HTML::Mason::Compiler::ToObject;
10
11 @ISA = qw( Exporter );
12 @EXPORT_OK = qw( mason_interps );
13
14 =head1 NAME
15
16 FS::Mason - Initialize the Mason environment
17
18 =head1 SYNOPSIS
19
20   use FS::Mason qw( mason_interps );
21
22   my( $fs_interp, $rt_interp ) = mason_interps('apache');
23
24   #OR
25
26   my( $fs_interp, $rt_interp ) = mason_interps('standalone'); #XXX name?
27
28 =head1 DESCRIPTION
29
30 Initializes the Mason environment, loads all Freeside and RT libraries, etc.
31
32 =cut
33
34 $addl_handler_use = '';
35 my $addl_handler_use_file = '%%%FREESIDE_CONF%%%/addl_handler_use.pl';
36 if ( -e $addl_handler_use_file ) {
37   $addl_handler_use = slurp( $addl_handler_use_file );
38 }
39
40 # List of modules that you want to use from components (see Admin
41 # manual for details)
42 {
43   package HTML::Mason::Commands;
44
45   use strict;
46   use vars qw( %session );
47   use CGI 3.29 qw(-private_tempfiles); #3.29 to fix RT attachment problems
48
49   #breaks quick payment entry
50   #http://rt.cpan.org/Public/Bug/Display.html?id=37365
51   die "CGI.pm v3.38 is broken, use any other version >= 3.29".
52       " (Debian 5.0?  aptitude remove libcgi-pm-perl)"
53     if $CGI::VERSION == 3.38;
54
55   #use CGI::Carp qw(fatalsToBrowser);
56   use CGI::Cookie;
57   use List::Util qw( max min );
58   use Data::Dumper;
59   use Date::Format;
60   use Date::Parse;
61   use Time::Local;
62   use Time::HiRes;
63   use Time::Duration;
64   use DateTime;
65   use DateTime::Format::Strptime;
66   use Lingua::EN::Inflect qw(PL);
67   use Tie::IxHash;
68   use URI;
69   use URI::Escape;
70   use HTML::Entities;
71   use HTML::TreeBuilder;
72   use HTML::FormatText;
73   use JSON;
74   use MIME::Base64;
75   use IO::Handle;
76   use IO::File;
77   use IO::Scalar;
78   #not actually using this yet anyway...# use IPC::Run3 0.036;
79   use Net::Whois::Raw qw(whois);
80   if ( $] < 5.006 ) {
81     eval "use Net::Whois::Raw 0.32 qw(whois)";
82     die $@ if $@;
83   }
84   use Text::CSV_XS;
85   use Spreadsheet::WriteExcel;
86   use Business::CreditCard 0.30; #for mask-aware cardtype()
87   use NetAddr::IP;
88   use Net::Ping;
89   use Net::Ping::External;
90   #if CPAN #7815 ever gets fixed# if ( $Net::Ping::External::VERSION <= 0.12 )
91   {
92     no warnings 'redefine';
93     eval 'sub Net::Ping::External::_ping_linux { 
94             my %args = @_;
95             my $command = "ping -s $args{size} -c $args{count} -w $args{timeout} $args{host}";
96             return Net::Ping::External::_ping_system($command, 0);
97           }
98          ';
99     die $@ if $@;
100   }
101   use String::Approx qw(amatch);
102   use Chart::LinesPoints;
103   use Chart::Mountain;
104   use Color::Scheme;
105   use HTML::Widgets::SelectLayers 0.07; #should go away in favor of
106                                         #selectlayers.html
107   use Locale::Country;
108   use Business::US::USPS::WebTools::AddressStandardization;
109   use FS;
110   use FS::UID qw( getotaker dbh datasrc driver_name );
111   use FS::Record qw( qsearch qsearchs fields dbdef
112                     str2time_sql str2time_sql_closing
113                    );
114   use FS::Conf;
115   use FS::CGI qw(header menubar table itable ntable idiot
116                  eidiot myexit http_header);
117   use FS::UI::Web qw(svc_url);
118   use FS::UI::Web::small_custview qw(small_custview);
119   use FS::UI::bytecount;
120   use FS::Msgcat qw(gettext geterror);
121   use FS::Misc qw( send_email send_fax
122                    states_hash counties cities state_label
123                  );
124   use FS::Misc::eps2png qw( eps2png );
125   use FS::Report::Table::Monthly;
126   use FS::TicketSystem;
127   use FS::Tron qw( tron_lint );
128
129   use FS::agent;
130   use FS::agent_type;
131   use FS::domain_record;
132   use FS::cust_bill;
133   use FS::cust_bill_pay;
134   use FS::cust_credit;
135   use FS::cust_credit_bill;
136   use FS::cust_main qw(smart_search);
137   use FS::cust_main::Import;
138   use FS::cust_main_county;
139   use FS::cust_location;
140   use FS::cust_pay;
141   use FS::cust_pkg;
142   use FS::part_pkg_taxclass;
143   use FS::cust_pkg_reason;
144   use FS::cust_refund;
145   use FS::cust_credit_refund;
146   use FS::cust_pay_refund;
147   use FS::cust_svc;
148   use FS::nas;
149   use FS::part_bill_event;
150   use FS::part_event;
151   use FS::part_event_condition;
152   use FS::part_pkg;
153   use FS::part_referral;
154   use FS::part_svc;
155   use FS::part_svc_router;
156   use FS::part_virtual_field;
157   use FS::pay_batch;
158   use FS::pkg_svc;
159   use FS::port;
160   use FS::queue qw(joblisting);
161   use FS::raddb;
162   use FS::session;
163   use FS::svc_acct;
164   use FS::svc_acct_pop qw(popselector);
165   use FS::acct_rt_transaction;
166   use FS::svc_domain;
167   use FS::svc_forward;
168   use FS::svc_www;
169   use FS::router;
170   use FS::addr_block;
171   use FS::svc_broadband;
172   use FS::svc_external;
173   use FS::type_pkgs;
174   use FS::part_export;
175   use FS::part_export_option;
176   use FS::export_svc;
177   use FS::msgcat;
178   use FS::rate;
179   use FS::rate_region;
180   use FS::rate_prefix;
181   use FS::rate_detail;
182   use FS::usage_class;
183   use FS::payment_gateway;
184   use FS::agent_payment_gateway;
185   use FS::XMLRPC;
186   use FS::payby;
187   use FS::cdr;
188   use FS::cdr_batch;
189   use FS::inventory_class;
190   use FS::inventory_item;
191   use FS::pkg_category;
192   use FS::pkg_class;
193   use FS::access_user;
194   use FS::access_user_pref;
195   use FS::access_group;
196   use FS::access_usergroup;
197   use FS::access_groupagent;
198   use FS::access_right;
199   use FS::AccessRight;
200   use FS::svc_phone;
201   use FS::phone_device;
202   use FS::part_device;
203   use FS::reason_type;
204   use FS::reason;
205   use FS::cust_main_note;
206   use FS::tax_class;
207   use FS::cust_tax_location;
208   use FS::part_pkg_taxproduct;
209   use FS::part_pkg_taxoverride;
210   use FS::part_pkg_taxrate;
211   use FS::tax_rate;
212   use FS::part_pkg_report_option;
213   use FS::cust_attachment;
214   use FS::h_cust_pkg;
215   use FS::h_svc_acct;
216   use FS::h_svc_broadband;
217   use FS::h_svc_domain;
218   #use FS::h_domain_record;
219   use FS::h_svc_external;
220   use FS::h_svc_forward;
221   use FS::h_svc_phone;
222   #use FS::h_phone_device;
223   use FS::h_svc_www;
224   use FS::cust_statement;
225   use FS::cust_class;
226   use FS::cust_category;
227   use FS::prospect_main;
228   use FS::contact;
229   # Sammath Naur
230
231   if ( $FS::Mason::addl_handler_use ) {
232     eval $FS::Mason::addl_handler_use;
233     die $@ if $@;
234   }
235
236   if ( %%%RT_ENABLED%%% ) {
237     eval '
238       use lib ( "/opt/rt3/local/lib", "/opt/rt3/lib" );
239       use vars qw($Nobody $SystemUser);
240       use RT;
241       use RT::Tickets;
242       use RT::Transactions;
243       use RT::Users;
244       use RT::CurrentUser;
245       use RT::Templates;
246       use RT::Queues;
247       use RT::ScripActions;
248       use RT::ScripConditions;
249       use RT::Scrips;
250       use RT::Groups;
251       use RT::GroupMembers;
252       use RT::CustomFields;
253       use RT::CustomFieldValues;
254       use RT::ObjectCustomFieldValues;
255
256       #blah.  manually updated from RT::Interface::Web::Handler
257       use RT::Interface::Web;
258       use MIME::Entity;
259       use Text::Wrapper;
260       use Time::ParseDate;
261       use Time::HiRes;
262       use HTML::Scrubber;
263
264       #blah.  not even in RT::Interface::Web::Handler, just in 
265       #html/NoAuth/css/dhandler and rt-test-dependencies.  ask for it here
266       #to throw a real error instead of just a mysterious unstyled RT
267       use CSS::Squish 0.06;
268
269       use RT::Interface::Web::Request;
270
271       #slow, unreliable, segfaults and is optional
272       #see rt/html/Ticket/Elements/ShowTransactionAttachments
273       #use Text::Quoted;
274
275       #?#use File::Path qw( rmtree );
276       #?#use File::Glob qw( bsd_glob );
277       #?#use File::Spec::Unix;
278
279     ';
280     die $@ if $@;
281   }
282
283   *CGI::redirect = sub {
284     my $self = shift;
285     my $cookie = '';
286     if ( $_[0] eq '-cookie' ) { #this isn't actually used at the moment
287       (my $x, $cookie) = (shift, shift);
288       $HTML::Mason::r->err_headers_out->add( 'Set-cookie' => $cookie );
289     }
290     my $location = shift;
291
292     use vars qw($m);
293
294     # false laziness w/below
295     if ( defined(@DBIx::Profile::ISA) ) {
296
297       if ( $FS::CurrentUser::CurrentUser->option('show_db_profile') ) {
298
299         #profiling redirect
300
301         my $page =
302           qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
303           '<BR><BR><PRE>'.
304             ( UNIVERSAL::can(dbh, 'sprintProfile')
305                 ? encode_entities(dbh->sprintProfile())
306                 : 'DBIx::Profile missing sprintProfile method;'.
307                   'unpatched or too old?'                        ).
308           #"\n\n". &sprintAutoProfile().  '</PRE>'.
309           "\n\n".                         '</PRE>'.
310           '</BODY></HTML>';
311
312
313         dbh->{'private_profile'} = {};
314         return $page;
315
316       } else {
317
318         #clear db profile, but normal redirect
319         dbh->{'private_profile'} = {};
320         $m->redirect($location);
321         '';
322
323       }
324
325     } else { #normal redirect
326
327       $m->redirect($location);
328       '';
329
330     }
331
332   };
333   
334   sub include {
335     use vars qw($m);
336     $m->scomp(@_);
337   }
338
339   sub errorpage {
340     use vars qw($m);
341     $m->comp('/elements/errorpage.html', @_);
342   }
343
344   sub redirect {
345     my( $location ) = @_;
346     use vars qw($m);
347     $m->clear_buffer;
348     #false laziness w/above
349     if ( defined(@DBIx::Profile::ISA) ) {
350
351       if ( $FS::CurrentUser::CurrentUser->option('show_db_profile') ) {
352
353         #profiling redirect
354
355         $m->print(
356           qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
357           '<BR><BR><PRE>'.
358             ( UNIVERSAL::can(dbh, 'sprintProfile')
359                 ? encode_entities(dbh->sprintProfile())
360                 : 'DBIx::Profile missing sprintProfile method;'.
361                   'unpatched or too old?'                        ).
362           #"\n\n". &sprintAutoProfile().  '</PRE>'.
363           "\n\n".                         '</PRE>'.
364           '</BODY></HTML>'
365         );
366
367         dbh->{'private_profile'} = {};
368
369       } else {
370
371         #clear db profile, but normal redirect
372         dbh->{'private_profile'} = {};
373         $m->redirect($location);
374
375       }
376
377     } else { #normal redirect
378
379       $m->redirect($location);
380
381     }
382
383   }
384
385 } # end package HTML::Mason::Commands;
386
387 =head1 SUBROUTINE
388
389 =over 4
390
391 =item mason_interps [ MODE [ OPTION => VALUE ... ] ]
392
393 Returns a list consisting of two HTML::Mason::Interp objects, the first for
394 Freeside pages, and the second for RT pages.
395
396 MODE can be 'apache' or 'standalone'.  If not specified, defaults to 'apache'.
397
398 Options and values can be passed following mode.  Currently available options
399 are:
400
401 I<outbuf> should be set to a scalar reference in standalone mode.
402
403 =cut
404
405 sub mason_interps {
406   my $mode = shift || 'apache';
407   my %opt = @_;
408
409   #my $request_class = 'HTML::Mason::Request'.
410                       #( $mode eq 'apache' ? '::ApacheHandler' : '' );
411   my $request_class = 'FS::Mason::Request';
412
413   #not entirely sure it belongs here, but what the hey
414   if ( %%%RT_ENABLED%%% && $mode ne 'standalone' ) {
415     RT::LoadConfig();
416   }
417
418   # A hook supporting strange legacy ways people have added stuff on
419
420   my @addl_comp_root = ();
421   my $addl_comp_root_file = '%%%FREESIDE_CONF%%%/addl_comp_root.pl';
422   if ( -e $addl_comp_root_file ) {
423     warn "reading $addl_comp_root_file\n";
424     my $text = slurp( $addl_comp_root_file );
425     my @addl = eval $text;
426     if ( @addl && ! $@ ) {
427       @addl_comp_root = @addl;
428     } elsif ($@) {
429       warn "error parsing $addl_comp_root_file: $@\n";
430     }
431   }
432
433   my %interp = (
434     request_class        => $request_class,
435     data_dir             => '%%%MASONDATA%%%',
436     error_mode           => 'output',
437     error_format         => 'html',
438     ignore_warnings_expr => '.',
439     comp_root            => [
440                               [ 'freeside'=>'%%%FREESIDE_DOCUMENT_ROOT%%%'    ],
441                               [ 'rt'      =>'%%%FREESIDE_DOCUMENT_ROOT%%%/rt' ],
442                               @addl_comp_root,
443                             ],
444   );
445
446   $interp{out_method} = $opt{outbuf} if $mode eq 'standalone' && $opt{outbuf};
447
448   my $fs_interp = new HTML::Mason::Interp (
449     %interp,
450     escape_flags => { 'js_string' => sub {
451                         #${$_[0]} =~ s/(['\\\n])/'\\'.($1 eq "\n" ? 'n' : $1)/ge;
452                         ${$_[0]} =~ s/(['\\])/\\$1/g;
453                         ${$_[0]} =~ s/\n/\\n/g;
454                         ${$_[0]} = "'". ${$_[0]}. "'";
455                       }
456                     },
457     compiler     => HTML::Mason::Compiler::ToObject->new(
458                       allow_globals        => [qw(%session)],
459                     ),
460   );
461
462   my $rt_interp = new HTML::Mason::Interp (
463     %interp,
464     escape_flags => { 'h' => \&RT::Interface::Web::EscapeUTF8 },
465     compiler     => HTML::Mason::Compiler::ToObject->new(
466                       default_escape_flags => 'h',
467                       allow_globals        => [qw(%session)],
468                     ),
469   );
470
471   ( $fs_interp, $rt_interp );
472
473 }
474
475 =back
476
477 =head1 BUGS
478
479 Lurking in the darkness...
480
481 =head1 SEE ALSO
482
483 L<HTML::Mason>, L<FS>, L<RT>
484
485 =cut
486
487 1;