@lines;
}
-=item spool_formats
-
-Returns a list of the invoice spool formats.
-
-=cut
-
-sub spool_formats {
- qw(default oneline billco bridgestone)
-}
-
=back
=head1 BUGS
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;
$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 );
'amount' => $self->amount,
'percent' => $self->percent,
'months' => $self->months,
- 'setup' => $self->setup,
+ 'setup' => $self->setup,
+ #'linked' => $self->linked,
'disabled' => 'Y',
};
my $error = $discount->insert;
|| $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;
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');
'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"
#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;
'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',
},
'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
);
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 $@;
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
}
-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);
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
);
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'})
$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'};
'';
}
=item process
-Experimental job-queue processor for web interface adds/edits
+Job-queue processor for web interface adds/edits
=cut
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) )"
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";
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";
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
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,
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
'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',
<P>
-Copyright © 2005-2009 Freeside Internet Services, Inc.<BR>
+Copyright © 2005-2012 Freeside Internet Services, Inc.<BR>
Copyright © 2000-2005 Ivan Kohler<BR>
Copyright © 1999 Silicon Interactive Software Design<BR>
All rights reserved<BR>
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 #',
'percent' => 'Percentage ',
'months' => 'Duration (months)',
'setup' => 'Apply to setup fees',
+ #'linked' => 'Apply to add-on packages',
},
'viewall_dir' => 'browse',
'new_callback' => $new_callback,
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 = '';
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';
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 = '';
}
}
'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;
% $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
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+)$/
}
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>
<& 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"
% } 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 = '';
}
}
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' );
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' );
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',
.
$deps{'FASTCGI'} = [ text_to_hash( << '.') ];
-FCGI
+FCGI 0.74
FCGI::ProcManager
.
$deps{'GRAPHVIZ'} = [ text_to_hash( << '.') ];
GraphViz
-IPC::Run
+IPC::Run 0.90
.
$deps{'GD'} = [ text_to_hash( << '.') ];
my %AVOID = (
'DBD::Oracle' => [qw(1.23)],
+ 'Email::Address' => [qw(1.893 1.894)],
);
if ($args{'download'}) {
$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 = @_;
<%INIT>
use Spreadsheet::WriteExcel;
+use OLE::Storage_Lite;
use List::Util qw( max );
use Date::Format qw( time2str );
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(
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');
+++ /dev/null
-#!/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");
+++ /dev/null
-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',
- );
-}
-
-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";
}
-
use strict;
use warnings;
-use RT::Test tests => 23;
+use RT::Test tests => 44;
use RT::CustomField;
use RT::Queue;
'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.
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;
+}
+
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);
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";
+}
</IfModule>
</IfModule>
+ServerName localhost
Listen %%LISTEN%%
ErrorLog "%%LOG_FILE%%"
</IfModule>
</IfModule>
+ServerName localhost
Listen %%LISTEN%%
ErrorLog "%%LOG_FILE%%"
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' );
use strict;
use warnings;
-use RT::Test tests => 187;
+use RT::Test tests => 181;
use Test::Warn;
use RT::Dashboard::Mailer;
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
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;
($baseurl, $m) = RT::Test->started_ok;
delete_dashboard($dashboard_id);
-delete_subscriptions();
RT::Test->clean_caught_mails;
($baseurl, $m) = RT::Test->started_ok;
delete_dashboard($dashboard_id);
-delete_subscriptions();
RT::Test->clean_caught_mails;
($baseurl, $m) = RT::Test->started_ok;
delete_dashboard($dashboard_id);
-delete_subscriptions();
RT::Test->clean_caught_mails;
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;
$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;
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;
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');
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');
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');
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());
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");
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 = {};
@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)/ },
'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)/ },
'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();
#!/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';
$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");
$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 );
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;
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...");
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";
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");
$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");
$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");
$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");
$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
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;
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";
}
}
+undef $m;
+done_testing;
};
+# 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' );
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(
$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
use strict;
use warnings;
-use RT::Test tests => 15;
+use RT::Test tests => 22;
my $ticket = RT::Test->create_ticket(
Subject => 'test bulk update',
$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
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',
);