Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Fri, 28 Sep 2012 03:27:43 +0000 (20:27 -0700)
committerIvan Kohler <ivan@freeside.biz>
Fri, 28 Sep 2012 03:27:43 +0000 (20:27 -0700)
Conflicts:
FS/FS/cust_main/Billing.pm

62 files changed:
FS/FS/Misc.pm
FS/FS/TicketSystem/RT_Internal.pm
FS/FS/cust_main/Billing.pm
FS/FS/cust_pkg_discount.pm
FS/FS/discount.pm
FS/FS/part_event/Action/pkg_agent_credit.pm
FS/FS/part_export/freeswitch.pm
FS/FS/part_export/shellcommands.pm
FS/FS/rate.pm
FS/FS/svc_Tower_Mixin.pm
bin/231commit
bin/23diff
bin/cdr.import [changed mode: 0644->0755]
bin/cust_main-bill_now [changed mode: 0644->0755]
bin/pod2x
fs_selfservice/DEPLOY
fs_selfservice/FS-SelfService/cgi/agent.cgi [changed mode: 0644->0755]
fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi [changed mode: 0644->0755]
fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi [changed mode: 0644->0755]
httemplate/browse/cust_note_class.html
httemplate/docs/license.html
httemplate/edit/discount.html
httemplate/edit/process/cust_pkg_discount.html
httemplate/edit/process/quick-cust_pkg.cgi
httemplate/edit/process/svc_broadband.cgi
httemplate/elements/tr-select-discount.html
httemplate/view/cust_main/custom_content/.birthdate.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.small_custview.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.spouse_birthdate.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.svc_Common.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.svc_acct.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.svc_hardware.html.swp [deleted file]
httemplate/view/cust_main/custom_content/.svc_phone.html.swp [deleted file]
rt/sbin/rt-server.fcgi.in
rt/sbin/rt-server.in
rt/sbin/rt-test-dependencies.in
rt/share/html/Search/Results.xls
rt/t/api/config.t
rt/t/api/template-insert.t [deleted file]
rt/t/api/template-simple.t [deleted file]
rt/t/api/template.t
rt/t/articles/search-interface.t
rt/t/articles/uri-a.t
rt/t/data/configs/apache2.2+fastcgi.conf.in
rt/t/data/configs/apache2.2+mod_perl.conf.in
rt/t/mail/dashboard-chart-with-utf8.t
rt/t/mail/dashboards.t
rt/t/mail/gateway.t
rt/t/shredder/01ticket.t
rt/t/shredder/03plugin_tickets.t
rt/t/shredder/03plugin_users.t
rt/t/shredder/utils.pl
rt/t/ticket/search_by_watcher.t
rt/t/web/attachments.t
rt/t/web/command_line.t
rt/t/web/command_line_with_unknown_field.t
rt/t/web/crypt-gnupg.t
rt/t/web/googleish_search.t
rt/t/web/query_builder_queue_limits.t
rt/t/web/search_simple.t
rt/t/web/ticket_modify_all.t
rt/t/web/transaction_batch.t

index 2be9ec2..297e39f 100644 (file)
@@ -913,16 +913,6 @@ sub ocr_image {
   @lines;
 }
 
-=item spool_formats
-  
-Returns a list of the invoice spool formats.
-
-=cut
-
-sub spool_formats {
-  qw(default oneline billco bridgestone)
-}
-
 =back
 
 =head1 BUGS
