grandstream device configuration support #4220
[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::export_device;
178   use FS::msgcat;
179   use FS::rate;
180   use FS::rate_region;
181   use FS::rate_prefix;
182   use FS::rate_detail;
183   use FS::usage_class;
184   use FS::payment_gateway;
185   use FS::agent_payment_gateway;
186   use FS::XMLRPC;
187   use FS::payby;
188   use FS::cdr;
189   use FS::cdr_batch;
190   use FS::inventory_class;
191   use FS::inventory_item;
192   use FS::pkg_category;
193   use FS::pkg_class;
194   use FS::access_user;
195   use FS::access_user_pref;
196   use FS::access_group;
197   use FS::access_usergroup;
198   use FS::access_groupagent;
199   use FS::access_right;
200   use FS::AccessRight;
201   use FS::svc_phone;
202   use FS::phone_device;
203   use FS::part_device;
204   use FS::reason_type;
205   use FS::reason;
206   use FS::cust_main_note;
207   use FS::tax_class;
208   use FS::cust_tax_location;
209   use FS::part_pkg_taxproduct;
210   use FS::part_pkg_taxoverride;
211   use FS::part_pkg_taxrate;
212   use FS::tax_rate;
213   use FS::part_pkg_report_option;
214   use FS::cust_attachment;
215   use FS::h_cust_pkg;
216   use FS::h_svc_acct;
217   use FS::h_svc_broadband;
218   use FS::h_svc_domain;
219   #use FS::h_domain_record;
220   use FS::h_svc_external;
221   use FS::h_svc_forward;
222   use FS::h_svc_phone;
223   #use FS::h_phone_device;
224   use FS::h_svc_www;
225   use FS::cust_statement;
226   use FS::cust_class;
227   use FS::cust_category;
228   use FS::prospect_main;
229   use FS::contact;
230   use FS::svc_pbx;
231   use FS::discount;
232   use FS::cust_pkg_discount;
233   use FS::cust_bill_pkg_discount;
234   # Sammath Naur
235
236   if ( $FS::Mason::addl_handler_use ) {
237     eval $FS::Mason::addl_handler_use;
238     die $@ if $@;
239   }
240
241   if ( %%%RT_ENABLED%%% ) {
242     eval '
243       use lib ( "/opt/rt3/local/lib", "/opt/rt3/lib" );
244       use vars qw($Nobody $SystemUser);
245       use RT;
246       use RT::Tickets;
247       use RT::Transactions;
248       use RT::Users;
249       use RT::CurrentUser;
250       use RT::Templates;
251       use RT::Queues;
252       use RT::ScripActions;
253       use RT::ScripConditions;
254       use RT::Scrips;
255       use RT::Groups;
256       use RT::GroupMembers;
257       use RT::CustomFields;
258       use RT::CustomFieldValues;
259       use RT::ObjectCustomFieldValues;
260
261       #blah.  manually updated from RT::Interface::Web::Handler
262       use RT::Interface::Web;
263       use MIME::Entity;
264       use Text::Wrapper;
265       use Time::ParseDate;
266       use Time::HiRes;
267       use HTML::Scrubber;
268
269       #blah.  not even in RT::Interface::Web::Handler, just in 
270       #html/NoAuth/css/dhandler and rt-test-dependencies.  ask for it here
271       #to throw a real error instead of just a mysterious unstyled RT
272       use CSS::Squish 0.06;
273
274       use RT::Interface::Web::Request;
275
276       #slow, unreliable, segfaults and is optional
277       #see rt/html/Ticket/Elements/ShowTransactionAttachments
278       #use Text::Quoted;
279
280       #?#use File::Path qw( rmtree );
281       #?#use File::Glob qw( bsd_glob );
282       #?#use File::Spec::Unix;
283
284     ';
285     die $@ if $@;
286   }
287
288   *CGI::redirect = sub {
289     my $self = shift;
290     my $cookie = '';
291     if ( $_[0] eq '-cookie' ) { #this isn't actually used at the moment
292       (my $x, $cookie) = (shift, shift);
293       $HTML::Mason::r->err_headers_out->add( 'Set-cookie' => $cookie );
294     }
295     my $location = shift;
296
297     use vars qw($m);
298
299     # false laziness w/below
300     if ( defined(@DBIx::Profile::ISA) ) {
301
302       if ( $FS::CurrentUser::CurrentUser->option('show_db_profile') ) {
303
304         #profiling redirect
305
306         my $page =
307           qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
308           '<BR><BR><PRE>'.
309             ( UNIVERSAL::can(dbh, 'sprintProfile')
310                 ? encode_entities(dbh->sprintProfile())
311                 : 'DBIx::Profile missing sprintProfile method;'.
312                   'unpatched or too old?'                        ).
313           #"\n\n". &sprintAutoProfile().  '</PRE>'.
314           "\n\n".                         '</PRE>'.
315           '</BODY></HTML>';
316
317
318         dbh->{'private_profile'} = {};
319         return $page;
320
321       } else {
322
323         #clear db profile, but normal redirect
324         dbh->{'private_profile'} = {};
325         $m->redirect($location);
326         '';
327
328       }
329
330     } else { #normal redirect
331
332       $m->redirect($location);
333       '';
334
335     }
336
337   };
338   
339   sub include {
340     use vars qw($m);
341     $m->scomp(@_);
342   }
343
344   sub errorpage {
345     use vars qw($m);
346     $m->comp('/elements/errorpage.html', @_);
347   }
348
349   sub redirect {
350     my( $location ) = @_;
351     use vars qw($m);
352     $m->clear_buffer;
353     #false laziness w/above
354     if ( defined(@DBIx::Profile::ISA) ) {
355
356       if ( $FS::CurrentUser::CurrentUser->option('show_db_profile') ) {
357
358         #profiling redirect
359
360         $m->print(
361           qq!<HTML><BODY>Redirect to <A HREF="$location">$location</A>!.
362           '<BR><BR><PRE>'.
363             ( UNIVERSAL::can(dbh, 'sprintProfile')
364                 ? encode_entities(dbh->sprintProfile())
365                 : 'DBIx::Profile missing sprintProfile method;'.
366                   'unpatched or too old?'                        ).
367           #"\n\n". &sprintAutoProfile().  '</PRE>'.
368           "\n\n".                         '</PRE>'.
369           '</BODY></HTML>'
370         );
371
372         dbh->{'private_profile'} = {};
373
374       } else {
375
376         #clear db profile, but normal redirect
377         dbh->{'private_profile'} = {};
378         $m->redirect($location);
379
380       }
381
382     } else { #normal redirect
383
384       $m->redirect($location);
385
386     }
387
388   }
389
390 } # end package HTML::Mason::Commands;
391
392 =head1 SUBROUTINE
393
394 =over 4
395
396 =item mason_interps [ MODE [ OPTION => VALUE ... ] ]
397
398 Returns a list consisting of two HTML::Mason::Interp objects, the first for
399 Freeside pages, and the second for RT pages.
400
401 MODE can be 'apache' or 'standalone'.  If not specified, defaults to 'apache'.
402
403 Options and values can be passed following mode.  Currently available options
404 are:
405
406 I<outbuf> should be set to a scalar reference in standalone mode.
407
408 =cut
409
410 sub mason_interps {
411   my $mode = shift || 'apache';
412   my %opt = @_;
413
414   #my $request_class = 'HTML::Mason::Request'.
415                       #( $mode eq 'apache' ? '::ApacheHandler' : '' );
416   my $request_class = 'FS::Mason::Request';
417
418   #not entirely sure it belongs here, but what the hey
419   if ( %%%RT_ENABLED%%% && $mode ne 'standalone' ) {
420     RT::LoadConfig();
421   }
422
423   # A hook supporting strange legacy ways people have added stuff on
424
425   my @addl_comp_root = ();
426   my $addl_comp_root_file = '%%%FREESIDE_CONF%%%/addl_comp_root.pl';
427   if ( -e $addl_comp_root_file ) {
428     warn "reading $addl_comp_root_file\n";
429     my $text = slurp( $addl_comp_root_file );
430     my @addl = eval $text;
431     if ( @addl && ! $@ ) {
432       @addl_comp_root = @addl;
433     } elsif ($@) {
434       warn "error parsing $addl_comp_root_file: $@\n";
435     }
436   }
437
438   my %interp = (
439     request_class        => $request_class,
440     data_dir             => '%%%MASONDATA%%%',
441     error_mode           => 'output',
442     error_format         => 'html',
443     ignore_warnings_expr => '.',
444     comp_root            => [
445                               [ 'freeside'=>'%%%FREESIDE_DOCUMENT_ROOT%%%'    ],
446                               [ 'rt'      =>'%%%FREESIDE_DOCUMENT_ROOT%%%/rt' ],
447                               @addl_comp_root,
448                             ],
449   );
450
451   $interp{out_method} = $opt{outbuf} if $mode eq 'standalone' && $opt{outbuf};
452
453   my $fs_interp = new HTML::Mason::Interp (
454     %interp,
455     escape_flags => { 'js_string' => sub {
456                         #${$_[0]} =~ s/(['\\\n])/'\\'.($1 eq "\n" ? 'n' : $1)/ge;
457                         ${$_[0]} =~ s/(['\\])/\\$1/g;
458                         ${$_[0]} =~ s/\n/\\n/g;
459                         ${$_[0]} = "'". ${$_[0]}. "'";
460                       }
461                     },
462     compiler     => HTML::Mason::Compiler::ToObject->new(
463                       allow_globals        => [qw(%session)],
464                     ),
465   );
466
467   my $rt_interp = new HTML::Mason::Interp (
468     %interp,
469     escape_flags => { 'h' => \&RT::Interface::Web::EscapeUTF8 },
470     compiler     => HTML::Mason::Compiler::ToObject->new(
471                       default_escape_flags => 'h',
472                       allow_globals        => [qw(%session)],
473                     ),
474   );
475
476   ( $fs_interp, $rt_interp );
477
478 }
479
480 =back
481
482 =head1 BUGS
483
484 Lurking in the darkness...
485
486 =head1 SEE ALSO
487
488 L<HTML::Mason>, L<FS>, L<RT>
489
490 =cut
491
492 1;