index b09647e..01e2e29 100644 (file)
@@ -50,7 +50,7 @@ sub access_right {
 sub session {
   my( $self, $session ) = @_;
 
-  if ( $session && $session->{'Current_User'} ) { # does this even work?
+  if ( $session && $session->{'CurrentUser'} ) { # does this even work?
     warn "$me session: using existing session and CurrentUser: \n".
          Dumper($session->{'CurrentUser'})
       if $DEBUG;
index 02774c9..11247a2 100644 (file)
@@ -1255,6 +1255,8 @@ sub _handle_taxes {
 
       $taxhash{'taxclass'} = $part_pkg->taxclass;
 
+      warn "taxhash:\n". Dumper(\%taxhash) if $DEBUG > 2;
+
       my @taxes = (); # entries are cust_main_county objects
       my %taxhash_elim = %taxhash;
       my @elim = qw( district city county state );
index a207940..5f4d0dc 100644 (file)
@@ -106,7 +106,8 @@ sub insert {
       'amount'   => $self->amount,
       'percent'  => $self->percent,
       'months'   => $self->months,
-      'setup'   => $self->setup,
+      'setup'    => $self->setup,
+      #'linked'   => $self->linked,
       'disabled' => 'Y',
     };
     my $error = $discount->insert;
index 88cbdd4..f6f9945 100644 (file)
@@ -136,6 +136,7 @@ sub check {
     || $self->ut_floatn('months') #actually decimal, but this will do
     || $self->ut_enum('disabled', [ '', 'Y' ])
     || $self->ut_enum('setup', [ '', 'Y' ])
+    #|| $self->ut_enum('linked', [ '', 'Y' ])
   ;
   return $error if $error;
 
index 4bcee98..e1c77be 100644 (file)
@@ -18,7 +18,7 @@ sub do_action {
   my $agent_cust_main = $agent->agent_cust_main;
     #? or return "No customer record for agent ". $agent->agent;
 
-  my $amount    = $self->_calc_credit($cust_pkg);
+  my $amount = $self->_calc_credit($cust_pkg);
   return '' unless $amount > 0;
 
   my $reasonnum = $self->option('reasonnum');
@@ -29,6 +29,7 @@ sub do_action {
     'eventnum' => $cust_event->eventnum,
     'addlinfo' => 'for customer #'. $cust_main->display_custnum.
                                ': '.$cust_main->name,
+    #'commission_agentnum' => $agent->agentnum,
   );
   die "Error crediting customer ". $agent_cust_main->custnum.
       " for agent commission: $error"
index 7447849..eb490fd 100644 (file)
@@ -5,7 +5,8 @@ use vars qw( %info ); # $DEBUG );
 #use Data::Dumper;
 use Tie::IxHash;
 use Text::Template;
-#use FS::Record qw( qsearch qsearchs );
+use FS::Record qw( qsearch ); #qsearchs );
+use FS::svc_phone;
 #use FS::Schema qw( dbdef );
 
 #$DEBUG = 1;
@@ -15,7 +16,7 @@ tie my %options, 'Tie::IxHash',
   'directory' => { label   => 'Directory to store FreeSWITCH account XML files',
                    default => '/usr/local/freeswitch/conf/directory/',
                  },
-  'domain'    => { label => 'Optional fixed SIP domain to use, overrides svc_phone domain', },
+  #'domain'    => { label => 'Optional fixed SIP domain to use, overrides svc_phone domain', },
   'reload'    => { label   => 'Reload command',
                    default => '/usr/local/freeswitch/bin/fs_cli -x reloadxml',
                  },
@@ -38,9 +39,9 @@ END
   'desc'    => 'Provision phone services to FreeSWITCH XML configuration files',
   'options' => \%options,
   'notes'   => <<'END',
-Export XML account configuration files to FreeSWITCH, one per phone services.
+Export XML account configuration files to FreeSWITCH, one per domain.
 <br><br>
-You will need to
+You will need to enable the svc_phone-domain configuration setting and
 <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.9:Documentation:Administration:SSH_Keys">setup SSH for unattended operation</a>.
 END
 );
@@ -50,6 +51,33 @@ sub rebless { shift; }
 sub _export_insert {
   my( $self, $svc_phone ) = ( shift, shift );
 
+  $self->_export_rebuild_domain($svc_phone);
+
+}
+
+sub _export_replace {
+  my( $self, $new, $old ) = ( shift, shift, shift );
+
+  my $error = $self->_export_rebuild_domain($new);
+  return $error if $error;
+
+  if ( $new->domsvc ne $old->domsvc && $old->domsvc ) {
+    $error = $self->_export_rebuild_domain($old);
+    return $error if $error;
+  }
+
+  '';
+}
+
+sub _export_delete {
+  my( $self, $svc_phone ) = ( shift, shift );
+
+  $self->_export_rebuild_domain($svc_phone);
+}
+
+sub _export_rebuild_domain {
+  my($self, $svc_phone) = ( shift, shift );
+
   eval "use Net::SCP;";
   die $@ if $@;
 
@@ -57,24 +85,34 @@ sub _export_insert {
 
   my $tempdir = '%%%FREESIDE_CONF%%%/cache.'. $FS::UID::datasrc;
 
-  my $svcnum = $svc_phone->svcnum;
+  my $domain = $svc_phone->domain or return "domain required";
 
   my $fh = new File::Temp(
-    TEMPLATE => "$tempdir/freeswitch.$svcnum.XXXXXXXX",
+    TEMPLATE => "$tempdir/freeswitch.$domain.XXXXXXXX",
     DIR      => $dir,
     #UNLINK   => 0,
   );
 
-  print $fh $self->freeswitch_template_fillin( $svc_phone, 'user' )
-    or die "print to freeswitch template failed: $!";
-  close $fh;
+  print $fh qq(<domain name="$domain">\n);
+
+  my @dom_svc_phone = qsearch( 'svc_phone', { 'domsvc'=>$svc_phone->domsvc } );
+
+  foreach my $dom_svc_phone (@dom_svc_phone) {
+
+    print $fh $self->freeswitch_template_fillin( $dom_svc_phone, 'user' )
+      or die "print to freeswitch template failed: $!";
+
+  }
+
+  print $fh qq(</domain>\n);
+  $fh->flush;
 
   my $scp = new Net::SCP;
   my $user = $self->option('user')||'root';
   my $host = $self->machine;
   my $dir = $self->option('directory');
 
-  $scp->scp( $fh->filename, "$user\@$host:$dir/$svcnum.xml" )
+  $scp->scp( $fh->filename, "$user\@$host:$dir/$domain.xml" )
     or return $scp->{errstr};
 
   #signal freeswitch to reload config
@@ -84,27 +122,6 @@ sub _export_insert {
 
 }
 
-sub _export_replace {
-  my( $self, $new, $old ) = ( shift, shift, shift );
-
-  $self->_export_insert($new, @_);
-}
-
-sub _export_delete {
-  my( $self, $svc_phone ) = ( shift, shift );
-
-  my $dir  = $self->option('directory');
-  my $svcnum = $svc_phone->svcnum;
-
-  #delete file
-  $self->freeswitch_ssh( command => "rm $dir/$svcnum.xml" );
-
-  #signal freeswitch to reload config
-  $self->freeswitch_ssh( command => $self->option('reload') );
-
-  '';
-}
-
 sub freeswitch_template_fillin {
   my( $self, $svc_phone, $template ) = (shift, shift, shift);
 
@@ -117,13 +134,8 @@ sub freeswitch_template_fillin {
     DELIMITERS => [ '<%', '%>' ],
   );
 
-  my $domain =  $self->option('domain')
-             || $svc_phone->domain
-             || '$${sip_profile}';
-
   #false lazinessish w/phone_shellcommands::_export_command
   my %hash = (
-    'domain' => $domain,
     map { $_ => $svc_phone->getfield($_) } $svc_phone->fields
   );
 
index ca4e524..f964af3 100644 (file)
@@ -490,7 +490,7 @@ sub ssh_cmd { #subroutine, not method
   my ($output, $errput) = $ssh->capture2($ssh_opt, $opt->{'command'});
 
   return if $opt->{'ignore_all_errors'};
-  die "Error running SSH command: ". $ssh->error if $ssh->error;
+  #die "Error running SSH command: ". $ssh->error if $ssh->error;
 
   if ( ($output || $errput)
        && $opt->{'ignored_errors'} && length($opt->{'ignored_errors'})
@@ -504,7 +504,9 @@ sub ssh_cmd { #subroutine, not method
     $errput =~ s/[\s\n]//g;
   }
 
-  die "$errput\n" if $errput;
+  die (($errput || $ssh->error). "\n") if $errput || $ssh->error; 
+  #die "$errput\n" if $errput;
+
   die "$output\n" if $output and $opt->{'fail_on_output'};
   '';
 }
index 02d8250..a2511cf 100644 (file)
@@ -387,7 +387,7 @@ sub rate_detail {
 
 =item process
 
-Experimental job-queue processor for web interface adds/edits
+Job-queue processor for web interface adds/edits
 
 =cut
 
index 0b55884..6adbc6f 100644 (file)
@@ -52,5 +52,4 @@ sub tower_sector_sql {
   @where;
 }
 
-
 1;
index ca28ede..6d09863 100755 (executable)
@@ -20,8 +20,8 @@ die "no files!" unless @ARGV;
 system join('',
   "( cd /home/$USER/freeside2.3/$prefix; git pull ) && ",
   "( cd /home/$USER/freeside2.1/$prefix; git pull ) && ",
-  "git diff -u @ARGV | ( cd /home/$USER/freeside2.3/$prefix; patch ) ",
-  " && git diff -u @ARGV | ( cd /home/$USER/freeside2.1/$prefix; patch ) ",
+  "git diff -u @ARGV | ( cd /home/$USER/freeside2.3/$prefix; patch -p1 ) ",
+  " && git diff -u @ARGV | ( cd /home/$USER/freeside2.1/$prefix; patch -p1 ) ",
   " && ( ( git commit  -m $desc @ARGV && git push); ",
   "( cd /home/$USER/freeside2.3/$prefix; git commit -m $desc @ARGV && git push); ",
   "( cd /home/$USER/freeside2.1/$prefix; git commit -m $desc @ARGV && git push) )"
index 0c0575a..d38c848 100755 (executable)
@@ -3,7 +3,8 @@
 my $file = shift;
 
 chomp(my $dir = `pwd`);
-$dir =~ s/freeside\//freeside2.3\//;
+$dir =~ s/freeside(\/?)/freeside2.3$1/;
+warn $dir;
 
 #$cmd = "diff -u $file $dir/$file";
 $cmd = "diff -u $dir/$file $file";
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 17e48fb..f8a1580
@@ -13,7 +13,9 @@ my $custnum = shift or die &usage;
 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
   or die "unknown custnum $custnum\n";
 
-$cust_main->bill_and_collect( debug=>2, check_freq=>'1d' );
+$FS::cust_main::DEBUG = 3;
+
+$cust_main->bill_and_collect( debug=>3, check_freq=>'1d' );
 
 sub usage {
   die "Usage:\n  cust_main-bill_now user custnum\n";
index ecb7f91..1ec998f 100755 (executable)
--- a/bin/pod2x
+++ b/bin/pod2x
@@ -7,12 +7,15 @@ chomp( my $mw_password = `cat .mw-password` );
 
 my $site_perl = "./FS";
 #my $html = "Freeside:1.7:Documentation:Developer";
-my $html = "Freeside:1.9:Documentation:Developer";
+#my $html = "Freeside:1.9:Documentation:Developer";
+my $html = "Freeside:3:Documentation:Developer";
 
 foreach my $dir (
   $html,
-  map "$html/$_", qw( bin FS FS/UI FS/part_export FS/part_pkg
+  map "$html/$_", qw( bin FS
+                      FS/cdr FS/cust_main FS/cust_pkg FS/detail_format
                       FS/part_event FS/part_event/Condition FS/part_event/Action
+                      FS/part_export FS/part_pkg FS/pay_batch
                       FS/ClientAPI FS/Cron FS/Misc FS/Report FS/Report/Table
                       FS/TicketSystem FS/UI
                       FS/SelfService
@@ -43,6 +46,7 @@ foreach my $file (
 use WWW::Mediawiki::Client;
 my $mvs = WWW::Mediawiki::Client->new(
             'host'           => 'www.freeside.biz',
+            'protocol'       => 'https',
             'wiki_path'      => 'mediawiki/index.php',
             'username'       => $mw_username,
             'password'       => $mw_password,
index e73012f..bedb5ec 100755 (executable)
@@ -11,7 +11,7 @@ perl Makefile.PL && make && make install
 cd ..
 
 #( cd ..; make deploy; cd fs_selfservice )
-( cd ..; make clean; make install-perl-modules; /etc/init.d/freeside restart; cd fs_selfservice )
+( cd ..; make clean; make configure-rt; make install-perl-modules; /etc/init.d/freeside restart; cd fs_selfservice )
 
 #cp /home/ivan/freeside/fs_selfservice/FS-SelfService/cgi/* /var/www/MyAccount
 #chown freeside /var/www/MyAccount/*.cgi
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index f5d450b..7928199 100644 (file)
@@ -3,7 +3,7 @@
                  'html_init'   => $html_init,
                  'name'        => 'customer note classes',
                  'disableable' => 1,
-                 'disabled_statuspos' => 2,
+                 'disabled_statuspos' => 1,
                  'query'       => { 'table'     => 'cust_note_class',
                                     'hashref'   => {},
                                     'order_by' => 'ORDER BY classnum',
index fab8cd0..e40b243 100644 (file)
@@ -6,7 +6,7 @@
 
 <P>
 
-Copyright &copy; 2005-2009 Freeside Internet Services, Inc.<BR>
+Copyright &copy; 2005-2012 Freeside Internet Services, Inc.<BR>
 Copyright &copy; 2000-2005 Ivan Kohler<BR>
 Copyright &copy; 1999 Silicon Interactive Software Design<BR>
 All rights reserved<BR>
index b195eb3..9bcd1e7 100644 (file)
@@ -22,6 +22,7 @@
                                  postfix => '<BR><FONT SIZE="-1"><I>(blank for non-expiring discount)</I></FONT>',
                                },
                                { field => 'setup', type => 'checkbox', value=>'Y', },
+                               #{ field => 'linked', type => 'checkbox', value=>'Y', },
                              ],
                  'labels' => { 
                                'discountnum' => 'Discount #',
@@ -32,6 +33,7 @@
                                'percent'     => 'Percentage&nbsp;',
                                'months'      => 'Duration (months)',
                                'setup'       => 'Apply to setup fees',
+                               #'linked'      => 'Apply to add-on packages',
                              },
                  'viewall_dir' => 'browse',
                  'new_callback' => $new_callback,
@@ -114,6 +116,10 @@ my $javascript = <<END;
         document.getElementById('percent_label').style.visibility = 'hidden';
         document.getElementById('percent_input0').style.display = 'none';
         document.getElementById('percent_input0').style.visibility = 'hidden';
+//        document.getElementById('linked_label').style.display = 'none';
+//        document.getElementById('linked_label').style.visibility = 'hidden';
+//        document.getElementById('linked').style.display = 'none';
+//        document.getElementById('linked').style.visibility = 'hidden';
       } else if ( _type == 'Amount' ) {
         document.getElementById('amount_label').style.display = '';
         document.getElementById('amount_label').style.visibility = '';
@@ -123,6 +129,10 @@ my $javascript = <<END;
         document.getElementById('percent_label').style.visibility = 'hidden';
         document.getElementById('percent_input0').style.display = 'none';
         document.getElementById('percent_input0').style.visibility = 'hidden';
+//        document.getElementById('linked_label').style.display = 'none';
+//        document.getElementById('linked_label').style.visibility = 'hidden';
+//        document.getElementById('linked').style.display = 'none';
+//        document.getElementById('linked').style.visibility = 'hidden';
       } else if ( _type == 'Percentage' ) {
         document.getElementById('amount_label').style.display = 'none';
         document.getElementById('amount_label').style.visibility = 'hidden';
@@ -132,6 +142,10 @@ my $javascript = <<END;
         document.getElementById('percent_label').style.visibility = '';
         document.getElementById('percent_input0').style.display = '';
         document.getElementById('percent_input0').style.visibility = '';
+//        document.getElementById('linked_label').style.display = '';
+//        document.getElementById('linked_label').style.visibility = '';
+//        document.getElementById('linked').style.display = '';
+//        document.getElementById('linked').style.visibility = '';
      }
 
     }
index 6f97a79..4a71f69 100644 (file)
@@ -39,7 +39,8 @@ my $cust_pkg_discount = new FS::cust_pkg_discount {
   'amount'      => scalar($cgi->param('discountnum_amount')),
   'percent'     => scalar($cgi->param('discountnum_percent')),
   'months'      => scalar($cgi->param('discountnum_months')),
-  'setup'      => scalar($cgi->param('discountnum_setup')),
+  'setup'       => scalar($cgi->param('discountnum_setup')),
+  #'linked'       => scalar($cgi->param('discountnum_linked')),
   #'disabled'    => $self->discountnum_disabled,
 };
 my $error = $cust_pkg_discount->insert;
index ba4c5b1..c5eee0c 100644 (file)
@@ -2,19 +2,24 @@
 %  $cgi->param('error', $error);
 <% $cgi->redirect(popurl(3). 'misc/order_pkg.html?'. $cgi->query_string ) %>
 %} else {
-%  my $frag = "cust_pkg". $cust_pkg->pkgnum;
 %  my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/
 %               ? ''
 %               : ';show=packages';
-%  my $redir_url = popurl(3)
-%            ."view/cust_main.cgi?custnum=$custnum$show;fragment=$frag#$frag";
+%
+%  my $redir_url = popurl(3);
+%  if ( $svcpart ) { # for going straight to service provisining after ordering
+%    $redir_url .= 'edit/'.$part_svc->svcdb.'.cgi?'.
+%                    'pkgnum='.$cust_pkg->pkgnum. ";svcpart=$svcpart";
+%    $redir_url .= ";qualnum=$qualnum" if $qualnum;
+%  } elsif ( $quotationnum ) {
+%    $redir_url .= "view/quotation.html?quotationnum=$quotationnum";
+%  } else {
+%    my $custnum = $cust_main->custnum;
+%    my $frag = "cust_pkg". $cust_pkg->pkgnum;
+%    $redir_url .=
+%      "view/cust_main.cgi?custnum=$custnum$show;fragment=$frag#$frag";
+%  }
 % 
-% # for going right to a provision service after ordering a package
-% if ( $svcpart ) { 
-%   $redir_url = popurl(3)."edit/".$part_svc->svcdb.".cgi?".
-%                  "pkgnum=".$cust_pkg->pkgnum. ";svcpart=$svcpart";
-%   $redir_url .= ";qualnum=$qualnum" if $qualnum;
-% }
 <% header('Package ordered') %>
   <SCRIPT TYPE="text/javascript">
     // XXX fancy ajax rebuild table at some point, but a page reload will do for now
@@ -33,16 +38,27 @@ my $curuser = $FS::CurrentUser::CurrentUser;
 die "access denied"
   unless $curuser->access_right('Order customer package');
 
-#untaint custnum (probably not necessary, searching for it is escape enough)
-$cgi->param('custnum') =~ /^(\d+)$/
-  or die 'illegal custnum '. $cgi->param('custnum');
-my $custnum = $1;
-my $cust_main = qsearchs({
-  'table'     => 'cust_main',
-  'hashref'   => { 'custnum' => $custnum },
-  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
-});
-die 'unknown custnum' unless $cust_main;
+my $cust_main;
+if ( $cgi->param('custnum') =~ /^(\d+)$/ ) {
+  my $custnum = $1;
+  $cust_main = qsearchs({
+    'table'     => 'cust_main',
+    'hashref'   => { 'custnum' => $custnum },
+    'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+  });
+}
+
+my $prospect_main;
+if ( $cgi->param('prospectnum') =~ /^(\d+)$/ ) {
+  my $prospectnum = $1;
+  $prospect_main = qsearchs({
+    'table'     => 'prospect_main',
+    'hashref'   => { 'prospectnum' => $prospectnum },
+    'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+  });
+}
+
+die 'no custnum or prospectnum' unless $cust_main || $prospect_main;
 
 #probably not necessary, taken care of by cust_pkg::check
 $cgi->param('pkgpart') =~ /^(\d+)$/
@@ -72,47 +88,70 @@ if ( $cgi->param('svcpart') ) {
 }
 
 my $qualnum = '';
-if ( $cgi->param('qualnum') ) {
-  $cgi->param('qualnum') =~ /^(\d+)$/ or die 'illegal qualnum';
+if ( $cgi->param('qualnum') =~ /^(\d+)$/ ) {
   $qualnum = $1;
 }
+my $quotationnum = '';
+if ( $cgi->param('quotationnum') =~ /^(\d+)$/ ) {
+  $quotationnum = $1;
+}
+# verify this quotation is visible to this user
 
+my $cust_pkg = '';
+my $quotation_pkg = '';
+my $error = '';
 
-my $cust_pkg = new FS::cust_pkg {
-  'custnum'              => $custnum,
-  'pkgpart'              => $pkgpart,
-  'quantity'             => $quantity,
-  'start_date'           => ( scalar($cgi->param('start_date'))
-                                ? parse_datetime($cgi->param('start_date'))
-                                : ''
-                            ),
-  'no_auto'              => scalar($cgi->param('no_auto')),
-  'refnum'               => $refnum,
-  'locationnum'          => $locationnum,
-  'discountnum'          => $discountnum,
-  #for the create a new discount case
-  'discountnum__type'    => scalar($cgi->param('discountnum__type')),
-  'discountnum_amount'   => scalar($cgi->param('discountnum_amount')),
-  'discountnum_percent'  => scalar($cgi->param('discountnum_percent')),
-  'discountnum_months'   => scalar($cgi->param('discountnum_months')),
-  'discountnum_setup'    => scalar($cgi->param('discountnum_setup')),
-  'contract_end'         => ( scalar($cgi->param('contract_end'))
-                                ? parse_datetime($cgi->param('contract_end'))
-                                : ''
-                            ),
-   'waive_setup'         => ( $cgi->param('waive_setup') eq 'Y' ? 'Y' : '' ),
-};
-
-my %opt = ( 'cust_pkg' => $cust_pkg );
-
-if ( $locationnum == -1 ) {
-  my $cust_location = new FS::cust_location {
-    map { $_ => scalar($cgi->param($_)) }
-        qw( custnum address1 address2 city county state zip country geocode )
-  };
-  $opt{'cust_location'} = $cust_location;
-}
+my %hash = (
+    'pkgpart'              => $pkgpart,
+    'quantity'             => $quantity,
+    'start_date'           => ( scalar($cgi->param('start_date'))
+                                  ? parse_datetime($cgi->param('start_date'))
+                                  : ''
+                              ),
+    'refnum'               => $refnum,
+    'locationnum'          => $locationnum,
+    'discountnum'          => $discountnum,
+    #for the create a new discount case
+    'discountnum__type'    => scalar($cgi->param('discountnum__type')),
+    'discountnum_amount'   => scalar($cgi->param('discountnum_amount')),
+    'discountnum_percent'  => scalar($cgi->param('discountnum_percent')),
+    'discountnum_months'   => scalar($cgi->param('discountnum_months')),
+    'discountnum_setup'    => scalar($cgi->param('discountnum_setup')),
+    'contract_end'         => ( scalar($cgi->param('contract_end'))
+                                  ? parse_datetime($cgi->param('contract_end'))
+                                  : ''
+                              ),
+     'waive_setup'         => ( $cgi->param('waive_setup') eq 'Y' ? 'Y' : '' ),
+);
+$hash{'custnum'} = $cust_main->custnum if $cust_main;
+
+if ( $quotationnum ) {
+
+  $quotation_pkg = new FS::quotation_pkg \%hash;
+  $quotation_pkg->quotationnum($quotationnum);
+  $quotation_pkg->prospectnum($prospect_main->prospectnum) if $prospect_main;
 
-my $error = $cust_main->order_pkg( \%opt );
+  #XXX handle new location
+  $error = $quotation_pkg->insert;
+
+} else {
+
+  $cust_pkg = new FS::cust_pkg \%hash;
+
+  $cust_pkg->no_auto( scalar($cgi->param('no_auto')) );
+
+  my %opt = ( 'cust_pkg' => $cust_pkg );
+
+  if ( $locationnum == -1 ) {
+    my $cust_location = new FS::cust_location {
+      map { $_ => scalar($cgi->param($_)) }
+          qw( custnum address1 address2 city county state zip country geocode )
+    };
+    $opt{'cust_location'} = $cust_location;
+  }
+
+  $error = $cust_main->order_pkg( \%opt );
+
+}
 
 </%init>
index 90eab4a..25644e5 100644 (file)
@@ -1,11 +1,10 @@
 <& elements/svc_Common.html,
-  table       => 'svc_broadband',
-  fields      => [ fields('svc_broadband'), fields('nas'), 'usergroup' ],
+  table             => 'svc_broadband',
+  fields            => [ fields('svc_broadband'), fields('nas'), 'usergroup' ],
   precheck_callback => \&precheck,
 &>
 <%init>
-# for historical reasons, process_m2m for usergroup tables is done 
-# in the svc_x::insert/replace/delete methods, not here
+
 my $curuser = $FS::CurrentUser::CurrentUser;
 
 die "access denied"
index 30a60ec..ee86251 100644 (file)
@@ -6,7 +6,7 @@
 % } else { 
 
   <TR>
-    <TD ALIGN="right" WIDTH="176"><% $opt{'label'} || '<B>'.emt('Discount').'</B>' %></TD>
+    <TD ALIGN="right" WIDTH="275"><% $opt{'label'} || '<B>'.emt('Discount').'</B>' %></TD>
     <TD <% $colspan %>>
       <% include( '/elements/select-discount.html',
                     'curr_value' => $discountnum,
             )
   %>
 
+%#  <% include( '/elements/tr-checkbox.html',
+%#                'label'     => '<B>Apply discount to add-on packages</B>',
+%#                'field'     => $name.'_linked',
+%#                'id'        => $name.'_linked',
+%#                'curr_value' => scalar($cgi->param($name.'_linked')),
+%#                'value'     => 'Y',
+%#                'colspan'    => $opt{'colspan'},
+%#            )
+%#  %>
+
   <SCRIPT TYPE="text/javascript">
 
 %   my $ge = 'document.getElementById';
         <% $ge %>('<% $name %>_percent_label0').style.visibility = 'hidden';
         <% $ge %>('<% $name %>_percent_input0').style.display = 'none';
         <% $ge %>('<% $name %>_percent_input0').style.visibility = 'hidden';
+//        <% $ge %>('<% $name %>_linked_label0').style.display = 'none';
+//        <% $ge %>('<% $name %>_linked_label0').style.visibility = 'hidden';
+//        <% $ge %>('<% $name %>_linked').style.display = 'none';
+//        <% $ge %>('<% $name %>_linked').style.visibility = 'hidden';
       } else if ( <% $name %>__type == 'Amount' ) {
         <% $ge %>('<% $name %>_amount_label0').style.display = '';
         <% $ge %>('<% $name %>_amount_label0').style.visibility = '';
         <% $ge %>('<% $name %>_percent_label0').style.visibility = 'hidden';
         <% $ge %>('<% $name %>_percent_input0').style.display = 'none';
         <% $ge %>('<% $name %>_percent_input0').style.visibility = 'hidden';
+        <% $ge %>('<% $name %>_percent_input0').style.visibility = 'hidden';
+//        <% $ge %>('<% $name %>_linked_label0').style.display = 'none';
+//        <% $ge %>('<% $name %>_linked_label0').style.visibility = 'hidden';
+//        <% $ge %>('<% $name %>_linked').style.display = 'none';
+//        <% $ge %>('<% $name %>_linked').style.visibility = 'hidden';
       } else if ( <% $name %>__type == 'Percentage' ) {
         <% $ge %>('<% $name %>_amount_label0').style.display = 'none';
         <% $ge %>('<% $name %>_amount_label0').style.visibility = 'hidden';
         <% $ge %>('<% $name %>_percent_label0').style.visibility = '';
         <% $ge %>('<% $name %>_percent_input0').style.display = '';
         <% $ge %>('<% $name %>_percent_input0').style.visibility = '';
+        <% $ge %>('<% $name %>_percent_input0').style.visibility = '';
+//        <% $ge %>('<% $name %>_linked_label0').style.display = '';
+//        <% $ge %>('<% $name %>_linked_label0').style.visibility = '';
+//        <% $ge %>('<% $name %>_linked').style.display = '';
+//        <% $ge %>('<% $name %>_linked').style.visibility = '';
      }
 
     }
diff --git a/httemplate/view/cust_main/custom_content/.birthdate.html.swp b/httemplate/view/cust_main/custom_content/.birthdate.html.swp
deleted file mode 100644 (file)
index 9571d22..0000000
Binary files a/httemplate/view/cust_main/custom_content/.birthdate.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.small_custview.html.swp b/httemplate/view/cust_main/custom_content/.small_custview.html.swp
deleted file mode 100644 (file)
index a39f52d..0000000
Binary files a/httemplate/view/cust_main/custom_content/.small_custview.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.spouse_birthdate.html.swp b/httemplate/view/cust_main/custom_content/.spouse_birthdate.html.swp
deleted file mode 100644 (file)
index 0042012..0000000
Binary files a/httemplate/view/cust_main/custom_content/.spouse_birthdate.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.svc_Common.html.swp b/httemplate/view/cust_main/custom_content/.svc_Common.html.swp
deleted file mode 100644 (file)
index 15591b9..0000000
Binary files a/httemplate/view/cust_main/custom_content/.svc_Common.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.svc_acct.html.swp b/httemplate/view/cust_main/custom_content/.svc_acct.html.swp
deleted file mode 100644 (file)
index e2db6d5..0000000
Binary files a/httemplate/view/cust_main/custom_content/.svc_acct.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.svc_hardware.html.swp b/httemplate/view/cust_main/custom_content/.svc_hardware.html.swp
deleted file mode 100644 (file)
index 1106f9e..0000000
Binary files a/httemplate/view/cust_main/custom_content/.svc_hardware.html.swp and /dev/null differ
diff --git a/httemplate/view/cust_main/custom_content/.svc_phone.html.swp b/httemplate/view/cust_main/custom_content/.svc_phone.html.swp
deleted file mode 100644 (file)
index 79b8185..0000000
Binary files a/httemplate/view/cust_main/custom_content/.svc_phone.html.swp and /dev/null differ
index 45c3770..f84f6c1 100644 (file)
@@ -172,7 +172,7 @@ if (caller) {
 require Plack::Runner;
 
 my $is_fastcgi = $0 =~ m/fcgi$/;
-my $r = Plack::Runner->new( $0 =~ 'standalone' ? ( server => 'Standalone' ) :
+my $r = Plack::Runner->new( $0 =~ /standalone/ ? ( server => 'Standalone' ) :
                             $is_fastcgi        ? ( server => 'FCGI' )
                                                : (),
                             env => 'deployment' );
index 45c3770..f84f6c1 100644 (file)
@@ -172,7 +172,7 @@ if (caller) {
 require Plack::Runner;
 
 my $is_fastcgi = $0 =~ m/fcgi$/;
-my $r = Plack::Runner->new( $0 =~ 'standalone' ? ( server => 'Standalone' ) :
+my $r = Plack::Runner->new( $0 =~ /standalone/ ? ( server => 'Standalone' ) :
                             $is_fastcgi        ? ( server => 'FCGI' )
                                                : (),
                             env => 'deployment' );
index 37ef32f..960d640 100644 (file)
@@ -56,9 +56,10 @@ no warnings qw(numeric redefine);
 use Getopt::Long;
 my %args;
 my %deps;
+my @orig_argv = @ARGV;
 GetOptions(
     \%args,                               'v|verbose',
-    'install',                            'with-MYSQL',
+    'install!',                           'with-MYSQL',
     'with-POSTGRESQL|with-pg|with-pgsql', 'with-SQLITE',
     'with-ORACLE',                        'with-FASTCGI',
     'with-MODPERL1',                      'with-MODPERL2',
@@ -293,7 +294,7 @@ Test::LongString
 .
 
 $deps{'FASTCGI'} = [ text_to_hash( << '.') ];
-FCGI
+FCGI 0.74
 FCGI::ProcManager
 .
 
@@ -344,7 +345,7 @@ URI 1.59
 
 $deps{'GRAPHVIZ'} = [ text_to_hash( << '.') ];
 GraphViz
-IPC::Run
+IPC::Run 0.90
 .
 
 $deps{'GD'} = [ text_to_hash( << '.') ];
@@ -359,6 +360,7 @@ Convert::Color
 
 my %AVOID = (
     'DBD::Oracle' => [qw(1.23)],
+    'Email::Address' => [qw(1.893 1.894)],
 );
 
 if ($args{'download'}) {
@@ -403,7 +405,12 @@ foreach my $type (sort grep $args{$_}, keys %args) {
     $Missing_By_Type{$type} = \%missing if keys %missing;
 }
 
-conclude(%Missing_By_Type);
+if ( $args{'install'} && keys %Missing_By_Type ) {
+    exec($0, @orig_argv, '--no-install');
+}
+else {
+    conclude(%Missing_By_Type);
+}
 
 sub test_deps {
     my @deps = @_;
index 52a05da..8b94e22 100644 (file)
@@ -54,6 +54,7 @@ $Format => undef
 <%INIT>
 
 use Spreadsheet::WriteExcel;
+use OLE::Storage_Lite;
 use List::Util qw( max );
 use Date::Format qw( time2str );
 
index a986c3c..62b77df 100644 (file)
@@ -1,7 +1,8 @@
 use strict;
 use warnings;
 use RT;
-use RT::Test nodb => 1, tests => 9;
+use RT::Test nodb => 1, tests => 11;
+use Test::Warn;
 
 ok(
     RT::Config->AddOption(
@@ -31,3 +32,12 @@ is( $meta->{Widget}, '/Widgets/Form/Boolean', 'widget is updated to boolean' );
 ok( RT::Config->DeleteOption( Name => 'foo' ), 'removed option foo' );
 is( RT::Config->Meta('foo'), undef, 'foo is indeed deleted' );
 
+# Test EmailInputEncodings PostLoadCheck code
+RT::Config->Set('EmailInputEncodings', qw(utf-8 iso-8859-1 us-ascii foo));
+my @encodings = qw(utf-8-strict iso-8859-1 ascii);
+
+warning_is {RT::Config->PostLoadCheck} "Unknown encoding 'foo' in \@EmailInputEncodings option",
+  'Correct warning for encoding foo';
+
+my @canonical_encodings = RT::Config->Get('EmailInputEncodings');
+is_deeply(\@encodings, \@canonical_encodings, 'Got correct encoding list');
diff --git a/rt/t/api/template-insert.t b/rt/t/api/template-insert.t
deleted file mode 100644 (file)
index 1bf5fc3..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-
-
-use RT;
-use RT::Test tests => 7;
-
-
-
-# This tiny little test script triggers an interaction bug between DBD::Oracle 1.16, SB 1.15 and RT 3.4
-
-use_ok('RT::Template');
-my $template = RT::Template->new(RT->SystemUser);
-
-isa_ok($template, 'RT::Template');
-my ($val,$msg) = $template->Create(Queue => 1,
-                  Name => 'InsertTest',
-                  Content => 'This is template content');
-ok($val,$msg);
-is($template->Name, 'InsertTest');
-is($template->Content, 'This is template content', "We created the object right");
-($val, $msg) = $template->SetContent( 'This is new template content');
-ok($val,$msg);
-is($template->Content, 'This is new template content', "We managed to _Set_ the content");
diff --git a/rt/t/api/template-simple.t b/rt/t/api/template-simple.t
deleted file mode 100644 (file)
index bbdebb3..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-use strict;
-use warnings;
-use RT;
-use RT::Test tests => 231;
-use Test::Warn;
-
-my $queue = RT::Queue->new(RT->SystemUser);
-$queue->Load("General");
-
-my $ticket_cf = RT::CustomField->new(RT->SystemUser);
-$ticket_cf->Create(
-    Name        => 'Department',
-    Queue       => '0',
-    Type        => 'FreeformSingle',
-);
-
-my $txn_cf = RT::CustomField->new(RT->SystemUser);
-$txn_cf->Create(
-    Name        => 'Category',
-    LookupType  => RT::Transaction->CustomFieldLookupType,
-    Type        => 'FreeformSingle',
-);
-$txn_cf->AddToObject($queue);
-
-my $ticket = RT::Ticket->new(RT->SystemUser);
-my ($id, $msg) = $ticket->Create(
-    Subject   => "template testing",
-    Queue     => "General",
-    Owner     => 'root@localhost',
-    Requestor => ["dom\@example.com"],
-    "CustomField-" . $txn_cf->id => "Special",
-);
-ok($id, "Created ticket: $msg");
-my $txn = $ticket->Transactions->First;
-
-$ticket->AddCustomFieldValue(
-    Field => 'Department',
-    Value => 'Coolio',
-);
-
-TemplateTest(
-    Content      => "\ntest",
-    PerlOutput   => "test",
-    SimpleOutput => "test",
-);
-
-TemplateTest(
-    Content      => "\ntest { 5 * 5 }",
-    PerlOutput   => "test 25",
-    SimpleOutput => "test { 5 * 5 }",
-);
-
-TemplateTest(
-    Content      => "\ntest { \$Requestor }",
-    PerlOutput   => "test dom\@example.com",
-    SimpleOutput => "test dom\@example.com",
-);
-
-TemplateTest(
-    Content      => "\ntest { \$TicketSubject }",
-    PerlOutput   => "test ",
-    SimpleOutput => "test template testing",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketQueueId }",
-    Output  => "test 1",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketQueueName }",
-    Output  => "test General",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketOwnerId }",
-    Output  => "test 12",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketOwnerName }",
-    Output  => "test root",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketOwnerEmailAddress }",
-    Output  => "test root\@localhost",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketStatus }",
-    Output  => "test new",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest #{ \$TicketId }",
-    Output  => "test #" . $ticket->id,
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketCFDepartment }",
-    Output  => "test Coolio",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest #{ \$TransactionId }",
-    Output  => "test #" . $txn->id,
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TransactionType }",
-    Output  => "test Create",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TransactionCFCategory }",
-    Output  => "test Special",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$TicketDelete }",
-    Output  => "test { \$TicketDelete }",
-);
-
-SimpleTemplateTest(
-    Content => "\ntest { \$Nonexistent }",
-    Output  => "test { \$Nonexistent }",
-);
-
-warning_like {
-    TemplateTest(
-        Content      => "\ntest { \$Ticket->Nonexistent }",
-        PerlOutput   => undef,
-        SimpleOutput => "test { \$Ticket->Nonexistent }",
-    );
-} qr/RT::Ticket::Nonexistent Unimplemented/;
-
-warning_like {
-    TemplateTest(
-        Content      => "\ntest { \$Nonexistent->Nonexistent }",
-        PerlOutput   => undef,
-        SimpleOutput => "test { \$Nonexistent->Nonexistent }",
-    );
-} qr/Can't call method "Nonexistent" on an undefined value/;
-
-TemplateTest(
-    Content      => "\ntest { \$Ticket->OwnerObj->Name }",
-    PerlOutput   => "test root",
-    SimpleOutput => "test { \$Ticket->OwnerObj->Name }",
-);
-
-warning_like {
-    TemplateTest(
-        Content      => "\ntest { *!( }",
-        SyntaxError  => 1,
-        PerlOutput   => undef,
-        SimpleOutput => "test { *!( }",
-    );
-} qr/Template parsing error: syntax error/;
-
-TemplateTest(
-    Content      => "\ntest { \$rtname ",
-    SyntaxError  => 1,
-    PerlOutput   => undef,
-    SimpleOutput => undef,
-);
-
-is($ticket->Status, 'new', "test setup");
-SimpleTemplateTest(
-    Content => "\ntest { \$Ticket->SetStatus('resolved') }",
-    Output  => "test { \$Ticket->SetStatus('resolved') }",
-);
-is($ticket->Status, 'new', "simple templates can't call ->SetStatus");
-
-# Make sure changing the template's type works
-my $template = RT::Template->new(RT->SystemUser);
-$template->Create(
-    Name    => "type chameleon",
-    Type    => "Perl",
-    Content => "\ntest { 10 * 7 }",
-);
-ok($id = $template->id, "Created template");
-$template->Parse;
-is($template->MIMEObj->stringify_body, "test 70", "Perl output");
-
-$template = RT::Template->new(RT->SystemUser);
-$template->Load($id);
-is($template->Name, "type chameleon");
-
-$template->SetType('Simple');
-$template->Parse;
-is($template->MIMEObj->stringify_body, "test { 10 * 7 }", "Simple output");
-
-$template = RT::Template->new(RT->SystemUser);
-$template->Load($id);
-is($template->Name, "type chameleon");
-
-$template->SetType('Perl');
-$template->Parse;
-is($template->MIMEObj->stringify_body, "test 70", "Perl output");
-
-undef $ticket;
-
-my $counter = 0;
-sub IndividualTemplateTest {
-    local $Test::Builder::Level = $Test::Builder::Level + 1;
-
-    my %args = (
-        Name => "Test-" . ++$counter,
-        Type => "Perl",
-        @_,
-    );
-
-    my $t = RT::Template->new(RT->SystemUser);
-    $t->Create(
-        Name    => $args{Name},
-        Type    => $args{Type},
-        Content => $args{Content},
-    );
-
-    ok($t->id, "Created $args{Type} template");
-    is($t->Name, $args{Name}, "$args{Type} template name");
-    is($t->Content, $args{Content}, "$args{Type} content");
-    is($t->Type, $args{Type}, "template type");
-
-    # this should never blow up!
-    my ($ok, $msg) = $t->CompileCheck;
-
-    # we don't need to syntax check simple templates since if you mess them up
-    # it's safe to just use the input directly as the template's output
-    if ($args{SyntaxError} && $args{Type} eq 'Perl') {
-        ok(!$ok, "got a syntax error");
-    }
-    else {
-        ok($ok, $msg);
-    }
-
-    ($ok, $msg) = $t->Parse(
-        TicketObj      => $ticket,
-        TransactionObj => $txn,
-    );
-    if (defined $args{Output}) {
-        ok($ok, $msg);
-        is($t->MIMEObj->stringify_body, $args{Output}, "$args{Type} template's output");
-    }
-    else {
-        ok(!$ok, "expected a failure");
-    }
-}
-
-sub TemplateTest {
-    local $Test::Builder::Level = $Test::Builder::Level + 1;
-    my %args = @_;
-
-    for my $type ('Perl', 'Simple') {
-        next if $args{"Skip$type"};
-
-        IndividualTemplateTest(
-            %args,
-            Type   => $type,
-            Output => $args{$type . 'Output'},
-        );
-    }
-}
-
-sub SimpleTemplateTest {
-    local $Test::Builder::Level = $Test::Builder::Level + 1;
-    my %args = @_;
-
-    IndividualTemplateTest(
-        %args,
-        Type => 'Simple',
-    );
-}
-
index 2fadede..331d9f9 100644 (file)
@@ -1,25 +1,34 @@
 
-use strict;
 use warnings;
-use RT;
-use RT::Test tests => 2;
-
-
-{
-
-ok(require RT::Template);
+use strict;
 
+use RT;
+use RT::Test tests => 10;
 
-}
+my $queue = RT::Test->load_or_create_queue( Name => 'Templates' );
+ok $queue && $queue->id, "loaded or created a queue";
 
 {
-
-my $t = RT::Template->new(RT->SystemUser);
-$t->Create(Name => "Foo", Queue => 1);
-my $t2 = RT::Template->new(RT->Nobody);
-$t2->Load($t->Id);
-ok($t2->QueueObj->id, "Got the template's queue objet");
-
-
+    my $template = RT::Template->new( RT->SystemUser );
+    isa_ok($template, 'RT::Template');
+    my ($val,$msg) = $template->Create(
+        Queue => $queue->id,
+        Name => 'InsertTest',
+        Content => 'This is template content'
+    );
+    ok $val, "created a template" or diag "error: $msg";
+    ok my $id = $template->id, "id is defined";
+    is $template->Name, 'InsertTest';
+    is $template->Content, 'This is template content', "We created the object right";
+
+    ($val, $msg) = $template->SetContent( 'This is new template content');
+    ok $val, "changed content" or diag "error: $msg";
+
+    is $template->Content, 'This is new template content', "We managed to _Set_ the content";
+
+    ($val, $msg) = $template->Delete;
+    ok $val, "deleted template";
+
+    $template->Load($id);
+    ok !$template->id, "can not load template after deletion";
 }
-
index eb3a4f7..bcba311 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 23;
+use RT::Test tests => 44;
 
 use RT::CustomField;
 use RT::Queue;
@@ -67,7 +67,12 @@ my %cvals = ('article1q' => 'Some question about swallows',
                'article3q' => 'Why should I eat my supper?',
                'article3a' => 'There are starving children in Africa',
                'article4q' => 'What did Brian originally write?',
-               'article4a' => 'Romanes eunt domus');
+               'article4a' => 'This is an answer that is longer than 255 '
+            . 'characters so these tests will be sure to use the LargeContent '
+            . 'SQL as well as the normal SQL that would be generated if this '
+            . 'was an answer that was shorter than 255 characters. This second '
+            . 'sentence has a few extra characters to get this string to go '
+            . 'over the 255 character boundary. Lorem ipsum.');
 
 # Create an article or two with our custom field values.
 
@@ -108,6 +113,52 @@ isa_ok($m, 'Test::WWW::Mechanize');
 ok($m->login, 'logged in');
 $m->follow_link_ok( { text => 'Articles', url_regex => qr!^/Articles/! },
     'UI -> Articles' );
-$m->follow_link_ok( {text => 'Search'}, 'Articles -> Search');
-$m->follow_link_ok( {text => 'in class '.$class->Name}, 'Articles in class '.$class->Name);
-$m->content_contains($article1->Name);
+
+# In all of the search results below, the results page should
+# have the summary text of the article it occurs in.
+
+# Case sensitive search on small field.
+DoArticleSearch($m, $class->Name, 'Africa');
+$m->text_contains('Search results'); # Did we do a search?
+$m->text_contains('blah blah 1');
+
+# Case insensitive search on small field.
+DoArticleSearch($m, $class->Name, 'africa');
+$m->text_contains('Search results'); # Did we do a search?
+$m->text_contains('blah blah 1');
+
+# Case sensitive search on large field.
+DoArticleSearch($m, $class->Name, 'ipsum');
+$m->text_contains('Search results'); # Did we do a search?
+$m->text_contains('hoi polloi 4');
+
+# Case insensitive search on large field.
+DoArticleSearch($m, $class->Name, 'lorem');
+$m->text_contains('Search results'); # Did we do a search?
+TODO:{
+    local $TODO = 'Case insensitive search on LONGBLOB not available in MySQL'
+      if RT->Config->Get('DatabaseType') eq 'mysql';
+    $m->text_contains('hoi polloi 4');
+}
+
+# When you send $m to this sub, it must be on a page with
+# a Search link.
+sub DoArticleSearch{
+  my $m = shift;
+  my $class_name = shift;
+  my $search_text = shift;
+
+  $m->follow_link_ok( {text => 'Search'}, 'Articles -> Search');
+  $m->follow_link_ok( {text => 'in class '. $class_name}, 'Articles in class '. $class_name);
+  $m->text_contains('First article');
+
+  $m->submit_form_ok( {
+            form_number => 3,
+            fields      => {
+                'Article~' => $search_text
+            },
+        }, "Search for $search_text"
+    );
+  return;
+}
+
index 82d0f1b..5c1fdaf 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 7;
+use RT::Test tests => 15;
 
 use_ok("RT::URI::a");
 my $uri = RT::URI::a->new($RT::SystemUser);
@@ -26,3 +26,39 @@ is(ref($uri->Object), "RT::Article", "Object loaded is an article");
 is($uri->Object->Id, $article->Id, "Object loaded has correct ID");
 is($article->URI, 'fsck.com-article://example.com/article/'.$article->Id, 
    "URI object has correct URI string");
+
+{
+    my $aid = $article->id;
+    my $ticket = RT::Ticket->new( RT->SystemUser );
+    my ($id, $msg) = $ticket->Create(
+        Queue       => 1,
+        Subject     => 'test ticket',
+    );
+    ok $id, "Created a test ticket";
+
+    # Try searching
+    my $tickets = RT::Tickets->new( RT->SystemUser );
+    $tickets->FromSQL(" RefersTo = 'a:$aid' ");
+    is $tickets->Count, 0, "No results yet";
+
+    # try with the full uri
+    $tickets->FromSQL(" RefersTo = '@{[ $article->URI ]}' ");
+    is $tickets->Count, 0, "Still no results";
+
+    # add the link
+    $ticket->AddLink( Type => 'RefersTo', Target => "a:$aid" );
+
+    # verify the ticket has it
+    my @links = @{$ticket->RefersTo->ItemsArrayRef};
+    is scalar @links, 1, "Has one RefersTo link";
+    is ref $links[0]->TargetObj, "RT::Article", "Link points to an article";
+    is $links[0]->TargetObj->id, $aid, "Link points to the article we specified";
+
+    # search again
+    $tickets->FromSQL(" RefersTo = 'a:$aid' ");
+    is $tickets->Count, 1, "Found one ticket with short URI";
+
+    # search with the full uri
+    $tickets->FromSQL(" RefersTo = '@{[ $article->URI ]}' ");
+    is $tickets->Count, 1, "Found one ticket with full URI";
+}
index 3ec36dd..03eaa9a 100644 (file)
@@ -12,6 +12,7 @@ Group @WEB_GROUP@
 </IfModule>
 </IfModule>
 
+ServerName localhost
 Listen %%LISTEN%%
 
 ErrorLog "%%LOG_FILE%%"
index 3b1f3f6..20d2f44 100644 (file)
@@ -30,6 +30,7 @@ Group @WEB_GROUP@
 </IfModule>
 </IfModule>
 
+ServerName localhost
 Listen %%LISTEN%%
 
 ErrorLog "%%LOG_FILE%%"
index 6d07b96..79f5f0e 100644 (file)
@@ -1,7 +1,17 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 15;
+BEGIN {
+    require RT::Test;
+
+    if (eval { require GD }) {
+        RT::Test->import(tests => 15);
+    }
+    else {
+        RT::Test->import(skip_all => 'GD required.');
+    }
+}
+
 use utf8;
 
 my $root = RT::Test->load_or_create_user( Name => 'root' );
index 7a7a54c..00cfc6a 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 187;
+use RT::Test tests => 181;
 use Test::Warn;
 use RT::Dashboard::Mailer;
 
@@ -138,17 +138,6 @@ sub delete_dashboard { # {{{
     ok($ok, $msg);
 } # }}}
 
-sub delete_subscriptions { # {{{
-    my $subscription_id = shift;
-    # delete the dashboard and make sure we get exactly one subscription failure
-    # notice
-    my $user = RT::User->new(RT->SystemUser);
-    $user->Load('root');
-    for my $subscription ($user->Attributes->Named('Subscription')) {
-        $subscription->Delete;
-    }
-} # }}}
-
 my $good_time = 1290423660; # 6:01 EST on a monday
 my $bad_time  = 1290427260; # 7:01 EST on a monday
 
@@ -223,21 +212,9 @@ SKIP: {
 
 delete_dashboard($dashboard_id);
 
-warning_like {
-    RT::Dashboard::Mailer->MailDashboards(All => 1);
-} qr/Unable to load dashboard $dashboard_id of subscription $subscription_id for user root/;
-
-@mails = RT::Test->fetch_caught_mails;
-is(@mails, 1, "one mail for subscription failure");
-$mail = parse_mail($mails[0]);
-is($mail->head->get('Subject'), "[example.com] Missing dashboard!\n");
-is($mail->head->get('From'), "dashboard\@example.com\n");
-is($mail->head->get('X-RT-Dashboard-Id'), "$dashboard_id\n");
-is($mail->head->get('X-RT-Dashboard-Subscription-Id'), "$subscription_id\n");
-
 RT::Dashboard::Mailer->MailDashboards(All => 1);
 @mails = RT::Test->fetch_caught_mails;
-is(@mails, 0, "no mail because the subscription notice happens only once");
+is(@mails, 0, "no mail because the subscription is deleted");
 
 RT::Test->stop_server;
 RT::Test->clean_caught_mails;
@@ -277,7 +254,6 @@ RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
 ($baseurl, $m) = RT::Test->started_ok;
 
 delete_dashboard($dashboard_id);
-delete_subscriptions();
 
 RT::Test->clean_caught_mails;
 
@@ -330,7 +306,6 @@ RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
 ($baseurl, $m) = RT::Test->started_ok;
 
 delete_dashboard($dashboard_id);
-delete_subscriptions();
 
 RT::Test->clean_caught_mails;
 
@@ -373,7 +348,6 @@ RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
 ($baseurl, $m) = RT::Test->started_ok;
 
 delete_dashboard($dashboard_id);
-delete_subscriptions();
 
 RT::Test->clean_caught_mails;
 
index 9f0e669..98eabd5 100644 (file)
@@ -57,7 +57,7 @@ use strict;
 use warnings;
 
 
-use RT::Test config => 'Set( $UnsafeEmailCommands, 1);', tests => 221, actual_server => 1;
+use RT::Test config => 'Set( $UnsafeEmailCommands, 1);', tests => 228, actual_server => 1;
 my ($baseurl, $m) = RT::Test->started_ok;
 
 use RT::Tickets;
@@ -608,6 +608,35 @@ EOF
     $m->no_warnings_ok;
 }
 
+diag "make sure we check that UTF-8 is really UTF-8";
+{
+    my $text = <<EOF;
+From: root\@localhost
+To: rtemail\@@{[RT->Config->Get('rtname')]}
+Subject: This is test wrong utf-8 chars
+Content-Type: text/plain; charset="utf-8"
+
+utf-8: informaci\303\263n confidencial
+latin1: informaci\363n confidencial
+
+bye
+EOF
+    my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
+    is ($status >> 8, 0, "The mail gateway exited normally");
+    ok ($id, "created ticket");
+
+    my $tick = RT::Test->last_ticket;
+    is ($tick->Id, $id, "correct ticket");
+
+    my $content = $tick->Transactions->First->Content;
+    Encode::_utf8_off($content);
+
+    like $content, qr{informaci\303\263n confidencial};
+    like $content, qr{informaci\357\277\275n confidencial};
+
+    $m->no_warnings_ok;
+}
+
 diag "check that mailgate doesn't suffer from empty Reply-To:";
 {
     my $text = <<EOF;
index 7dff16d..a7abeef 100644 (file)
@@ -78,7 +78,11 @@ cmp_deeply( dump_current_and_savepoint('clean'), "current DB equal to savepoint"
     my $shredder = shredder_new();
     $shredder->PutObjects( Objects => $child );
     $shredder->WipeoutAll;
-    cmp_deeply( dump_current_and_savepoint('parent_ticket'), "current DB equal to savepoint");
+
+  TODO: {
+        local $TODO = "Shredder doesn't delete all links and transactions";
+        cmp_deeply( dump_current_and_savepoint('parent_ticket'), "current DB equal to savepoint");
+    }
 
     $shredder->PutObjects( Objects => $parent );
     $shredder->WipeoutAll;
index 092b570..e63eef8 100644 (file)
@@ -34,6 +34,7 @@ use_ok('RT::Tickets');
     my $child = RT::Ticket->new( RT->SystemUser );
     my ($cid) = $child->Create( Subject => 'child', Queue => 1, MemberOf => $pid );
     ok( $cid, "created new ticket" );
+    $_->ApplyTransactionBatch for $parent, $child;
 
     my $plugin = RT::Shredder::Plugin::Tickets->new;
     isa_ok($plugin, 'RT::Shredder::Plugin::Tickets');
@@ -77,6 +78,8 @@ cmp_deeply( dump_current_and_savepoint('clean'), "current DB equal to savepoint"
     my ($status, $msg) = $child->AddLink( Target => $pid, Type => 'DependsOn' );
     ok($status, "added reqursive link") or diag "error: $msg";
 
+    $_->ApplyTransactionBatch for $parent, $child;
+
     my $plugin = RT::Shredder::Plugin::Tickets->new;
     isa_ok($plugin, 'RT::Shredder::Plugin::Tickets');
 
@@ -121,6 +124,8 @@ cmp_deeply( dump_current_and_savepoint('clean'), "current DB equal to savepoint"
     ok( $cid2, "created new ticket" );
     $child2->SetStatus('resolved');
 
+    $_->ApplyTransactionBatch for $parent, $child1, $child2;
+
     my $plugin = RT::Shredder::Plugin::Tickets->new;
     isa_ok($plugin, 'RT::Shredder::Plugin::Tickets');
 
index 4f4ecc8..1f4cb49 100644 (file)
@@ -5,8 +5,8 @@ use warnings;
 
 use Test::Deep;
 use File::Spec;
-use Test::More tests => 9;
-use RT::Test nodb => 1;
+use Test::More tests => 21;
+use RT::Test ();
 BEGIN {
     my $shredder_utils = RT::Test::get_relocatable_file('utils.pl',
         File::Spec->curdir());
@@ -38,3 +38,61 @@ use_ok('RT::Shredder::Plugin::Users');
     ok(!$status, "bad 'status' arg value");
 }
 
+init_db();
+
+RT::Test->set_rights(
+    { Principal => 'Everyone', Right => [qw(CreateTicket)] },
+);
+
+create_savepoint('clean');
+
+{ # Create two users and a ticket. Shred second user and replace relations with first user
+    my ($uidA, $uidB, $msg);
+    my $userA = RT::User->new( RT->SystemUser );
+    ($uidA, $msg) = $userA->Create( Name => 'userA', Privileged => 1, Disabled => 0 );
+    ok( $uidA, "created user A" ) or diag "error: $msg";
+
+    my $userB = RT::User->new( RT->SystemUser );
+    ($uidB, $msg) = $userB->Create( Name => 'userB', Privileged => 1, Disabled => 0 );
+    ok( $uidB, "created user B" ) or diag "error: $msg";
+
+    my ($tid, $trid);
+    my $ticket = RT::Ticket->new( RT::CurrentUser->new($userB) );
+    ($tid, $trid, $msg) = $ticket->Create( Subject => 'UserB Ticket', Queue => 1 );
+    ok( $tid, "created new ticket") or diag "error: $msg";
+
+    my $transaction = RT::Transaction->new( RT->SystemUser );
+    $transaction->Load($trid);
+    is ( $transaction->Creator, $uidB, "ticket creator is user B" );
+
+    my $plugin = RT::Shredder::Plugin::Users->new;
+    isa_ok($plugin, 'RT::Shredder::Plugin::Users');
+
+    my $status;
+    ($status, $msg) = $plugin->TestArgs( status => 'any', name => 'userB', replace_relations => $uidA );
+    ok($status, "plugin arguments are ok") or diag "error: $msg";
+
+    my @objs;
+    ($status, @objs) = $plugin->Run;
+    ok($status, "executed plugin successfully") or diag "error: @objs";
+    @objs = RT::Shredder->CastObjectsToRecords( Objects => \@objs );
+    is(scalar @objs, 1, "one object in the result set");
+
+    my $shredder = shredder_new();
+
+    ($status, $msg) = $plugin->SetResolvers( Shredder => $shredder );
+    ok($status, "set conflicts resolver") or diag "error: $msg";
+
+    $shredder->PutObjects( Objects => \@objs );
+    $shredder->WipeoutAll;
+
+    $ticket->Load( $tid );
+    is($ticket->id, $tid, 'loaded ticket');
+
+    $transaction->Load($trid);
+    is ( $transaction->Creator, $uidA, "ticket creator is now user A" );
+
+    $shredder->Wipeout( Object => $ticket );
+    $shredder->Wipeout( Object => $userA );
+}
+cmp_deeply( dump_current_and_savepoint('clean'), "current DB equal to savepoint");
index 5f5c182..9b848c6 100644 (file)
@@ -283,7 +283,7 @@ sub dump_sqlite
     my $old_fhkn = $dbh->{'FetchHashKeyName'};
     $dbh->{'FetchHashKeyName'} = 'NAME_lc';
 
-    my $sth = $dbh->table_info( '', '', '%', 'TABLE' ) || die $DBI::err;
+    my $sth = $dbh->table_info( '', '%', '%', 'TABLE' ) || die $DBI::err;
     my @tables = keys %{$sth->fetchall_hashref( 'table_name' )};
 
     my $res = {};
index 809450b..cfc7b1c 100644 (file)
@@ -142,8 +142,8 @@ sub run_auto_tests {
 @conditions = (
     'Cc = "not@exist"'       => sub { 0 },
     'Cc != "not@exist"'      => sub { 1 },
-    'Cc IS NULL'             => sub { $_[0] =~ 'c:-;' },
-    'Cc IS NOT NULL'         => sub { $_[0] !~ 'c:-;' },
+    'Cc IS NULL'             => sub { $_[0] =~ /c:-;/ },
+    'Cc IS NOT NULL'         => sub { $_[0] !~ /c:-;/ },
     'Cc = "x@foo.com"'       => sub { $_[0] =~ /c:[^;]*x/ },
     'Cc != "x@foo.com"'      => sub { $_[0] !~ /c:[^;]*x/ },
     'Cc LIKE "@bar.com"'     => sub { $_[0] =~ /c:[^;]*(?:y|z)/ },
@@ -152,8 +152,8 @@ sub run_auto_tests {
 
     'Requestor = "not@exist"'   => sub { 0 },
     'Requestor != "not@exist"'  => sub { 1 },
-    'Requestor IS NULL'         => sub { $_[0] =~ 'r:-;' },
-    'Requestor IS NOT NULL'     => sub { $_[0] !~ 'r:-;' },
+    'Requestor IS NULL'         => sub { $_[0] =~ /r:-;/ },
+    'Requestor IS NOT NULL'     => sub { $_[0] !~ /r:-;/ },
     'Requestor = "x@foo.com"'   => sub { $_[0] =~ /r:[^;]*x/ },
     'Requestor != "x@foo.com"'  => sub { $_[0] !~ /r:[^;]*x/ },
     'Requestor LIKE "@bar.com"' => sub { $_[0] =~ /r:[^;]*(?:y|z)/ },
@@ -174,7 +174,7 @@ sub run_auto_tests {
     'Subject LIKE "ne"'      => sub { 0 },
     'Subject NOT LIKE "ne"'  => sub { 1 },
     'Subject = "r:x;c:y;"'   => sub { $_[0] eq 'r:x;c:y;' },
-    'Subject LIKE "x"'       => sub { $_[0] =~ 'x' },
+    'Subject LIKE "x"'       => sub { $_[0] =~ /x/ },
 );
 
 @tickets = generate_tix();
index 8c75f6c..784cbbe 100644 (file)
@@ -1,10 +1,11 @@
 #!/usr/bin/perl -w
 use strict;
 
-use RT::Test tests => 25;
+use RT::Test tests => 33;
 
 use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
 use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png';
+use constant TextFile => $RT::MasonComponentRoot .'/NoAuth/css/print.css';
 
 my ($baseurl, $m) = RT::Test->started_ok;
 ok $m->login, 'logged in';
@@ -30,9 +31,18 @@ $m->content_contains('Attachments test', 'we have subject on the page');
 $m->content_contains('Some content', 'and content');
 $m->content_contains('Download bpslogo.png', 'page has file name');
 
+open LOGO, "<", LogoFile or die "Can't open logo file: $!";
+binmode LOGO;
+my $logo_contents = do {local $/; <LOGO>};
+close LOGO;
+$m->follow_link_ok({text => "Download bpslogo.png"});
+is($m->content_type, "image/png");
+is($m->content, $logo_contents, "Binary content matches");
+
+$m->back;
 $m->follow_link_ok({text => 'Reply'}, "reply to the ticket");
 $m->form_name('TicketUpdate');
-$m->field('Attach',  LogoFile);
+$m->field('Attach',  TextFile);
 $m->click('AddMoreAttach');
 is($m->status, 200, "request successful");
 
@@ -44,7 +54,16 @@ is($m->status, 200, "request successful");
 
 $m->content_contains('Download bpslogo.png', 'page has file name');
 $m->content_contains('Download favicon.png', 'page has file name');
+$m->content_contains('Download print.css', 'page has file name');
+
+$m->follow_link_ok( { text => 'Download bpslogo.png' } );
+is( $m->response->header('Content-Type'), 'image/png', 'Content-Type of png lacks charset' );
+
+$m->back;
 
+$m->follow_link_ok( { text => 'Download print.css' } );
+is( $m->response->header('Content-Type'),
+    'text/css;charset=UTF-8', 'Content-Type of text has charset' );
 
 diag "test mobile ui";
 $m->get_ok( $baseurl . '/m/ticket/create?Queue=' . $qid );
index 1fed8e6..394daab 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use File::Spec ();
 use Test::Expect;
-use RT::Test tests => 303, actual_server => 1;
+use RT::Test tests => 315, actual_server => 1;
 my ($baseurl, $m) = RT::Test->started_ok;
 
 use RT::User;
@@ -480,6 +480,8 @@ expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in
         expect_like(qr/Created link $link1_id $reln $link2_id/, 'Linked');
         expect_send("show -s ticket/$link1_id/links", "Checking creation of $reln...");
         expect_like(qr/$display_relns{$reln}: [\w\d\.\-]+:\/\/[\w\d\.]+\/ticket\/$link2_id/, "Created link $reln");
+        expect_send("show ticket/$link1_id/links", "Checking show links without format");
+        expect_like(qr/$display_relns{$reln}: [\w\d\.\-]+:\/\/[\w\d\.]+\/ticket\/$link2_id/, "Found link $reln");
 
         # delete link
         expect_send("link -d $link1_id $reln $link2_id", "Delete $reln...");
index 736be4d..d63956b 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use File::Spec ();
 use Test::Expect;
-use RT::Test tests => 14, actual_server => 1;
+use RT::Test tests => 17, actual_server => 1;
 my ($baseurl, $m) = RT::Test->started_ok;
 my $rt_tool_path = "$RT::BinPath/rt";
 
@@ -19,6 +19,11 @@ expect_run(
     prompt => 'rt> ',
     quit => 'quit',
 );
+
+expect_send( q{create -t ticket set foo=bar}, "create ticket with unknown field" );
+expect_like(qr/foo: Unknown field/, 'foo is unknown field');
+expect_like(qr/Could not create ticket/, 'ticket is not created');
+
 expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket...");
 
 expect_like(qr/Ticket \d+ created/, "Created the ticket");
index 6bdefda..8c0eb57 100644 (file)
@@ -53,6 +53,7 @@ RT::Test->clean_caught_mails;
 
 $m->goto_create_ticket( $queue );
 $m->form_name('TicketCreate');
+$m->field('Requestors', 'recipient@example.com');
 $m->field('Subject', 'Encryption test');
 $m->field('Content', 'Some content');
 ok($m->value('Encrypt', 2), "encrypt tick box is checked");
@@ -122,6 +123,7 @@ RT::Test->clean_caught_mails;
 
 $m->goto_create_ticket( $queue );
 $m->form_name('TicketCreate');
+$m->field('Requestors', 'recipient@example.com');
 $m->field('Subject', 'Signing test');
 $m->field('Content', 'Some other content');
 ok(!$m->value('Encrypt', 2), "encrypt tick box is unchecked");
@@ -195,6 +197,7 @@ RT::Test->clean_caught_mails;
 
 $m->goto_create_ticket( $queue );
 $m->form_name('TicketCreate');
+$m->field('Requestors', 'recipient@example.com');
 $m->field('Subject', 'Crypt+Sign test');
 $m->field('Content', 'Some final? content');
 ok($m->value('Encrypt', 2), "encrypt tick box is checked");
@@ -260,6 +263,7 @@ RT::Test->clean_caught_mails;
 
 $m->goto_create_ticket( $queue );
 $m->form_name('TicketCreate');
+$m->field('Requestors', 'recipient@example.com');
 $m->field('Subject', 'Test crypt-off on encrypted queue');
 $m->field('Content', 'Thought you had me figured out didya');
 $m->field(Encrypt => undef, 2); # turn off encryption
index e2a4e91..f4c8fa4 100644 (file)
@@ -2,7 +2,8 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 96, config => 'Set( %FullTextSearch, Enable => 1, Indexed => 0 );';
+use RT::Test tests => undef,
+    config => 'Set( %FullTextSearch, Enable => 1, Indexed => 0 );';
 my ($baseurl, $m) = RT::Test->started_ok;
 my $url = $m->rt_base_url;
 
@@ -57,6 +58,7 @@ ok $two_words_queue && $two_words_queue->id, 'loaded or created a queue';
     is $parser->QueryToSQL("'me'"), "$active AND ( Subject LIKE 'me' )", "correct parsing";
     is $parser->QueryToSQL("owner:me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
     is $parser->QueryToSQL("owner:'me'"), "( Owner = 'me' ) AND $active", "correct parsing";
+    is $parser->QueryToSQL('owner:root@localhost'), "( Owner.EmailAddress = 'root\@localhost' ) AND $active", "Email address as owner";
 
     is $parser->QueryToSQL("resolved me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' )", "correct parsing";
     is $parser->QueryToSQL("resolved active me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' OR Status = 'new' OR Status = 'open' OR Status = 'stalled' )", "correct parsing";
@@ -217,3 +219,5 @@ for my $quote ( q{'}, q{"} ) {
     }
 }
 
+undef $m;
+done_testing;
index a3b9765..f583d64 100644 (file)
@@ -11,6 +11,9 @@ $lifecycles->{foo} = {
 
 };
 
+# explicitly Set so RT::Test can catch our change
+RT->Config->Set( Lifecycles => %$lifecycles );
+
 RT::Lifecycle->FillCache();
 
 my $general = RT::Test->load_or_create_queue( Name => 'General' );
index 1efc9a5..a1a3ce8 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 16;
+use RT::Test tests => 30;
 my ( $baseurl, $m ) = RT::Test->started_ok;
 
 RT::Test->create_tickets(
@@ -19,4 +19,58 @@ $m->content_contains( 'Show Results',   "has page menu" );
 $m->title_is( 'Found 1 ticket', 'title' );
 $m->content_contains( 'ticket foo', 'has ticket foo' );
 
+# Test searches on custom fields
+my $cf1 = RT::Test->load_or_create_custom_field(
+                      Name  => 'Location',
+                      Queue => 'General',
+                      Type  => 'FreeformSingle', );
+isa_ok( $cf1, 'RT::CustomField' );
+
+my $cf2 = RT::Test->load_or_create_custom_field(
+                      Name  => 'Server-name',
+                      Queue => 'General',
+                      Type  => 'FreeformSingle', );
+isa_ok( $cf2, 'RT::CustomField' );
+
+my $t = RT::Ticket->new(RT->SystemUser);
+
+{
+  my ($id,undef,$msg) = $t->Create(
+            Queue => 'General',
+            Subject => 'Test searching CFs');
+  ok( $id, "Created ticket - $msg" );
+}
+
+{
+  my ($status, $msg) = $t->AddCustomFieldValue(
+                           Field => $cf1->id,
+                          Value => 'Downtown');
+  ok( $status, "Added CF value - $msg" );
+}
+
+{
+  my ($status, $msg) = $t->AddCustomFieldValue(
+                           Field => $cf2->id,
+                          Value => 'Proxy');
+  ok( $status, "Added CF value - $msg" );
+}
+
+# Regular search
+my $search = 'cf.Location:Downtown';
+$m->get_ok("/Search/Simple.html?q=$search");
+$m->title_is( 'Found 1 ticket', 'Found 1 ticket' );
+$m->text_contains( 'Test searching CFs', "Found test CF ticket with $search" );
+
+# Case insensitive
+$search = "cf.Location:downtown";
+$m->get_ok("/Search/Simple.html?q=$search");
+$m->title_is( 'Found 1 ticket', 'Found 1 ticket' );
+$m->text_contains( 'Test searching CFs', "Found test CF ticket with $search" );
+
+# With dash in CF name
+$search = "cf.Server-name:Proxy";
+$m->get_ok("/Search/Simple.html?q=$search");
+$m->title_is( 'Found 1 ticket', 'Found 1 ticket' );
+$m->text_contains( 'Test searching CFs', "Found test CF ticket with $search" );
+
 # TODO more simple search tests
index c9dd7e7..2f0c4d1 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 15;
+use RT::Test tests => 22;
 
 my $ticket = RT::Test->create_ticket(
     Subject => 'test bulk update',
@@ -40,5 +40,44 @@ $m->click('SubmitTicket');
 $m->form_name('TicketModifyAll');
 is($m->value('Owner'), 'root', 'owner was successfully changed to root');
 
-# XXX TODO test other parts, i.e. basic, dates, people and links
+$m->get_ok($url . "/Ticket/ModifyAll.html?id=" . $ticket->id);
 
+$m->form_name('TicketModifyAll');
+$m->field('Starts_Date' => "2013-01-01 00:00:00");
+$m->click('SubmitTicket');
+$m->text_contains("Starts: (Tue Jan 01 00:00:00 2013)", 'start date successfully updated');
+
+$m->form_name('TicketModifyAll');
+$m->field('Started_Date' => "2014-01-01 00:00:00");
+$m->click('SubmitTicket');
+$m->text_contains("Started: (Wed Jan 01 00:00:00 2014)", 'started date successfully updated');
+
+$m->form_name('TicketModifyAll');
+$m->field('Told_Date' => "2015-01-01 00:00:00");
+$m->click('SubmitTicket');
+$m->text_contains("Last Contact:  (Thu Jan 01 00:00:00 2015)", 'told date successfully updated');
+
+$m->form_name('TicketModifyAll');
+$m->field('Due_Date' => "2016-01-01 00:00:00");
+$m->click('SubmitTicket');
+$m->text_contains("Due: (Fri Jan 01 00:00:00 2016)", 'due date successfully updated');
+
+$m->get( $url . '/Ticket/ModifyAll.html?id=' . $ticket->id );
+$m->form_name('TicketModifyAll');
+$m->field(WatcherTypeEmail => 'Requestor');
+$m->field(WatcherAddressEmail => 'root@localhost');
+$m->click('SubmitTicket');
+$m->text_contains(
+    "Added principal as a Requestor for this ticket",
+    'watcher is added',
+);
+$m->form_name('TicketModifyAll');
+$m->field(WatcherTypeEmail => 'Requestor');
+$m->field(WatcherAddressEmail => 'root@localhost');
+$m->click('SubmitTicket');
+$m->text_contains(
+    "That principal is already a Requestor for this ticket",
+    'no duplicate watchers',
+);
+
+# XXX TODO test other parts, i.e. links
index ae04e1f..12d01fb 100644 (file)
@@ -12,7 +12,14 @@ my ($val, $msg) =$s1->Create( Queue => $q->Id,
              ScripAction       => 'User Defined',
              CustomIsApplicableCode => 'return ($self->TransactionObj->Field||"") eq "TimeEstimated"',
              CustomPrepareCode => 'return 1',
-             CustomCommitCode  => '$self->TicketObj->SetPriority($self->TicketObj->Priority + 2); return 1;',
+             CustomCommitCode  => '
+if ( $self->TicketObj->CurrentUser->Name ne "RT_System" ) { 
+    warn "Ticket obj has incorrect CurrentUser (should be RT_System) ".$self->TicketObj->CurrentUser->Name
+}
+if ( $self->TicketObj->QueueObj->CurrentUser->Name ne "RT_System" ) { 
+    warn "Queue obj has incorrect CurrentUser (should be RT_System) ".$self->TicketObj->QueueObj->CurrentUser->Name
+}
+$self->TicketObj->SetPriority($self->TicketObj->Priority + 2); return 1;',
              Template          => 'Blank',
              Stage             => 'TransactionBatch',
     );